[gvfs] Port to libsecret instead of libgnome-keyring



commit 86830605aeb46e63385e9000d9a78e1aa9c035e3
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Aug 20 18:53:59 2012 +0200

    Port to libsecret instead of libgnome-keyring
    
    Based on an initial port by Stef Walter
    
    https://bugzilla.gnome.org/show_bug.cgi?id=679854

 configure.ac                        |    4 +-
 daemon/gvfskeyring.c                |  227 ++++++++++++++++++++++++++++-------
 monitor/udisks2/gvfsudisks2volume.c |  100 +++++++++-------
 3 files changed, 238 insertions(+), 93 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7adc583..fa581f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -461,10 +461,10 @@ KEYRING_LIBS=
 KEYRING_CFLAGS=
 
 if test "x$enable_keyring" != "xno"; then
-  PKG_CHECK_EXISTS(gnome-keyring-1, msg_keyring=yes)
+  PKG_CHECK_EXISTS(libsecret-unstable, msg_keyring=yes)
 
   if test "x$msg_keyring" = "xyes"; then
-    PKG_CHECK_MODULES(KEYRING, gnome-keyring-1)
+    PKG_CHECK_MODULES(KEYRING, libsecret-unstable)
     AC_DEFINE(HAVE_KEYRING, 1, [Define to 1 if GNOME Keyring is available])
   fi
 fi
diff --git a/daemon/gvfskeyring.c b/daemon/gvfskeyring.c
index c720a57..3555ec1 100644
--- a/daemon/gvfskeyring.c
+++ b/daemon/gvfskeyring.c
@@ -22,8 +22,10 @@
 
 #include <config.h>
 
+#define SECRET_API_SUBJECT_TO_CHANGE 1
+
 #ifdef HAVE_KEYRING
-#include <gnome-keyring.h>
+#include <libsecret/secret.h>
 #endif
 
 #include "gvfskeyring.h"
@@ -32,12 +34,131 @@ gboolean
 g_vfs_keyring_is_available (void)
 {
 #ifdef HAVE_KEYRING
-  return gnome_keyring_is_available ();
+  return TRUE;
 #else
   return FALSE;
 #endif
 }
 
