Do PIN authentication

This adds checking whether PIN is required during SIM initialisation and
delaying the sim ready notifications until after correct PIN is given.
This commit is contained in:
Andrzej Zaborowski 2009-09-17 22:43:22 +02:00 committed by Denis Kenzior
parent b1c8b291f5
commit ee02b14836
6 changed files with 604 additions and 1 deletions

View File

@ -398,6 +398,242 @@ error:
CALLBACK_WITH_FAILURE(cb, NULL, data);
}
static struct {
enum ofono_passwd_type type;
const char *name;
} const at_sim_name[] = {
{ OFONO_PASSWD_SIM_PIN, "SIM PIN" },
{ OFONO_PASSWD_SIM_PUK, "SIM PUK" },
{ OFONO_PASSWD_PHSIM_PIN, "PH-SIM PIN" },
{ OFONO_PASSWD_PHFSIM_PIN, "PH-FSIM PIN" },
{ OFONO_PASSWD_PHFSIM_PUK, "PH-FSIM PUK" },
{ OFONO_PASSWD_SIM_PIN2, "SIM PIN2" },
{ OFONO_PASSWD_SIM_PUK2, "SIM PUK2" },
{ OFONO_PASSWD_PHNET_PIN, "PH-NET PIN" },
{ OFONO_PASSWD_PHNET_PUK, "PH-NET PUK" },
{ OFONO_PASSWD_PHNETSUB_PIN, "PH-NETSUB PIN" },
{ OFONO_PASSWD_PHNETSUB_PUK, "PH-NETSUB PUK" },
{ OFONO_PASSWD_PHSP_PIN, "PH-SP PIN" },
{ OFONO_PASSWD_PHSP_PUK, "PH-SP PUK" },
{ OFONO_PASSWD_PHCORP_PIN, "PH-CORP PIN" },
{ OFONO_PASSWD_PHCORP_PUK, "PH-CORP PUK" },
};
static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
GAtResultIter iter;
ofono_sim_passwd_cb_t cb = cbd->cb;
struct ofono_error error;
const char *pin_required;
int pin_type;
int i;
int len = sizeof(at_sim_name) / sizeof(*at_sim_name);
dump_response("at_cpin_cb", ok, result);
decode_at_error(&error, g_at_result_final_response(result));
if (!ok) {
cb(&error, -1, cbd->data);
return;
}
g_at_result_iter_init(&iter, result);
if (!g_at_result_iter_next(&iter, "+CPIN:")) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
g_at_result_iter_next_unquoted_string(&iter, &pin_required);
pin_type = -1;
if (!strcmp(pin_required, "READY"))
pin_type = OFONO_PASSWD_NONE;
else
for (i = 0; i < len; i++)
if (!strcmp(pin_required, at_sim_name[i].name)) {
pin_type = at_sim_name[i].type;
break;
}
if (pin_type == -1) {
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
return;
}
ofono_debug("crsm_pin_cb: %s", pin_required);
cb(&error, pin_type, cbd->data);
}
static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
void *data)
{
GAtChat *chat = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
if (!cbd)
goto error;
if (g_at_chat_send(chat, "AT+CPIN?", NULL,
at_cpin_cb, cbd, g_free) > 0)
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, -1, data);
}
static void at_lock_unlock_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
struct cb_data *cbd = user_data;
ofono_sim_lock_unlock_cb_t cb = cbd->cb;
struct ofono_error error;
dump_response("at_lock_unlock_cb", ok, result);
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
}
static void at_pin_send(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
GAtChat *chat = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
if (!cbd)
goto error;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
if (ret > 0)
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
GAtChat *chat = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
if (!cbd)
goto error;
snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
if (ret > 0)
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static const char *const at_clck_cpwd_fac[] = {
[OFONO_PASSWD_SIM_PIN] = "SC",
[OFONO_PASSWD_SIM_PIN2] = "P2",
[OFONO_PASSWD_PHSIM_PIN] = "PS",
[OFONO_PASSWD_PHFSIM_PIN] = "PF",
[OFONO_PASSWD_PHNET_PIN] = "PN",
[OFONO_PASSWD_PHNETSUB_PIN] = "PU",
[OFONO_PASSWD_PHSP_PIN] = "PP",
[OFONO_PASSWD_PHCORP_PIN] = "PC",
};
static void at_pin_enable(struct ofono_sim *sim, int passwd_type, int enable,
const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
GAtChat *chat = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
if (!cbd)
goto error;
if (passwd_type < 0 || passwd_type >= len ||
!at_clck_cpwd_fac[passwd_type])
goto error;
snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
if (ret > 0)
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static void at_change_passwd(struct ofono_sim *sim, int passwd_type,
const char *old, const char *new,
ofono_sim_lock_unlock_cb_t cb, void *data)
{
GAtChat *chat = ofono_sim_get_data(sim);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[64];
int ret;
int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
if (!cbd)
goto error;
if (passwd_type < 0 || passwd_type >= len ||
!at_clck_cpwd_fac[passwd_type])
goto error;
snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
at_clck_cpwd_fac[passwd_type], old, new);
ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free);
memset(buf, 0, sizeof(buf));
if (ret > 0)
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
}
static gboolean at_sim_register(gpointer user)
{
struct ofono_sim *sim = user;
@ -434,6 +670,11 @@ static struct ofono_sim_driver driver = {
.write_file_linear = at_sim_update_record,
.write_file_cyclic = at_sim_update_cyclic,
.read_imsi = at_read_imsi,
.query_passwd_state = at_pin_query,
.send_passwd = at_pin_send,
.reset_passwd = at_pin_send_puk,
.lock = at_pin_enable,
.change_passwd = at_change_passwd,
};
void at_sim_init()

View File

@ -64,6 +64,12 @@ typedef void (*ofono_sim_file_read_cb_t)(int ok,
typedef void (*ofono_sim_file_write_cb_t)(int ok, void *userdata);
typedef void (*ofono_sim_passwd_cb_t)(const struct ofono_error *error,
int passwd_type, void *data);
typedef void (*ofono_sim_lock_unlock_cb_t)(const struct ofono_error *error,
void *data);
struct ofono_sim_driver {
const char *name;
int (*probe)(struct ofono_sim *sim, unsigned int vendor, void *data);
@ -90,6 +96,19 @@ struct ofono_sim_driver {
ofono_sim_write_cb_t cb, void *data);
void (*read_imsi)(struct ofono_sim *sim,
ofono_sim_imsi_cb_t cb, void *data);
void (*query_passwd_state)(struct ofono_sim *sim,
ofono_sim_passwd_cb_t cb, void *data);
void (*send_passwd)(struct ofono_sim *sim, const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data);
void (*reset_passwd)(struct ofono_sim *sim, const char *puk,
const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data);
void (*change_passwd)(struct ofono_sim *sim, int passwd_type,
const char *old, const char *new,
ofono_sim_lock_unlock_cb_t cb, void *data);
void (*lock)(struct ofono_sim *sim, int passwd_type, int enable,
const char *passwd,
ofono_sim_lock_unlock_cb_t cb, void *data);
};
int ofono_sim_driver_register(const struct ofono_sim_driver *d);

View File

@ -91,6 +91,26 @@ struct ofono_call {
int clip_validity;
};
enum ofono_passwd_type {
OFONO_PASSWD_NONE = 0,
OFONO_PASSWD_SIM_PIN,
OFONO_PASSWD_SIM_PUK,
OFONO_PASSWD_PHSIM_PIN,
OFONO_PASSWD_PHFSIM_PIN,
OFONO_PASSWD_PHFSIM_PUK,
OFONO_PASSWD_SIM_PIN2,
OFONO_PASSWD_SIM_PUK2,
OFONO_PASSWD_PHNET_PIN,
OFONO_PASSWD_PHNET_PUK,
OFONO_PASSWD_PHNETSUB_PIN,
OFONO_PASSWD_PHNETSUB_PUK,
OFONO_PASSWD_PHSP_PIN,
OFONO_PASSWD_PHSP_PUK,
OFONO_PASSWD_PHCORP_PIN,
OFONO_PASSWD_PHCORP_PUK,
};
#ifdef __cplusplus
}
#endif

286
src/sim.c
View File

@ -55,6 +55,7 @@ static GSList *g_drivers = NULL;
static gboolean sim_op_next(gpointer user_data);
static gboolean sim_op_retrieve_next(gpointer user);
static void sim_own_numbers_update(struct ofono_sim *sim);
static void sim_pin_check(struct ofono_sim *sim);
struct sim_file_op {
int id;
@ -77,6 +78,7 @@ struct ofono_sim {
GSList *service_numbers;
gboolean sdn_ready;
gboolean ready;
int pin_type;
char **language_prefs;
GQueue *simop_q;
gint simop_source;
@ -89,6 +91,7 @@ struct ofono_sim {
const struct ofono_sim_driver *driver;
void *driver_data;
struct ofono_atom *atom;
DBusMessage *pending;
};
struct msisdn_set_request {
@ -98,6 +101,12 @@ struct msisdn_set_request {
DBusMessage *msg;
};
struct pin_enable_request {
struct ofono_sim *sim;
int type;
char *passwd;
};
struct service_number {
char *id;
struct ofono_phone_number ph;
@ -167,6 +176,7 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
DBusMessageIter dict;
char **own_numbers;
char **service_numbers;
const char *pin_name;
reply = dbus_message_new_method_return(msg);
if (!reply)
@ -206,6 +216,11 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
DBUS_TYPE_STRING,
&sim->language_prefs);
pin_name = sim_passwd_name(sim->pin_type);
ofono_dbus_dict_append(&dict, "PinRequired",
DBUS_TYPE_STRING,
(void *) &pin_name);
dbus_message_iter_close_container(&iter, &dict);
return reply;
@ -354,10 +369,234 @@ error:
return __ofono_error_invalid_args(msg);
}
static void sim_enable_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
reply = __ofono_error_failed(sim->pending);
else
reply = dbus_message_new_method_return(sim->pending);
__ofono_dbus_pending_reply(&sim->pending, reply);
}
static void sim_change_pin_cb(const struct ofono_error *error, void *data)
{
struct pin_enable_request *req = data;
struct ofono_sim *sim = req->sim;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
__ofono_dbus_pending_reply(&sim->pending,
__ofono_error_failed(sim->pending));
goto cleanup;
}
if (!sim->driver->lock) {
__ofono_dbus_pending_reply(&sim->pending,
dbus_message_new_method_return(sim->pending));
goto cleanup;
}
sim->driver->lock(sim, req->type, 1, req->passwd,
sim_enable_pin_cb, sim);
cleanup:
memset(req->passwd, 0, strlen(req->passwd));
g_free(req->passwd);
g_free(req);
}
static DBusMessage *sim_change_pin(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct ofono_sim *sim = data;
struct pin_enable_request *req;
DBusMessageIter iter;
enum ofono_passwd_type type;
const char *typestr;
const char *old;
const char *new;
if (sim->pending)
return __ofono_error_busy(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &typestr);
type = sim_string_to_passwd(typestr);
if (type == OFONO_PASSWD_NONE)
return __ofono_error_invalid_format(msg);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &old);
if (!is_valid_pin(old))
return __ofono_error_invalid_format(msg);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &new);
if (new[0] != '\0' && strcmp(new, old)) {
if (!sim->driver->change_passwd)
return __ofono_error_not_implemented(msg);
if (!is_valid_pin(new))
return __ofono_error_invalid_format(msg);
req = g_new0(struct pin_enable_request, 1);
req->sim = sim;
req->type = type;
req->passwd = g_strdup(new);
sim->pending = dbus_message_ref(msg);
sim->driver->change_passwd(sim, type, old, new,
sim_change_pin_cb, req);
} else {
if (!sim->driver->lock)
return __ofono_error_not_implemented(msg);
sim->pending = dbus_message_ref(msg);
sim->driver->lock(sim, type, new[0] != '\0',
old, sim_enable_pin_cb, sim);
}
return NULL;
}
static void sim_enter_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
DBusMessage *reply;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
reply = __ofono_error_failed(sim->pending);
else
reply = dbus_message_new_method_return(sim->pending);
__ofono_dbus_pending_reply(&sim->pending, reply);
sim_pin_check(sim);
}
static DBusMessage *sim_enter_pin(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct ofono_sim *sim = data;
DBusMessageIter iter;
const char *typestr;
int type;
const char *pin;
if (!sim->driver->send_passwd)
return __ofono_error_not_implemented(msg);
if (sim->pending)
return __ofono_error_busy(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &typestr);
type = sim_string_to_passwd(typestr);
if (type == OFONO_PASSWD_NONE || type != sim->pin_type)
return __ofono_error_invalid_format(msg);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &pin);
if (!is_valid_pin(pin))
return __ofono_error_invalid_format(msg);
sim->pending = dbus_message_ref(msg);
sim->driver->send_passwd(sim, pin, sim_enter_pin_cb, sim);
return NULL;
}
static DBusMessage *sim_reset_pin(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct ofono_sim *sim = data;
DBusMessageIter iter;
const char *typestr;
int type;
const char *puk;
const char *pin;
if (!sim->driver->reset_passwd)
return __ofono_error_not_implemented(msg);
if (sim->pending)
return __ofono_error_busy(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &typestr);
type = sim_string_to_passwd(typestr);
if (type == OFONO_PASSWD_NONE || type != sim->pin_type)
return __ofono_error_invalid_format(msg);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &puk);
if (!is_valid_pin(puk))
return __ofono_error_invalid_format(msg);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &pin);
if (!is_valid_pin(pin))
return __ofono_error_invalid_format(msg);
sim->pending = dbus_message_ref(msg);
sim->driver->reset_passwd(sim, puk, pin, sim_enter_pin_cb, sim);
return NULL;
}
static GDBusMethodTable sim_methods[] = {
{ "GetProperties", "", "a{sv}", sim_get_properties },
{ "SetProperty", "sv", "", sim_set_property,
G_DBUS_METHOD_FLAG_ASYNC },
{ "ChangePin", "sss", "", sim_change_pin,
G_DBUS_METHOD_FLAG_ASYNC },
{ "EnterPin", "ss", "", sim_enter_pin,
G_DBUS_METHOD_FLAG_ASYNC },
{ "ResetPin", "sss", "", sim_reset_pin,
G_DBUS_METHOD_FLAG_ASYNC },
{ }
};
@ -613,6 +852,51 @@ static void sim_retrieve_imsi(struct ofono_sim *sim)
sim->driver->read_imsi(sim, sim_imsi_cb, sim);
}
static void sim_pin_check_done(struct ofono_sim *sim)
{
sim_retrieve_imsi(sim);
}
static void sim_pin_query_cb(const struct ofono_error *error, int pin_type,
void *data)
{
struct ofono_sim *sim = data;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
const char *pin_name;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
ofono_error("Querying PIN authentication state failed");
goto checkdone;
}
if (sim->pin_type != pin_type) {
sim->pin_type = pin_type;
pin_name = sim_passwd_name(pin_type);
ofono_dbus_signal_property_changed(conn, path,
SIM_MANAGER_INTERFACE,
"PinRequired",
DBUS_TYPE_STRING,
&pin_name);
}
checkdone:
if (pin_type == OFONO_PASSWD_NONE)
sim_pin_check_done(sim);
}
static void sim_pin_check(struct ofono_sim *sim)
{
if (!sim->driver->query_passwd_state) {
sim_pin_check_done(sim);
return;
}
sim->driver->query_passwd_state(sim, sim_pin_query_cb, sim);
}
static void sim_efli_read_cb(int ok,
enum ofono_sim_file_structure structure,
int length, int record,
@ -1465,7 +1749,7 @@ void ofono_sim_register(struct ofono_sim *sim)
* in the EFust
*/
sim_retrieve_efli_and_efpl(sim);
sim_retrieve_imsi(sim);
sim_pin_check(sim);
}
void ofono_sim_remove(struct ofono_sim *sim)

