diff options
author | Alexander Larsson <alexl@redhat.com> | 2012-08-20 18:53:59 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2012-08-20 18:53:59 +0200 |
commit | 86830605aeb46e63385e9000d9a78e1aa9c035e3 (patch) | |
tree | 322e96bef0fe2d3570c257d40a9af1c63d6f75c5 | |
parent | e580cd115f61e98055c3619c24fc2d5b3eb64c68 (diff) | |
download | gvfs-86830605aeb46e63385e9000d9a78e1aa9c035e3.tar.gz |
Port to libsecret instead of libgnome-keyring
Based on an initial port by Stef Walter
https://bugzilla.gnome.org/show_bug.cgi?id=679854
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | daemon/gvfskeyring.c | 227 | ||||
-rw-r--r-- | monitor/udisks2/gvfsudisks2volume.c | 100 |
3 files changed, 238 insertions, 93 deletions
diff --git a/configure.ac b/configure.ac index 7adc583c..fa581f33 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 c720a573..3555ec14 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 29ba0a43..7652a4b8 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 |