+#ifdef HAVE_KEYRING
+
+static void
+insert_string (const gchar *key,
+	       const gchar *value,
+	       GHashTable **attributes)
+{
+  if (*attributes == NULL)
+    return;
+
+  if (!g_utf8_validate (value, -1, NULL))
+    {
+      g_warning ("Non-utf8 value for key %s\n", key);
+      g_hash_table_unref (*attributes);
+      *attributes = NULL;
+    }
+
+  g_hash_table_insert (*attributes,
+		       g_strdup (key),
+		       g_strdup (value));
+}
+
+static void
+insert_int (const gchar *key,
+	    gint value,
+	    GHashTable **attributes)
+{
+  if (*attributes == NULL)
+    return;
+
+  g_hash_table_insert (*attributes,
+		       g_strdup (key),
+		       g_strdup_printf ("%d", value));
+}
+
+static GHashTable *
+build_network_attributes (const gchar *username,
+                          const gchar *host,
+                          const gchar *domain,
+                          const gchar *protocol,
+                          const gchar *object,
+                          const gchar *authtype,
+                          guint32 port)
+{
+  GHashTable *attributes;
+
+  attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  if (username)
+    insert_string ("user", username, &attributes);
+  if (host)
+    insert_string ("server", host, &attributes);
+  if (domain)
+    insert_string ("domain", domain, &attributes);
+  if (protocol)
+    insert_string ("protocol", protocol, &attributes);
+  if (object)
+    insert_string ("object", object, &attributes);
+  if (authtype)
+    insert_string ("authtype", authtype, &attributes);
+  if (port != 0)
+    insert_int ("port", (gint)port, &attributes);
+
+  return attributes;
+}
+
+static gchar *
+build_network_label (const gchar *user,
+                     const gchar *server,
+                     const gchar *object,
+                     guint32  port)
+{
+  GString *s;
+  gchar *name;
+
+  if (server != NULL)
+    {
+      s = g_string_new (NULL);
+      if (user != NULL)
+	g_string_append_uri_escaped (s, user, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, TRUE);
+        g_string_append (s, "@");
+      g_string_append (s, server);
+      if (port != 0)
+        g_string_append_printf (s, ":%d", port);
+      if (object != NULL)
+        g_string_append_printf (s, "/%s", object);
+      name = g_string_free (s, FALSE);
+    }
+  else
+    {
+      name = g_strdup ("network password");
+    }
+  return name;
+}
+
+#endif /* HAVE_KEYRING */
+
+gint
+compare_specificity (gconstpointer  a,
+		     gconstpointer  b)
+{
+  GHashTable  *attributes_a, *attributes_b;
+  SecretItem  *item_a, *item_b;
+  int res;
+
+  item_a = SECRET_ITEM (a);
+  attributes_a = secret_item_get_attributes (item_a);
+
+  item_b = SECRET_ITEM (b);
+  attributes_b = secret_item_get_attributes (item_b);
+
+  res = g_hash_table_size (attributes_a) - g_hash_table_size (attributes_b);
+
+  g_hash_table_unref (attributes_a);
+  g_hash_table_unref (attributes_b);
+
+  return res;
+}
+
 gboolean
 g_vfs_keyring_lookup_password (const gchar *username,
                                const gchar *host,
@@ -51,39 +172,58 @@ g_vfs_keyring_lookup_password (const gchar *username,
                                gchar      **password_out)
 {
 #ifdef HAVE_KEYRING
-  GnomeKeyringNetworkPasswordData *pwd_data;
-  GnomeKeyringResult               result;
-  GList                           *plist;
+  GHashTable  *attributes;
+  SecretItem  *item;
+  SecretValue *secret;
+  GList       *plist;
+  GError      *error = NULL;
+
+
+  attributes = build_network_attributes (username, host, domain, protocol, object, authtype, port);
+  plist = secret_service_search_sync (NULL, SECRET_SCHEMA_COMPAT_NETWORK, attributes,
+                                      SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS |
+				      SECRET_SEARCH_ALL,
+                                      NULL, &error);
+  g_hash_table_unref (attributes);
+
+  if (error != NULL)
+    {
+       g_error_free (error);
+       return FALSE;
+    }
 
-  if (!gnome_keyring_is_available ())
+  if (plist == NULL)
     return FALSE;
 
-  result = gnome_keyring_find_network_password_sync (
-    username,
-    domain,
-    host,
-    object,
-    protocol,
-    authtype,
-    port,
-    &plist);
+  /* We want the least specific result, so we sort the return values.
+     For instance, given both items for ftp://host:port and ftp://host
+     in the keyring we always want to use the ftp://host one for
+     i.e. ftp://host/some/path. */
+
+  plist = g_list_sort (plist, compare_specificity);
   
-  if (result != GNOME_KEYRING_RESULT_OK || plist == NULL)
-    return FALSE;
+  item = SECRET_ITEM (plist->data);
+  secret = secret_item_get_secret (item);
+  attributes = secret_item_get_attributes (item);
+  g_list_free_full (plist, g_object_unref);
 
-  /* We use the first result, which is the least specific match */
-  pwd_data = (GnomeKeyringNetworkPasswordData *)plist->data;
+  if (secret == NULL)
+    {
+      if (attributes)
+        g_hash_table_unref (attributes);
+      return FALSE;
+    }
 
-  *password_out = g_strdup (pwd_data->password);
+  *password_out = g_strdup (secret_value_get (secret, NULL));
+  secret_value_unref (secret);
 
   if (username_out)
-    *username_out = g_strdup (pwd_data->user);
-  
+    *username_out = g_strdup (g_hash_table_lookup (attributes, "user"));
+
   if (domain_out)
-    *domain_out = g_strdup (pwd_data->domain);
-      
-  gnome_keyring_network_password_list_free (plist);
-  
+    *domain_out = g_strdup (g_hash_table_lookup (attributes, "domain"));
+
+  g_hash_table_unref (attributes);
   return TRUE;
 #else
   return FALSE;
@@ -102,31 +242,26 @@ g_vfs_keyring_save_password (const gchar  *username,
                              GPasswordSave flags)
 {
 #ifdef HAVE_KEYRING
-  GnomeKeyringResult result;
   const gchar       *keyring;
-  guint32            item_id;
-  
-  if (!gnome_keyring_is_available ())
-    return FALSE;
+  GHashTable        *attributes;
+  gchar             *label;
+  gboolean           ret;
 
   if (flags == G_PASSWORD_SAVE_NEVER)
     return FALSE;
 
-  keyring = (flags == G_PASSWORD_SAVE_FOR_SESSION) ? "session" : NULL;
-
-  result = gnome_keyring_set_network_password_sync (
-    keyring,
-    username,
-    domain,
-    host,
-    object,
-    protocol,
-    authtype,
-    port,
-    password,
-    &item_id);
-
-  return (result == GNOME_KEYRING_RESULT_OK);
+  keyring = (flags == G_PASSWORD_SAVE_FOR_SESSION) ? SECRET_COLLECTION_SESSION : SECRET_COLLECTION_DEFAULT;
+
+  label = build_network_label (username, host, object, port);
+  attributes = build_network_attributes (username, host, domain, protocol, object, authtype, port);
+
+  ret = secret_password_storev_sync (SECRET_SCHEMA_COMPAT_NETWORK, attributes,
+                                     keyring, label, password, NULL, NULL);
+
+  g_free (label);
+  g_hash_table_unref (attributes);
+
+  return ret;
 #else
   return FALSE;
 #endif /* HAVE_KEYRING */
diff --git a/monitor/udisks2/gvfsudisks2volume.c b/monitor/udisks2/gvfsudisks2volume.c
index 29ba0a4..7652a4b 100644
--- a/monitor/udisks2/gvfsudisks2volume.c
+++ b/monitor/udisks2/gvfsudisks2volume.c
@@ -32,7 +32,7 @@
 #include <gio/gio.h>
 
 #ifdef HAVE_KEYRING
-#include <gnome-keyring.h>
+#include <libsecret/secret.h>
 #endif
 
 #include "gvfsudisks2drive.h"
@@ -779,12 +779,13 @@ gvfs_udisks2_volume_get_activation_root (GVolume *_volume)
 /* ---------------------------------------------------------------------------------------------------- */
 
 #ifdef HAVE_KEYRING
-static GnomeKeyringPasswordSchema luks_passphrase_schema =
+static SecretSchema luks_passphrase_schema =
 {
-  GNOME_KEYRING_ITEM_GENERIC_SECRET,
+  "org.gnome.GVfs.Luks.Password",
+  SECRET_SCHEMA_DONT_MATCH_NAME,
   {
-    {"gvfs-luks-uuid", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING},
-    {NULL, 0}
+    { "gvfs-luks-uuid", SECRET_SCHEMA_ATTRIBUTE_STRING },
+    { NULL, 0 },
   }
 };
 #endif
@@ -833,8 +834,13 @@ mount_data_free (MountData *data)
       g_object_unref (data->mount_operation);
     }
 
+#ifdef HAVE_KEYRING
+  secret_password_free (data->passphrase);
+  secret_password_free (data->passphrase_from_keyring);
+#else
   g_free (data->passphrase);
   g_free (data->passphrase_from_keyring);
+#endif
 
   g_free (data->uuid_of_encrypted_to_unlock);
   g_free (data->desc_of_encrypted_to_unlock);
@@ -981,11 +987,14 @@ do_mount (MountData *data)
 
 #ifdef HAVE_KEYRING
 static void
-luks_store_passphrase_cb (GnomeKeyringResult result,
-                          gpointer           user_data)
+luks_store_passphrase_cb (GObject      *source,
+                          GAsyncResult *result,
+                          gpointer      user_data)
 {
   MountData *data = user_data;
-  if (result == GNOME_KEYRING_RESULT_OK)
+  GError *error = NULL;
+
+  if (secret_password_store_finish (result, &error))
     {
       /* everything is good */
       do_mount (data);
@@ -996,9 +1005,10 @@ luks_store_passphrase_cb (GnomeKeyringResult result,
       g_simple_async_result_set_error (data->simple,
                                        G_IO_ERROR,
                                        G_IO_ERROR_FAILED,
-                                       _("Error storing passphrase in keyring (error code %d)"),
-                                       result);
+                                       _("Error storing passphrase in keyring (%s)"),
+                                       error->message);
       g_simple_async_result_complete (data->simple);
+      g_error_free (error);
       mount_data_free (data);
     }
 }
@@ -1010,11 +1020,14 @@ static void do_unlock (MountData *data);
 
 #ifdef HAVE_KEYRING
 static void
-luks_delete_passphrase_cb (GnomeKeyringResult result,
-                           gpointer           user_data)
+luks_delete_passphrase_cb (GObject      *source,
+                           GAsyncResult *result,
+                           gpointer      user_data)
 {
   MountData *data = user_data;
-  if (result == GNOME_KEYRING_RESULT_OK)
+  GError *error = NULL;
+
+  if (secret_password_clear_finish (result, &error))
     {
       /* with the bad passphrase out of the way, try again */
       g_free (data->passphrase);
@@ -1027,9 +1040,10 @@ luks_delete_passphrase_cb (GnomeKeyringResult result,
       g_simple_async_result_set_error (data->simple,
                                        G_IO_ERROR,
                                        G_IO_ERROR_FAILED,
-                                       _("Error deleting invalid passphrase from keyring (error code %d)"),
-                                       result);
+                                       _("Error deleting invalid passphrase from keyring (%s)"),
+                                       error->message);
       g_simple_async_result_complete (data->simple);
+      g_error_free (error);
       mount_data_free (data);
     }
 }
@@ -1061,12 +1075,10 @@ unlock_cb (GObject       *source_object,
           g_strcmp0 (data->passphrase, data->passphrase_from_keyring) == 0)
         {
           /* nuke the invalid passphrase from keyring... */
-          gnome_keyring_delete_password (&luks_passphrase_schema,
-                                         luks_delete_passphrase_cb,
-                                         data,
-                                         NULL, /* GDestroyNotify */
-                                         "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
-                                         NULL); /* sentinel */
+          secret_password_clear (&luks_passphrase_schema, data->cancellable,
+                                 luks_delete_passphrase_cb, data,
+                                 "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
+                                 NULL); /* sentinel */
           goto out;
         }
 #endif
@@ -1112,28 +1124,25 @@ unlock_cb (GObject       *source_object,
               g_assert_not_reached ();
               break;
             case G_PASSWORD_SAVE_FOR_SESSION:
-              keyring = GNOME_KEYRING_SESSION;
+              keyring = SECRET_COLLECTION_SESSION;
               break;
             case G_PASSWORD_SAVE_PERMANENTLY:
-              keyring = GNOME_KEYRING_DEFAULT;
+              keyring = SECRET_COLLECTION_DEFAULT;
               break;
             default:
-              keyring = GNOME_KEYRING_DEFAULT;
+              keyring = SECRET_COLLECTION_DEFAULT;
               break;
             }
 
           display_name = g_strdup_printf (_("Encryption passphrase for %s"),
                                           data->desc_of_encrypted_to_unlock);
 
-          gnome_keyring_store_password (&luks_passphrase_schema,
-                                        keyring,
-                                        display_name,
-                                        data->passphrase,
-                                        luks_store_passphrase_cb,
-                                        data,
-                                        NULL, /* GDestroyNotify */
-                                        "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
-                                        NULL); /* sentinel */
+          secret_password_store (&luks_passphrase_schema,
+                                 keyring, display_name, data->passphrase,
+                                 data->cancellable,
+                                 luks_store_passphrase_cb, data,
+                                 "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
+                                 NULL); /* sentinel */
           goto out;
         }
 #endif
@@ -1237,19 +1246,22 @@ has_crypttab_passphrase (MountData *data)
 
 #ifdef HAVE_KEYRING
 static void
-luks_find_passphrase_cb (GnomeKeyringResult result,
-                         const gchar       *string,
-                         gpointer           user_data)
+luks_find_passphrase_cb (GObject      *source,
+                         GAsyncResult *result,
+                         gpointer      user_data)
 {
   MountData *data = user_data;
+  gchar *password;
+
+  password = secret_password_lookup_finish (result, NULL);
 
   /* Don't fail if a keyring error occured - just continue and request
    * the passphrase from the user...
    */
-  if (result == GNOME_KEYRING_RESULT_OK)
+  if (password)
     {
-      data->passphrase = g_strdup (string);
-      data->passphrase_from_keyring = g_strdup (string);
+      data->passphrase = password;
+      data->passphrase_from_keyring = g_strdup (password);
     }
   /* try again */
   do_unlock (data);
@@ -1277,12 +1289,10 @@ do_unlock (MountData *data)
           if (!data->checked_keyring)
             {
               data->checked_keyring = TRUE;
-              gnome_keyring_find_password (&luks_passphrase_schema,
-                                           luks_find_passphrase_cb,
-                                           data,
-                                           NULL, /* GDestroyNotify */
-                                           "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
-                                           NULL); /* sentinel */
+              secret_password_lookup (&luks_passphrase_schema, data->cancellable,
+                                      luks_find_passphrase_cb, data,
+                                      "gvfs-luks-uuid", data->uuid_of_encrypted_to_unlock,
+                                      NULL); /* sentinel */
               goto out;
             }
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]