[gnome-keyring/dbus-api] [dbus] Refactor object to dbus path mapping.



commit 52aac7a5a95ad19a24149f6b1f54c12d5f0f90a8
Author: Stef Walter <stef memberwebs com>
Date:   Wed Nov 11 03:49:14 2009 +0000

    [dbus] Refactor object to dbus path mapping.
    
    Put pkcs11 object to dbus path mapping of secret
    collections and items into its own file.

 daemon/dbus/Makefile.am          |    3 +-
 daemon/dbus/gkd-secret-objects.c |  402 +++++++------------------------------
 daemon/dbus/gkd-secret-objects.h |    8 +-
 daemon/dbus/gkd-secret-prompt.c  |   14 +-
 daemon/dbus/gkd-secret-prompt.h  |    2 +
 daemon/dbus/gkd-secret-types.h   |    1 +
 daemon/dbus/gkd-secret-util.c    |  411 ++++++++++++++++++++++++++++++++++++++
 daemon/dbus/gkd-secret-util.h    |   45 ++++
 8 files changed, 542 insertions(+), 344 deletions(-)
---
diff --git a/daemon/dbus/Makefile.am b/daemon/dbus/Makefile.am
index 5aa9758..8353bc9 100644
--- a/daemon/dbus/Makefile.am
+++ b/daemon/dbus/Makefile.am
@@ -23,7 +23,8 @@ libgkr_dbus_la_SOURCES = \
 	gkd-secret-service.c gkd-secret-service.h \
 	gkd-secret-session.c gkd-secret-session.h \
 	gkd-secret-types.h \
-	gkd-secret-unlock.c gkd-secret-unlock.h
+	gkd-secret-unlock.c gkd-secret-unlock.h \
+	gkd-secret-util.c gkd-secret-util.h
 
 libgkr_dbus_la_LIBADD = \
 	$(GLIB_LIBS) \
diff --git a/daemon/dbus/gkd-secret-objects.c b/daemon/dbus/gkd-secret-objects.c
index af61e46..b3a3fe1 100644
--- a/daemon/dbus/gkd-secret-objects.c
+++ b/daemon/dbus/gkd-secret-objects.c
@@ -26,6 +26,7 @@
 #include "gkd-secret-service.h"
 #include "gkd-secret-objects.h"
 #include "gkd-secret-types.h"
+#include "gkd-secret-util.h"
 
 #include "pkcs11/pkcs11i.h"
 