View File

@ -488,3 +488,39 @@ void sim_adn_build(unsigned char *data, int length,
/* Ext1 unused */
*data++ = 0xff;
}
static const char *const passwd_name[] = {
[OFONO_PASSWD_NONE] = "none",
[OFONO_PASSWD_SIM_PIN] = "pin",
[OFONO_PASSWD_SIM_PUK] = "puk",
[OFONO_PASSWD_PHSIM_PIN] = "phone",
[OFONO_PASSWD_PHFSIM_PIN] = "firstphone",
[OFONO_PASSWD_PHFSIM_PUK] = "firstphonepuk",
[OFONO_PASSWD_SIM_PIN2] = "pin2",
[OFONO_PASSWD_SIM_PUK2] = "puk2",
[OFONO_PASSWD_PHNET_PIN] = "network",
[OFONO_PASSWD_PHNET_PUK] = "networkpuk",
[OFONO_PASSWD_PHNETSUB_PIN] = "netsub",
[OFONO_PASSWD_PHNETSUB_PUK] = "netsubpuk",
[OFONO_PASSWD_PHSP_PIN] = "service",
[OFONO_PASSWD_PHSP_PUK] = "servicepuk",
[OFONO_PASSWD_PHCORP_PIN] = "corp",
[OFONO_PASSWD_PHCORP_PUK] = "corppuk",
};
const char *sim_passwd_name(enum ofono_passwd_type type)
{
return passwd_name[type];
}
enum ofono_passwd_type sim_string_to_passwd(const char *name)
{
int len = sizeof(passwd_name) / sizeof(*passwd_name);
int i;
for (i = 0; i < len; i++)
if (!strcmp(passwd_name[i], name))
return i;
return OFONO_PASSWD_NONE;
}

View File

@ -93,3 +93,6 @@ gboolean sim_adn_parse(const unsigned char *data, int length,
void sim_adn_build(unsigned char *data, int length,
const struct ofono_phone_number *ph,
const char *identifier);
const char *sim_passwd_name(enum ofono_passwd_type type);
enum ofono_passwd_type sim_string_to_passwd(const char *name);