[libgnome-keyring] Try to return GNOME_KEYRING_ALREADY_EXISTS where possible.



commit 26d0f6492d2e413f6029cd8f3a11d94db333ab4d
Author: Stef Walter <stef memberwebs com>
Date:   Fri Mar 19 21:16:14 2010 +0000

    Try to return GNOME_KEYRING_ALREADY_EXISTS where possible.
    
    The secrets API has a significantly different model with creating of
    keyrings, where we never get an 'already exists' error. However this
    breaks certain strange uses of gnome_keyring_create ().
    
    So we simulate 'already exists' in a fairly good, but 'racy' manner.
    
    Fixes bug #611449

 library/gnome-keyring.c       |   86 ++++++++++++++++++++++++++++-------------
 library/tests/test-keyrings.c |    9 ++++
 2 files changed, 68 insertions(+), 27 deletions(-)
---
diff --git a/library/gnome-keyring.c b/library/gnome-keyring.c
index 0d07deb..95e1509 100644
--- a/library/gnome-keyring.c
+++ b/library/gnome-keyring.c
@@ -859,18 +859,18 @@ gnome_keyring_lock_all_sync (void)
 	return gkr_operation_block (op);
 }
 
-typedef struct _create_keyring_password_args {
+typedef struct _create_keyring_args {
 	gchar *keyring_name;
 	gchar *password;
-} create_keyring_password_args;
+} create_keyring_args;
 
 static void
-create_keyring_password_free (gpointer data)
+create_keyring_free (gpointer data)
 {
-	create_keyring_password_args *args = data;
+	create_keyring_args *args = data;
 	g_free (args->keyring_name);
 	egg_secure_strfree (args->password);
-	g_slice_free (create_keyring_password_args, args);
+	g_slice_free (create_keyring_args, args);
 }
 
 static void
@@ -892,7 +892,7 @@ create_keyring_encode_properties (DBusMessageIter *iter, const gchar *keyring_na
 static void
 create_keyring_password_reply (GkrOperation *op, GkrSession *session, gpointer user_data)
 {
-	create_keyring_password_args *args = user_data;
+	create_keyring_args *args = user_data;
 	DBusMessageIter iter;
 	DBusMessage *req;
 
@@ -939,6 +939,38 @@ create_keyring_reply (GkrOperation *op, DBusMessage *reply, gpointer user_data)
 		gkr_operation_prompt (op, prompt);
 }
 
+static void
+create_keyring_check_reply (GkrOperation *op, DBusMessage *reply, gpointer user_data)
+{
+	create_keyring_args *args = user_data;
+	DBusMessageIter iter;
+	DBusMessage *req;
+
+	/* If no such object, then no such keyring exists and we're good to go. */
+	if (!dbus_message_is_error (reply, ERROR_NO_SUCH_OBJECT)) {
+		/* Success means 'already exists' */
+		if (!gkr_operation_handle_errors (op, reply))
+			gkr_operation_complete (op, GNOME_KEYRING_RESULT_ALREADY_EXISTS);
+		return;
+	}
+
+	/* With a password requires a session, so get on that */
+	if (args->password) {
+		gkr_operation_push (op, create_keyring_password_reply, GKR_CALLBACK_OP_SESSION, args, NULL);
+		gkr_session_negotiate (op);
+
+	/* Otherwiswe just create the collection */
+	} else {
+		req = dbus_message_new_method_call (gkr_service_name (), SERVICE_PATH,
+		                                    SERVICE_INTERFACE, "CreateCollection");
+		dbus_message_iter_init_append (req, &iter);
+		create_keyring_encode_properties (&iter, args->keyring_name);
+		gkr_operation_push (op, create_keyring_reply, GKR_CALLBACK_OP_MSG, NULL, NULL);
+		gkr_operation_request (op, req);
+		dbus_message_unref (req);
+	}
+}
+
 /**
  * gnome_keyring_create:
  * @keyring_name: The new keyring name. Must not be %NULL.
@@ -962,34 +994,34 @@ gnome_keyring_create (const char                                  *keyring_name,
                       gpointer                                     data,
                       GDestroyNotify                               destroy_data)
 {
-	create_keyring_password_args *args;
-	DBusMessageIter iter;
+	create_keyring_args *args;
 	DBusMessage *req;
 	GkrOperation *op;
+	gchar *path;
 
 	g_return_val_if_fail (callback, NULL);
 
 	op = gkr_operation_new (callback, GKR_CALLBACK_RES, data, destroy_data);
 
-	/* With and without password are completely different */
+	args = g_slice_new0 (create_keyring_args);
+	args->keyring_name = g_strdup (keyring_name);
+	args->password = egg_secure_strdup (password);
 
-	if (password) {
-		args = g_slice_new0 (create_keyring_password_args);
-		args->keyring_name = g_strdup (keyring_name);
-		args->password = egg_secure_strdup (password);
-		gkr_operation_push (op, create_keyring_password_reply, GKR_CALLBACK_OP_SESSION,
-		                    args, create_keyring_password_free);
-		gkr_session_negotiate (op);
+	/*
+	 * The secrets API has a significantly different model with creating of
+	 * keyrings, where we never get an 'already exists' error. However this
+	 * breaks certain strange uses of gnome_keyring_create ().
+	 *
+	 * So we simulate 'already exists' in a fairly good, but 'racy' manner.
+	 */
 
-	} else {
-		req = dbus_message_new_method_call (gkr_service_name (), SERVICE_PATH,
-		                                    SERVICE_INTERFACE, "CreateCollection");
-		dbus_message_iter_init_append (req, &iter);
-		create_keyring_encode_properties (&iter, keyring_name);
-		gkr_operation_push (op, create_keyring_reply, GKR_CALLBACK_OP_MSG, NULL, NULL);
-		gkr_operation_request (op, req);
-		dbus_message_unref (req);
-	}
+	path = gkr_encode_keyring_name (keyring_name);
+	req = prepare_property_get (path, COLLECTION_INTERFACE, "Label");
+	gkr_operation_push (op, create_keyring_check_reply, GKR_CALLBACK_OP_MSG,
+	                    args, create_keyring_free);
+	gkr_operation_request (op, req);
+	dbus_message_unref (req);
+	g_free (path);
 
 	gkr_operation_unref (op);
 	return op;
diff --git a/library/tests/test-keyrings.c b/library/tests/test-keyrings.c
index aeba0ff..c5789f8 100644
--- a/library/tests/test-keyrings.c
+++ b/library/tests/test-keyrings.c
@@ -55,6 +55,15 @@ DEFINE_TEST(create_keyring)
 	g_assert_cmpint (GNOME_KEYRING_RESULT_OK, ==, res);
 }
 
+DEFINE_TEST(create_keyring_already_exists)
+{
+	GnomeKeyringResult res;
+
+	gnome_keyring_create_sync (KEYRING_NAME, PASSWORD);
+	res = gnome_keyring_create_sync (KEYRING_NAME, PASSWORD);
+	g_assert_cmpint (GNOME_KEYRING_RESULT_ALREADY_EXISTS, ==, res);
+}
+
 DEFINE_TEST(set_default_keyring)
 {
 	GnomeKeyringResult res;



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