@@ -77,104 +78,6 @@ typedef enum _DataType {
  * INTERNAL
  */
 
-static void
-encode_object_identifier (GString *result, const gchar* name, gssize length)
-{
-	g_assert (result);
-	g_assert (name);
-
-	if (length < 0)
-		length = strlen (name);
-
-	while (length > 0) {
-		char ch = *(name++);
-		--length;
-
-		/* Normal characters can go right through */
-		if (G_LIKELY ((ch >= 'A' && ch <= 'Z') ||
-		              (ch >= 'a' && ch <= 'z') ||
-		              (ch >= '0' && ch <= '9'))) {
-			g_string_append_c_inline (result, ch);
-
-		/* Special characters are encoded with a _ */
-		} else {
-			g_string_append_printf (result, "_%02x", (unsigned int)ch);
-		}
-	}
-}
-
-static gchar*
-decode_object_identifier (const gchar* enc, gssize length)
-{
-	GString *result;
-
-	g_assert (enc);
-
-	if (length < 0)
-		length = strlen (enc);
-
-	result = g_string_sized_new (length);
-	while (length > 0) {
-		char ch = *(enc++);
-		--length;
-
-		/* Underscores get special handling */
-		if (G_UNLIKELY (ch == '_' &&
-		                g_ascii_isxdigit(enc[0]) &&
-		                g_ascii_isxdigit (enc[1]))) {
-			ch = (g_ascii_xdigit_value (enc[0]) * 16) +
-			     (g_ascii_xdigit_value (enc[1]));
-			enc += 2;
-			length -= 2;
-		}
-
-		g_string_append_c_inline (result, ch);
-	}
-
-	return g_string_free (result, FALSE);
-}
-
-static gboolean
-parse_collection_and_item_from_path (const gchar *path, gchar **collection, gchar **item)
-{
-	const gchar *pos;
-
-	g_return_val_if_fail (path, FALSE);
-	g_assert (collection);
-	g_assert (item);
-
-	/* Make sure it starts with our prefix */
-	if (!g_str_has_prefix (path, SECRET_COLLECTION_PREFIX))
-		return FALSE;
-	path += strlen (SECRET_COLLECTION_PREFIX);
-
-	/* Skip the path separator */
-	if (path[0] != '/')
-		return FALSE;
-	++path;
-
-	/* Make sure we have something */
-	if (path[0] == '\0')
-		return FALSE;
-
-	pos = strchr (path, '/');
-
-	/* No item, just a collection */
-	if (pos == NULL) {
-		*collection = decode_object_identifier (path, -1);
-		*item = NULL;
-		return TRUE;
-	}
-
-	/* Make sure we have an item, and no further path bits */
-	if (pos[1] == '\0' || strchr (pos + 1, '/'))
-		return FALSE;
-
-	*collection = decode_object_identifier (path, pos - path);
-	*item = decode_object_identifier (pos + 1, -1);
-	return TRUE;
-}
-
 static gboolean
 property_to_attribute (const gchar *prop_name, CK_ATTRIBUTE_TYPE *attr_type, DataType *data_type)
 {
@@ -579,45 +482,17 @@ static void
 iter_append_item_paths (DBusMessageIter *iter, GList *items)
 {
 	DBusMessageIter array;
-	GP11Attributes *attrs;
-	GError *error = NULL;
-	GP11Attribute *coll;
-	GP11Attribute *id;
-	GString *path;
+	gchar *path;
 	GList *l;
 
 	dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "o", &array);
 
 	for (l = items; l; l = g_list_next (l)) {
-
-		/* Dig out the raw item identifier */
-		attrs = gp11_object_get (l->data, &error, CKA_ID, CKA_G_COLLECTION, GP11_INVALID);
-		if (error != NULL) {
-			g_warning ("couldn't retrieve item collection or id: %s", error->message);
-			g_clear_error (&error);
-			continue;
-		}
-
-		coll = gp11_attributes_find (attrs, CKA_G_COLLECTION);
-		id = gp11_attributes_find (attrs, CKA_ID);
-
-		if (!coll || gp11_attribute_is_invalid (coll) ||
-		    !id || gp11_attribute_is_invalid (id)) {
-			g_warning ("item has invalid collection or id");
-
-		} else {
-			path = g_string_new (SECRET_COLLECTION_PREFIX);
-			g_string_append_c (path, '/');
-			encode_object_identifier (path, (gchar*)coll->value, coll->length);
-			g_string_append_c (path, '/');
-			encode_object_identifier (path, (gchar*)id->value, id->length);
-
-			dbus_message_iter_append_basic (&array, DBUS_TYPE_OBJECT_PATH, &(path->str));
-
-			g_string_free (path, TRUE);
+		path = gkd_secret_util_path_for_item (l->data);
+		if (path != NULL) {
+			dbus_message_iter_append_basic (&array, DBUS_TYPE_OBJECT_PATH, &path);
+			g_free (path);
 		}
-
-		gp11_attributes_unref (attrs);
 	}
 
 	dbus_message_iter_close_container (iter, &array);
@@ -626,33 +501,18 @@ iter_append_item_paths (DBusMessageIter *iter, GList *items)
 static void
 iter_append_collection_paths (DBusMessageIter *iter, GList *collections)
 {
-	GString *path;
 	DBusMessageIter array;
-	GError *error = NULL;
-	gpointer data;
-	gsize n_data;
+	gchar *path;
 	GList *l;
 
 	dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "o", &array);
 
 	for (l = collections; l; l = g_list_next (l)) {
-
-		/* Dig out the raw item identifier */
-		data = gp11_object_get_data (l->data, CKA_ID, &n_data, &error);
-		if (error != NULL) {
-			g_warning ("couldn't retrieve collection id: %s", error->message);
-			g_clear_error (&error);
-
-		} else if (n_data) {
-			path = g_string_new (SECRET_COLLECTION_PREFIX);
-			g_string_append_c (path, '/');
-			encode_object_identifier (path, (gchar*)data, n_data);
-			dbus_message_iter_append_basic (&array, DBUS_TYPE_OBJECT_PATH, &(path->str));
-			g_string_free (path, TRUE);
+		path = gkd_secret_util_path_for_collection (l->data);
+		if (path != NULL) {
+			dbus_message_iter_append_basic (&array, DBUS_TYPE_OBJECT_PATH, &path);
+			g_free (path);
 		}
-
-		g_free (data);
-
 	}
 
 	dbus_message_iter_close_container (iter, &array);
@@ -741,42 +601,6 @@ object_property_set (GP11Object *object, DBusMessage *message,
 	return dbus_message_new_method_return (message);
 }
 
-static GP11Object*
-item_for_identifier (GP11Session *session, const gchar *coll_id, const gchar *item_id)
-{
-	GP11Object *object = NULL;
-	GError *error = NULL;
-	GList *objects;
-
-	g_assert (coll_id);
-	g_assert (item_id);
-
-	/*
-	 * TODO: I think this could benefit from some sort of
-	 * caching?
-	 */
-
-	objects = gp11_session_find_objects (session, &error,
-	                                     CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
-	                                     CKA_G_COLLECTION, strlen (coll_id), coll_id,
-	                                     CKA_ID, strlen (item_id), item_id,
-	                                     GP11_INVALID);
-
-	if (error != NULL) {
-		g_warning ("couldn't lookup '%s/%s' item: %s", coll_id, item_id, error->message);
-		g_clear_error (&error);
-		return NULL;
-	}
-
-	if (objects) {
-		object = g_object_ref (objects->data);
-		gp11_object_set_session (object, session);
-	}
-
-	gp11_list_unref_free (objects);
-	return object;
-}
-
 static DBusMessage*
 item_property_get (GP11Object *object, DBusMessage *message)
 {
@@ -912,48 +736,6 @@ item_message_handler (GkdSecretObjects *self, GP11Object *object, DBusMessage *m
 	return NULL;
 }
 
-static const gchar*
-collection_get_identifier (GP11Object *coll)
-{
-	return g_object_get_data (G_OBJECT (coll), "coll-identifier");
-}
-
-static GP11Object*
-collection_for_identifier (GP11Session *session, const gchar *coll_id)
-{
-	GP11Object *object = NULL;
-	GError *error = NULL;
-	GList *objects;
-
-	g_assert (coll_id);
-
-	/*
-	 * TODO: I think this could benefit from some sort of
-	 * caching?
-	 */
-
-	objects = gp11_session_find_objects (session, &error,
-	                                     CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
-	                                     CKA_ID, strlen (coll_id), coll_id,
-	                                     GP11_INVALID);
-
-	if (error != NULL) {
-		g_warning ("couldn't lookup '%s' collection: %s", coll_id, error->message);
-		g_clear_error (&error);
-		return NULL;
-	}
-
-	if (objects) {
-		object = objects->data;
-		gp11_object_set_session (object, session);
-		g_object_set_data_full (G_OBJECT (object), "coll-identifier", g_strdup (coll_id), g_free);
-		g_object_ref (object);
-	}
-
-	gp11_list_unref_free (objects);
-	return object;
-}
-
 static DBusMessage*
 collection_property_get (GkdSecretObjects *self, GP11Object *object, DBusMessage *message)
 {
@@ -975,8 +757,7 @@ collection_property_get (GkdSecretObjects *self, GP11Object *object, DBusMessage
 	if (g_str_equal (name, "Items")) {
 		reply = dbus_message_new_method_return (message);
 		dbus_message_iter_init_append (reply, &iter);
-		gkd_secret_objects_append_item_paths (self, &iter, message,
-		                                       collection_get_identifier (object));
+		gkd_secret_objects_append_item_paths (self, &iter, message, object);
 		return reply;
 	}
 
@@ -1051,8 +832,7 @@ collection_property_getall (GkdSecretObjects *self, GP11Object *object, DBusMess
 	dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
 	name = "Items";
 	dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
-	gkd_secret_objects_append_item_paths (self, &dict, message,
-	                                       collection_get_identifier (object));
+	gkd_secret_objects_append_item_paths (self, &dict, message, object);
 	dbus_message_iter_close_container (&array, &dict);
 
 	dbus_message_iter_close_container (&iter, &array);
@@ -1062,12 +842,7 @@ collection_property_getall (GkdSecretObjects *self, GP11Object *object, DBusMess
 static DBusMessage*
 collection_method_search_items (GkdSecretObjects *self, GP11Object *object, DBusMessage *message)
 {
-	const gchar *coll_id;
-
-	coll_id = collection_get_identifier (object);
-	g_return_val_if_fail (coll_id, NULL);
-
-	return gkd_secret_objects_handle_search_items (self, message, coll_id);
+	return gkd_secret_objects_handle_search_items (self, message, object);
 }
 
 static GP11Object*
@@ -1075,14 +850,14 @@ collection_find_matching_item (GkdSecretObjects *self, GP11Object *coll, GP11Att
 {
 	GP11Attributes *attrs;
 	const gchar *identifier;
-	GP11Object *result;
+	GP11Object *result = NULL;
 	GError *error = NULL;
 	GP11Session *session;
 	GP11Object *search;
 	gpointer data;
 	gsize n_data;
 
-	identifier = collection_get_identifier (coll);
+	identifier = gkd_secret_util_identifier_for_collection (coll);
 	g_return_val_if_fail (identifier, NULL);
 
 	/* Find items matching the collection and fields */
@@ -1109,15 +884,16 @@ collection_find_matching_item (GkdSecretObjects *self, GP11Object *coll, GP11Att
 	/* Get the matched item handles, and delete the search object */
 	gp11_object_set_session (search, session);
 	data = gp11_object_get_data (search, CKA_G_MATCHED, &n_data, NULL);
-	g_return_val_if_fail (data && n_data >= sizeof (CK_OBJECT_HANDLE), NULL);
 	gp11_object_destroy (search, NULL);
 	g_object_unref (search);
 
-	result = gp11_object_from_handle (gp11_session_get_slot (session),
-	                                  *((CK_OBJECT_HANDLE_PTR)data));
-	gp11_object_set_session (result, session);
-	g_free (data);
+	if (n_data >= sizeof (CK_OBJECT_HANDLE)) {
+		result = gp11_object_from_handle (gp11_session_get_slot (session),
+		                                  *((CK_OBJECT_HANDLE_PTR)data));
+		gp11_object_set_session (result, session);
+	}
 
+	g_free (data);
 	return result;
 }
 
@@ -1133,9 +909,8 @@ collection_method_create_item (GkdSecretObjects *self, GP11Object *object, DBusM
 	GError *error = NULL;
 	GP11Session *session;
 	DBusMessage *reply;
-	GString *path = NULL;
-	gpointer data;
-	gsize n_data;
+	gchar *path = NULL;
+	gchar *identifier;
 
 	/* Parse the message */
 	if (!dbus_message_has_signature (message, "a{sv}b"))
@@ -1168,28 +943,22 @@ collection_method_create_item (GkdSecretObjects *self, GP11Object *object, DBusM
 	} else {
 		session = gp11_object_get_session (object);
 		g_return_val_if_fail (session, NULL);
+		identifier = gkd_secret_util_identifier_for_collection (object);
+		g_return_val_if_fail (identifier, NULL);
 		gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY);
-		gp11_attributes_add_string (attrs, CKA_G_COLLECTION, collection_get_identifier (object));
+		gp11_attributes_add_string (attrs, CKA_G_COLLECTION, identifier);
 		item = gp11_session_create_object_full (session, attrs, NULL, &error);
+		g_free (identifier);
 	}
 
 	/* Build up the item identifier */
-	if (error == NULL) {
-		data = gp11_object_get_data (item, CKA_ID, &n_data, &error);
-		if (data != NULL) {
-			path = g_string_new (SECRET_COLLECTION_PREFIX);
-			g_string_append_c (path, '/');
-			g_string_append (path, collection_get_identifier (object));
-			g_string_append_c (path, '/');
-			encode_object_identifier (path, data, n_data);
-			g_free (data);
-		}
-	}
+	if (error == NULL)
+		path = gkd_secret_util_path_for_item (item);
 
-	if (error == NULL) {
+	if (path != NULL) {
 		prompt = "/";
 		reply = dbus_message_new_method_return (message);
-		dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &(path->str),
+		dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path,
 		                          DBUS_TYPE_OBJECT_PATH, &prompt,
 		                          DBUS_TYPE_INVALID);
 
@@ -1205,8 +974,7 @@ collection_method_create_item (GkdSecretObjects *self, GP11Object *object, DBusM
 
 	if (item)
 		g_object_unref (item);
-	if (path)
-		g_string_free (path, TRUE);
+	g_free (path);
 	return reply;
 }
 
@@ -1400,8 +1168,8 @@ gkd_secret_objects_dispatch (GkdSecretObjects *self, DBusMessage *message)
 	DBusMessage *reply = NULL;
 	GP11Object *object;
 	GP11Session *session;
-	gchar *coll_id;
-	gchar *item_id;
+	gboolean is_item;
+	const char *path;
 
 	g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
 	g_return_val_if_fail (message, NULL);
@@ -1411,30 +1179,19 @@ gkd_secret_objects_dispatch (GkdSecretObjects *self, DBusMessage *message)
 	if (session == NULL)
 		return NULL;
 
-	/* Figure out which collection or item we're talking about */
-	if (!parse_collection_and_item_from_path (dbus_message_get_path (message), &coll_id, &item_id))
-		return NULL;
+	path = dbus_message_get_path (message);
+	g_return_val_if_fail (path, NULL);
 
-	/* It's an item */
-	if (item_id) {
-		object = item_for_identifier (session, coll_id, item_id);
-		if (object != NULL) {
-			reply = item_message_handler (self, object, message);
-			g_object_unref (object);
-		}
-
-	/* It's a collection */
-	} else {
-		object = collection_for_identifier (session, coll_id);
-		if (object != NULL) {
-			reply = collection_message_handler (self, object, message);
-			g_object_unref (object);
-		}
-	}
+	object = gkd_secret_util_path_to_object (session, path, &is_item);
+	if (!object)
+		return NULL;
 
-	g_free (coll_id);
-	g_free (item_id);
+	if (is_item)
+		reply = item_message_handler (self, object, message);
+	else
+		reply = collection_message_handler (self, object, message);
 
+	g_object_unref (object);
 	return reply;
 }
 
@@ -1480,36 +1237,41 @@ gkd_secret_objects_parse_item_props (GkdSecretObjects *self, DBusMessageIter *it
 
 void
 gkd_secret_objects_append_item_paths (GkdSecretObjects *self, DBusMessageIter *iter,
-                                      DBusMessage *message, const gchar *coll_id)
+                                      DBusMessage *message, GP11Object *collection)
 {
 	DBusMessageIter variant;
 	GP11Session *session;
 	GError *error = NULL;
+	gchar *identifier;
 	GList *items;
 
 	g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
-	g_return_if_fail (coll_id);
+	g_return_if_fail (GP11_IS_OBJECT (collection));
 	g_return_if_fail (iter && message);
 
 	/* The session we're using to access the object */
 	session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
 	g_return_if_fail (session);
 
+	identifier = gkd_secret_util_identifier_for_collection (collection);
+	g_return_if_fail (identifier);
+
 	items = gp11_session_find_objects (session, &error,
 	                                   CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
-	                                   CKA_G_COLLECTION, strlen (coll_id), coll_id,
+	                                   CKA_G_COLLECTION, strlen (identifier), identifier,
 	                                   GP11_INVALID);
 
-	if (error != NULL) {
-		g_warning ("couldn't lookup items in '%s' collection: %s", coll_id, error->message);
+	if (error == NULL) {
+		dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
+		iter_append_item_paths (&variant, items);
+		dbus_message_iter_close_container (iter, &variant);
+	} else {
+		g_warning ("couldn't lookup items in '%s' collection: %s", identifier, error->message);
 		g_clear_error (&error);
-		return;
 	}
 
-	dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
-	iter_append_item_paths (&variant, items);
-	dbus_message_iter_close_container (iter, &variant);
 	gp11_list_unref_free (items);
+	g_free (identifier);
 }
 
 void
@@ -1546,7 +1308,7 @@ gkd_secret_objects_append_collection_paths (GkdSecretObjects *self, DBusMessageI
 
 DBusMessage*
 gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *message,
-                                        const gchar *coll_id)
+                                        GP11Object *collection)
 {
 	GP11Attributes *attrs;
 	GP11Attribute *attr;
@@ -1555,10 +1317,14 @@ gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *mes
 	GP11Session *session;
 	DBusMessage *reply;
 	GError *error = NULL;
+	gchar *identifier;
 	gpointer data;
 	gsize n_data;
 	GList *items;
 
+	g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
+	g_return_val_if_fail (message, NULL);
+
 	if (!dbus_message_has_signature (message, "a{ss}"))
 		return NULL;
 
@@ -1572,8 +1338,13 @@ gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *mes
 		                               "Invalid data in attributes argument");
 	}
 
-	if (coll_id)
-		gp11_attributes_add_string (attrs, CKA_G_COLLECTION, coll_id);
+	if (collection != NULL) {
+		identifier = gkd_secret_util_identifier_for_collection (collection);
+		g_return_val_if_fail (identifier, NULL);
+		gp11_attributes_add_string (attrs, CKA_G_COLLECTION, identifier);
+		g_free (identifier);
+	}
+
 	gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_G_SEARCH);
 	gp11_attributes_add_boolean (attrs, CKA_TOKEN, FALSE);
 
@@ -1620,34 +1391,3 @@ gkd_secret_objects_handle_search_items (GkdSecretObjects *self, DBusMessage *mes
 
 	return reply;
 }
-
-GP11Object*
-gkd_secret_objects_lookup_collection (GkdSecretObjects *self, const gchar *caller,
-                                      const gchar *objpath)
-{
-	GP11Session *session;
-	GP11Object *coll;
-	gchar *coll_id;
-	gchar *item_id;
-
-	g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
-	g_return_val_if_fail (objpath, NULL);
-	g_return_val_if_fail (caller, NULL);
-
-	/* The session we're using to access the object */
-	session = gkd_secret_service_get_pkcs11_session (self->service, caller);
-	g_return_val_if_fail (session, NULL);
-
-	/* Figure out which collection or item we're talking about */
-	if (!parse_collection_and_item_from_path (objpath, &coll_id, &item_id))
-		return NULL;
-
-	g_return_val_if_fail (coll_id, NULL);
-	coll = collection_for_identifier (session, coll_id);
-
-	g_free (coll_id);
-	g_free (item_id);
-
-	return coll;
-
-}
diff --git a/daemon/dbus/gkd-secret-objects.h b/daemon/dbus/gkd-secret-objects.h
index 012068b..bb8fef7 100644
--- a/daemon/dbus/gkd-secret-objects.h
+++ b/daemon/dbus/gkd-secret-objects.h
@@ -48,7 +48,7 @@ DBusMessage*        gkd_secret_objects_dispatch                  (GkdSecretObjec
 
 DBusMessage*        gkd_secret_objects_handle_search_items       (GkdSecretObjects *self,
                                                                   DBusMessage *message,
-                                                                  const gchar *coll_id);
+                                                                  GP11Object *object);
 
 void                gkd_secret_objects_append_collection_paths   (GkdSecretObjects *self,
                                                                   DBusMessageIter *iter,
@@ -61,12 +61,8 @@ gboolean            gkd_secret_objects_parse_item_props          (GkdSecretObjec
 void                gkd_secret_objects_append_item_paths         (GkdSecretObjects *self,
                                                                   DBusMessageIter *iter,
                                                                   DBusMessage *message,
-                                                                  const gchar *coll_id);
+                                                                  GP11Object *collection);
 
 GP11Slot*           gkd_secret_objects_get_pkcs11_slot           (GkdSecretObjects *self);
 
-GP11Object*         gkd_secret_objects_lookup_collection         (GkdSecretObjects *self,
-                                                                  const gchar *caller,
-                                                                  const gchar *objpath);
-
 #endif /* __GKD_SECRET_OBJECTS_H__ */
diff --git a/daemon/dbus/gkd-secret-prompt.c b/daemon/dbus/gkd-secret-prompt.c
index 7912c73..aab53af 100644
--- a/daemon/dbus/gkd-secret-prompt.c
+++ b/daemon/dbus/gkd-secret-prompt.c
@@ -21,11 +21,12 @@
 
 #include "config.h"
 
+#include "gkd-dbus-util.h"
 #include "gkd-secret-service.h"
 #include "gkd-secret-prompt.h"
 #include "gkd-secret-objects.h"
 #include "gkd-secret-types.h"
-#include "gkd-dbus-util.h"
+#include "gkd-secret-util.h"
 
 #include "prompt/gkd-prompt.h"
 
@@ -376,15 +377,16 @@ gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
 }
 
 GP11Object*
-gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *objpath)
+gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
 {
-	GkdSecretObjects *objects;
+	GP11Session *session;
 
 	g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
 	g_return_val_if_fail (self->pv->service, NULL);
+	g_return_val_if_fail (path, NULL);
 
-	objects = gkd_secret_service_get_objects (self->pv->service);
-	g_return_val_if_fail (objects, NULL);
+	session = gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
+	g_return_val_if_fail (session, NULL);
 
-	return gkd_secret_objects_lookup_collection (objects, self->pv->caller, objpath);
+	return gkd_secret_util_path_to_collection (session, path);
 }
diff --git a/daemon/dbus/gkd-secret-prompt.h b/daemon/dbus/gkd-secret-prompt.h
index fa29730..4ca1ac9 100644
--- a/daemon/dbus/gkd-secret-prompt.h
+++ b/daemon/dbus/gkd-secret-prompt.h
@@ -60,6 +60,8 @@ const gchar*        gkd_secret_prompt_get_caller              (GkdSecretPrompt *
 
 const gchar*        gkd_secret_prompt_get_object_path         (GkdSecretPrompt *self);
 
+GP11Session*        gkd_secret_prompt_get_pkcs11_session      (GkdSecretPrompt *self);
+
 GP11Object*         gkd_secret_prompt_lookup_collection       (GkdSecretPrompt *self,
                                                                const gchar *objpath);
 
diff --git a/daemon/dbus/gkd-secret-types.h b/daemon/dbus/gkd-secret-types.h
index 426e31a..c230ba4 100644
--- a/daemon/dbus/gkd-secret-types.h
+++ b/daemon/dbus/gkd-secret-types.h
@@ -44,6 +44,7 @@
 #define SECRET_ERROR_NO_SESSION        "org.freedesktop.Secrets.Error.NoSession"
 
 typedef struct _GkdSecretCollection GkdSecretCollection;
+typedef struct _GkdSecretCreate GkdSecretCreate;
 typedef struct _GkdSecretItem GkdSecretItem;
 typedef struct _GkdSecretObjects GkdSecretObjects;
 typedef struct _GkdSecretPrompt GkdSecretPrompt;
diff --git a/daemon/dbus/gkd-secret-util.c b/daemon/dbus/gkd-secret-util.c
new file mode 100644
index 0000000..1c7e162
--- /dev/null
+++ b/daemon/dbus/gkd-secret-util.c
@@ -0,0 +1,411 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gkd-secret-util.h"
+
+#include "pkcs11/pkcs11i.h"
+
+#include <string.h>
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+encode_object_identifier (GString *result, const gchar* name, gssize length)
+{
+	g_assert (result);
+	g_assert (name);
+
+	if (length < 0)
+		length = strlen (name);
+
+	while (length > 0) {
+		char ch = *(name++);
+		--length;
+
+		/* Normal characters can go right through */
+		if (G_LIKELY ((ch >= 'A' && ch <= 'Z') ||
+		              (ch >= 'a' && ch <= 'z') ||
+		              (ch >= '0' && ch <= '9'))) {
+			g_string_append_c_inline (result, ch);
+
+		/* Special characters are encoded with a _ */
+		} else {
+			g_string_append_printf (result, "_%02x", (unsigned int)ch);
+		}
+	}
+}
+
+static gchar*
+decode_object_identifier (const gchar* enc, gssize length)
+{
+	GString *result;
+
+	g_assert (enc);
+
+	if (length < 0)
+		length = strlen (enc);
+
+	result = g_string_sized_new (length);
+	while (length > 0) {
+		char ch = *(enc++);
+		--length;
+
+		/* Underscores get special handling */
+		if (G_UNLIKELY (ch == '_' &&
+		                g_ascii_isxdigit(enc[0]) &&
+		                g_ascii_isxdigit (enc[1]))) {
+			ch = (g_ascii_xdigit_value (enc[0]) * 16) +
+			     (g_ascii_xdigit_value (enc[1]));
+			enc += 2;
+			length -= 2;
+		}
+
+		g_string_append_c_inline (result, ch);
+	}
+
+	return g_string_free (result, FALSE);
+}
+
+static gboolean
+parse_collection_and_item_from_path (const gchar *path, gchar **collection, gchar **item)
+{
+	const gchar *pos;
+
+	g_return_val_if_fail (path, FALSE);
+
+	/* Make sure it starts with our prefix */
+	if (!g_str_has_prefix (path, SECRET_COLLECTION_PREFIX))
+		return FALSE;
+	path += strlen (SECRET_COLLECTION_PREFIX);
+
+	/* Skip the path separator */
+	if (path[0] != '/')
+		return FALSE;
+	++path;
+
+	/* Make sure we have something */
+	if (path[0] == '\0')
+		return FALSE;
+
+	pos = strchr (path, '/');
+
+	/* No item, just a collection */
+	if (pos == NULL) {
+		if (collection)
+			*collection = decode_object_identifier (path, -1);
+		if (item)
+			*item = NULL;
+		return TRUE;
+	}
+
+	/* Make sure we have an item, and no further path bits */
+	if (pos[1] == '\0' || strchr (pos + 1, '/'))
+		return FALSE;
+
+	if (collection)
+		*collection = decode_object_identifier (path, pos - path);
+	if (item)
+		*item = decode_object_identifier (pos + 1, -1);
+	return TRUE;
+}
+
+static gchar*
+get_cached_path (GP11Object *object)
+{
+	gchar *path = g_object_get_data (G_OBJECT (object), "gkd-util-cached-identifier");
+	return g_strdup (path);
+}
+
+static void
+set_cached_path (GP11Object *object, const gchar *path)
+{
+	g_object_set_data_full (G_OBJECT (object), "gkd-util-cached-identifier",
+	                        g_strdup (path), g_free);
+}
+
+static GP11Object*
+item_for_identifier (GP11Session *session, const gchar *coll_id, const gchar *item_id)
+{
+	GP11Object *object = NULL;
+	GError *error = NULL;
+	GList *objects;
+
+	g_assert (coll_id);
+	g_assert (item_id);
+
+	/*
+	 * TODO: I think this could benefit from some sort of
+	 * caching?
+	 */
+
+	objects = gp11_session_find_objects (session, &error,
+	                                     CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
+	                                     CKA_G_COLLECTION, strlen (coll_id), coll_id,
+	                                     CKA_ID, strlen (item_id), item_id,
+	                                     GP11_INVALID);
+
+	if (error != NULL) {
+		g_warning ("couldn't lookup '%s/%s' item: %s", coll_id, item_id, error->message);
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	if (objects) {
+		object = g_object_ref (objects->data);
+		gp11_object_set_session (object, session);
+	}
+
+	gp11_list_unref_free (objects);
+	return object;
+}
+
+static GP11Object*
+collection_for_identifier (GP11Session *session, const gchar *coll_id)
+{
+	GP11Object *object = NULL;
+	GError *error = NULL;
+	GList *objects;
+
+	g_assert (GP11_IS_SESSION (session));
+	g_assert (coll_id);
+
+	objects = gp11_session_find_objects (session, &error,
+	                                     CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
+	                                     CKA_ID, strlen (coll_id), coll_id,
+	                                     GP11_INVALID);
+
+	if (error != NULL) {
+		g_warning ("couldn't lookup '%s' collection: %s", coll_id, error->message);
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	if (objects) {
+		object = objects->data;
+		gp11_object_set_session (object, session);
+		g_object_set_data_full (G_OBJECT (object), "coll-identifier", g_strdup (coll_id), g_free);
+		g_object_ref (object);
+	}
+
+	gp11_list_unref_free (objects);
+	return object;
+}
+
+GP11Object*
+gkd_secret_util_path_to_collection (GP11Session *session, const gchar *path)
+{
+	GP11Object *collection = NULL;
+	gchar *coll_id;
+	gchar *item_id;
+
+	g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+	g_return_val_if_fail (path, NULL);
+
+	/* Figure out which collection or item we're talking about */
+	if (!parse_collection_and_item_from_path (path, &coll_id, &item_id))
+		return NULL;
+
+	g_return_val_if_fail (coll_id, NULL);
+	collection = collection_for_identifier (session, coll_id);
+
+	g_free (coll_id);
+	g_free (item_id);
+
+	if (collection) {
+		set_cached_path (collection, path);
+		gp11_object_set_session (collection, session);
+	}
+
+	return collection;
+}
+
+gchar*
+gkd_secret_util_path_for_collection (GP11Object *object)
+{
+	GError *error = NULL;
+	GString *result;
+	gpointer data;
+	gsize n_data;
+	gchar *path;
+
+	g_return_val_if_fail (GP11_IS_OBJECT (object), NULL);
+
+	path = get_cached_path (object);
+	if (path != NULL)
+		return path;
+
+	data = gp11_object_get_data (object, CKA_ID, &n_data, &error);
+	if (data == NULL) {
+		g_warning ("couldn't lookup identifier for collection: %s",
+		           error->message);
+		g_clear_error (&error);
+		g_return_val_if_reached (NULL);
+	}
+
+	result = g_string_new (SECRET_COLLECTION_PREFIX);
+	g_string_append_c (result, '/');
+	encode_object_identifier (result, data, n_data);
+	g_free (data);
+
+	path = g_string_free (result, FALSE);
+	set_cached_path (object, path);
+	return path;
+}
+
+GP11Object*
+gkd_secret_util_path_to_item (GP11Session *session, const gchar *path)
+{
+	GP11Object *item = NULL;
+	gchar *coll_id;
+	gchar *item_id;
+
+	g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+	g_return_val_if_fail (path, NULL);
+
+	/* Figure out which collection or item we're talking about */
+	if (!parse_collection_and_item_from_path (path, &coll_id, &item_id))
+		return NULL;
+
+	if (coll_id && item_id)
+		item = item_for_identifier (session, coll_id, item_id);
+	g_free (coll_id);
+	g_free (item_id);
+
+	if (item) {
+		set_cached_path (item, path);
+		gp11_object_set_session (item, session);
+	}
+
+	return item;
+}
+
+gchar*
+gkd_secret_util_path_for_item (GP11Object *object)
+{
+	GError *error = NULL;
+	GP11Attributes *attrs;
+	GP11Attribute *attr;
+	GString *result;
+	gchar *path;
+
+	g_return_val_if_fail (GP11_IS_OBJECT (object), NULL);
+
+	path = get_cached_path (object);
+	if (path != NULL)
+		return path;
+
+	attrs = gp11_object_get (object, &error, CKA_ID, CKA_G_COLLECTION, GP11_INVALID);
+	if (attrs == NULL) {
+		g_warning ("couldn't lookup identifier for item: %s", error->message);
+		g_clear_error (&error);
+		g_return_val_if_reached (NULL);
+	}
+
+	result = g_string_new (SECRET_COLLECTION_PREFIX);
+
+	g_string_append_c (result, '/');
+	attr = gp11_attributes_find (attrs, CKA_G_COLLECTION);
+	g_return_val_if_fail (attr && !gp11_attribute_is_invalid (attr), NULL);
+	encode_object_identifier (result, (const gchar*)attr->value, attr->length);
+
+	g_string_append_c (result, '/');
+	attr = gp11_attributes_find (attrs, CKA_ID);
+	g_return_val_if_fail (attr && !gp11_attribute_is_invalid (attr), NULL);
+	encode_object_identifier (result, (const gchar*)attr->value, attr->length);
+
+	gp11_attributes_unref (attrs);
+
+	path = g_string_free (result, FALSE);
+	set_cached_path (object, path);
+	return path;
+}
+
+GP11Object*
+gkd_secret_util_path_to_object (GP11Session *session, const gchar *path,
+                                gboolean *is_item)
+{
+	GP11Object *object = NULL;
+	gchar *coll_id;
+	gchar *item_id;
+
+	g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
+	g_return_val_if_fail (path, NULL);
+
+	/* Figure out which collection or item we're talking about */
+	if (!parse_collection_and_item_from_path (path, &coll_id, &item_id))
+		return NULL;
+
+	if (item_id) {
+		object = item_for_identifier (session, coll_id, item_id);
+		if (is_item)
+			*is_item = TRUE;
+	} else {
+		object = collection_for_identifier (session, coll_id);
+	}
+
+	g_free (coll_id);
+	g_free (item_id);
+
+	if (object) {
+		set_cached_path (object, path);
+		gp11_object_set_session (object, session);
+	}
+
+	return object;
+}
+
+
+gchar*
+gkd_secret_util_identifier_for_collection (GP11Object *collection)
+{
+	GError *error = NULL;
+	gchar *identifier = NULL;
+	gpointer data;
+	gsize n_data;
+	gchar *path;
+
+	g_return_val_if_fail (GP11_IS_OBJECT (collection), NULL);
+
+	/* Try to parse it out of the path */
+	path = get_cached_path (collection);
+	if (path != NULL) {
+		parse_collection_and_item_from_path (path, &identifier, NULL);
+		g_free (path);
+	}
+
+	/* Must do a lookup */
+	if (identifier == NULL) {
+		data = gp11_object_get_data (collection, CKA_ID, &n_data, &error);
+		if (data == NULL) {
+			g_warning ("couldn't get identifier for collection: %s", error->message);
+			g_clear_error (&error);
+		} else {
+			identifier = g_strndup (data, n_data);
+			g_free (data);
+		}
+	}
+
+	return identifier;
+}
diff --git a/daemon/dbus/gkd-secret-util.h b/daemon/dbus/gkd-secret-util.h
new file mode 100644
index 0000000..611899a
--- /dev/null
+++ b/daemon/dbus/gkd-secret-util.h
@@ -0,0 +1,45 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GKD_SECRET_UTIL_H__
+#define __GKD_SECRET_UTIL_H__
+
+#include "gkd-secret-types.h"
+
+#include "gp11/gp11.h"
+
+GP11Object*       gkd_secret_util_path_to_collection                    (GP11Session *session,
+                                                                         const gchar *path);
+
+GP11Object*       gkd_secret_util_path_to_item                          (GP11Session *session,
+                                                                         const gchar *path);
+
+GP11Object*       gkd_secret_util_path_to_object                        (GP11Session *session,
+                                                                         const gchar *path,
+                                                                         gboolean *is_item);
+
+gchar*            gkd_secret_util_path_for_collection                   (GP11Object *object);
+
+gchar*            gkd_secret_util_path_for_item                         (GP11Object *object);
+
+gchar*            gkd_secret_util_identifier_for_collection             (GP11Object *collection);
+
+#endif /* __GKD_SECRET_UTIL_H__ */



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