[network-manager-applet] gsm: auto-unlock using PINs stored in the keyring (bgo #618532) (lp:555467)
- From: Dan Williams <dcbw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-applet] gsm: auto-unlock using PINs stored in the keyring (bgo #618532) (lp:555467)
- Date: Wed, 12 Oct 2011 23:40:39 +0000 (UTC)
commit 7d837085c467675529a4e2be90f406e1cfcd6277
Author: Anders Feder <anders feder dk>
Date: Wed Oct 12 18:29:42 2011 -0500
gsm: auto-unlock using PINs stored in the keyring (bgo #618532) (lp:555467)
Store successful PINs in the keyring and use the modem's
DeviceIdentifier and SimIdentifier to look those PINs up
when the modem is inserted and requires an unlock.
(dcbw: leaks, cleanups, and async keyring calls)
src/applet-device-gsm.c | 215 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 205 insertions(+), 10 deletions(-)
---
diff --git a/src/applet-device-gsm.c b/src/applet-device-gsm.c
index d2740ef..e492cdb 100644
--- a/src/applet-device-gsm.c
+++ b/src/applet-device-gsm.c
@@ -73,6 +73,8 @@ typedef struct {
gboolean quality_valid;
guint32 quality;
char *unlock_required;
+ char *devid;
+ char *simid;
gboolean modem_enabled;
MMModemGsmAccessTech act;
@@ -90,6 +92,7 @@ typedef struct {
/* Unlock dialog stuff */
GtkWidget *dialog;
+ gpointer keyring_id;
} GsmDeviceInfo;
static void unlock_dialog_destroy (GsmDeviceInfo *info);
@@ -761,6 +764,56 @@ gsm_get_secrets (SecretsRequest *req, GError **error)
/********************************************************************/
static void
+save_pin_cb (GnomeKeyringResult result, guint32 val, gpointer user_data)
+{
+ if (result != GNOME_KEYRING_RESULT_OK)
+ g_warning ("%s: result %d", (const char *) user_data, result);
+}
+
+static void
+set_pin_in_keyring (const char *devid,
+ const char *simid,
+ const char *pin)
+{
+ GnomeKeyringAttributeList *attributes;
+ GnomeKeyringAttribute attr;
+ const char *name;
+ char *error_msg;
+
+ name = g_strdup_printf (_("PIN code for SIM card '%s' on '%s'"),
+ simid ? simid : "unknown",
+ devid);
+
+ attributes = gnome_keyring_attribute_list_new ();
+ attr.name = g_strdup ("devid");
+ attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ attr.value.string = g_strdup (devid);
+ g_array_append_val (attributes, attr);
+
+ if (simid) {
+ attr.name = g_strdup ("simid");
+ attr.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ attr.value.string = g_strdup (simid);
+ g_array_append_val (attributes, attr);
+ }
+
+ error_msg = g_strdup_printf ("Saving PIN code in keyring for devid:%s simid:%s failed",
+ devid, simid ? simid : "(unknown)");
+
+ gnome_keyring_item_create (NULL,
+ GNOME_KEYRING_ITEM_GENERIC_SECRET,
+ name,
+ attributes,
+ pin,
+ TRUE,
+ save_pin_cb,
+ error_msg,
+ (GDestroyNotify) g_free);
+
+ gnome_keyring_attribute_list_free (attributes);
+}
+
+static void
unlock_dialog_destroy (GsmDeviceInfo *info)
{
applet_mobile_pin_dialog_destroy (info->dialog);
@@ -772,9 +825,11 @@ unlock_pin_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
GsmDeviceInfo *info = user_data;
GError *error = NULL;
- const char *dbus_error, *msg = NULL;
+ const char *dbus_error, *msg = NULL, *code1;
if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
+ code1 = applet_mobile_pin_dialog_get_entry1 (info->dialog);
+ set_pin_in_keyring (info->devid, info->simid, code1);
unlock_dialog_destroy (info);
return;
}
@@ -962,6 +1017,9 @@ gsm_device_info_free (gpointer data)
if (info->bus)
dbus_g_connection_unref (info->bus);
+ if (info->keyring_id)
+ gnome_keyring_cancel_request (info->keyring_id);
+
if (info->providers)
g_hash_table_destroy (info->providers);
@@ -971,6 +1029,8 @@ gsm_device_info_free (gpointer data)
if (info->dialog)
unlock_dialog_destroy (info);
+ g_free (info->devid);
+ g_free (info->simid);
g_free (info->op_code);
g_free (info->op_name);
memset (info, 0, sizeof (GsmDeviceInfo));
@@ -1193,7 +1253,86 @@ parse_unlock_required (GValue *value)
}
static void
-unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+keyring_unlock_pin_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ GError *error = NULL;
+
+ if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
+ g_warning ("Failed to auto-unlock devid:%s simid:%s : (%s) %s",
+ info->devid ? info->devid : "(unknown)",
+ info->simid ? info->simid : "(unknown)",
+ dbus_g_error_get_name (error),
+ error->message);
+ /* Ask the user */
+ unlock_dialog_new (info->device, info);
+ g_clear_error (&error);
+ }
+}
+
+static void
+keyring_pin_check_cb (GnomeKeyringResult result, GList *list, gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ GList *iter;
+ const char *pin = NULL;
+
+ info->keyring_id = NULL;
+
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ /* No saved PIN, just ask the user */
+ unlock_dialog_new (info->device, info);
+ return;
+ }
+
+ /* Look for a result with a matching "simid" attribute since that's
+ * better than just using a matching "devid". The PIN is really tied
+ * to the SIM, not the modem itself.
+ */
+ for (iter = list;
+ info->simid && (pin == NULL) && iter;
+ iter = g_list_next (iter)) {
+ GnomeKeyringFound *found = iter->data;
+ int i;
+
+ /* Look for a matching "simid" attribute */
+ for (i = 0; (pin == NULL) && i < found->attributes->len; i++) {
+ GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index (found->attributes, i);
+
+ if ( g_strcmp0 (attr.name, "simid") == 0
+ && attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING
+ && g_strcmp0 (attr.value.string, info->simid) == 0) {
+ pin = found->secret;
+ break;
+ }
+ }
+ }
+
+ if (pin == NULL) {
+ /* Fall back to the first result's PIN */
+ pin = ((GnomeKeyringFound *) list->data)->secret;
+ if (pin == NULL) {
+ /* Should never get here */
+ g_warn_if_fail (pin != NULL);
+ unlock_dialog_new (info->device, info);
+ return;
+ }
+ }
+
+ /* Send the PIN code to ModemManager */
+ if (!dbus_g_proxy_begin_call_with_timeout (info->card_proxy, "SendPin",
+ keyring_unlock_pin_reply, info, NULL,
+ 15000, /* 15 seconds */
+ G_TYPE_STRING, pin,
+ G_TYPE_INVALID)) {
+ g_warning ("Failed to auto-unlock devid:%s simid:%s",
+ info->devid ? info->devid : "(unknown)",
+ info->simid ? info->simid : "(unknown)");
+ }
+}
+
+static void
+simid_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
GsmDeviceInfo *info = user_data;
GError *error = NULL;
@@ -1203,15 +1342,72 @@ unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
G_TYPE_VALUE, &value,
G_TYPE_INVALID)) {
if (G_VALUE_HOLDS_STRING (&value)) {
- g_free (info->unlock_required);
- info->unlock_required = parse_unlock_required (&value);
-
- /* Show the unlock dialog if an unlock is now required */
- if (info->unlock_required)
- unlock_dialog_new (info->device, info);
+ g_free (info->simid);
+ info->simid = g_value_dup_string (&value);
}
g_value_unset (&value);
}
+ g_clear_error (&error);
+
+ /* Procure unlock code and apply it if an unlock is now required. */
+ if (info->unlock_required) {
+ /* If we have a device ID ask the keyring for any saved SIM-PIN codes */
+ if (info->devid && (g_strcmp0 (info->unlock_required, "sim-pin") == 0)) {
+ g_warn_if_fail (info->keyring_id == NULL);
+ info->keyring_id = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+ keyring_pin_check_cb,
+ info,
+ NULL,
+ "devid",
+ GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
+ info->devid,
+ NULL);
+ } else {
+ /* Couldn't get a device ID, but unlock required; present dialog */
+ unlock_dialog_new (info->device, info);
+ }
+ }
+
+ check_start_polling (info);
+}
+
+#define MM_DBUS_INTERFACE_MODEM_GSM_CARD "org.freedesktop.ModemManager.Modem.Gsm.Card"
+
+static void
+unlock_reply (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
+{
+ GsmDeviceInfo *info = user_data;
+ GError *error = NULL;
+ GHashTable *props = NULL;
+
+ if (dbus_g_proxy_end_call (proxy, call, &error,
+ DBUS_TYPE_G_MAP_OF_VARIANT, &props,
+ G_TYPE_INVALID)) {
+ GHashTableIter iter;
+ const char *prop_name;
+ GValue *value;
+
+ g_hash_table_iter_init (&iter, props);
+ while (g_hash_table_iter_next (&iter, (gpointer) &prop_name, (gpointer) &value)) {
+ if ((strcmp (prop_name, "UnlockRequired") == 0) && G_VALUE_HOLDS_STRING (value)) {
+ g_free (info->unlock_required);
+ info->unlock_required = parse_unlock_required (value);
+ }
+
+ if ((strcmp (prop_name, "DeviceIdentifier") == 0) && G_VALUE_HOLDS_STRING (value)) {
+ g_free (info->devid);
+ info->devid = g_value_dup_string (value);
+ }
+ }
+ g_hash_table_destroy (props);
+
+ /* Get SIM card identifier */
+ dbus_g_proxy_begin_call (info->props_proxy, "Get",
+ simid_reply, info, NULL,
+ G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM_GSM_CARD,
+ G_TYPE_STRING, "SimIdentifier",
+ G_TYPE_INVALID);
+ }
g_clear_error (&error);
check_start_polling (info);
@@ -1465,10 +1661,9 @@ gsm_device_added (NMDevice *device, NMApplet *applet)
info, NULL);
/* Ask whether the device needs to be unlocked */
- dbus_g_proxy_begin_call (info->props_proxy, "Get",
+ dbus_g_proxy_begin_call (info->props_proxy, "GetAll",
unlock_reply, info, NULL,
G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
- G_TYPE_STRING, "UnlockRequired",
G_TYPE_INVALID);
/* Ask whether the device is enabled */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]