[gnome-keyring/dbus-api] [dbus] Do our own dispatch of dbus messages.



commit 3e8b8fc73a4c70a91159d92efe1a74d0a3f31051
Author: Stef Walter <stef memberwebs com>
Date:   Sat Aug 22 19:34:13 2009 +0000

    [dbus] Do our own dispatch of dbus messages.
    
    Do our own dispatch of dbus messages, which allows us to:
    a) Make sure we've identified the client, b) show certain
    objects to certain clients.

 daemon/dbus/gkd-secrets-objects.c |   98 ++++-----
 daemon/dbus/gkd-secrets-objects.h |    4 +-
 daemon/dbus/gkd-secrets-service.c |  416 +++++++++++++++++++++++--------------
 daemon/dbus/gkd-secrets-service.h |    1 -
 daemon/dbus/gkd-secrets-session.c |  116 +++++------
 daemon/dbus/gkd-secrets-session.h |    4 +-
 daemon/dbus/gkd-secrets-types.h   |    2 +-
 pkcs11/pkcs11i.h                  |    2 -
 8 files changed, 356 insertions(+), 287 deletions(-)
---
diff --git a/daemon/dbus/gkd-secrets-objects.c b/daemon/dbus/gkd-secrets-objects.c
index 5e6259a..5a3cb3e 100644
--- a/daemon/dbus/gkd-secrets-objects.c
+++ b/daemon/dbus/gkd-secrets-objects.c
@@ -93,53 +93,6 @@ gkd_sercets_objects_property_handler (DBusConnection *conn, DBusMessage *message
 }
 #endif
 
-static DBusHandlerResult
-gkd_secrets_objects_message_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data)
-{
-	GkdSecretsObjects *self = user_data;
-	DBusMessage *reply = NULL;
-
-	g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
-	g_return_val_if_fail (GKD_SECRETS_IS_OBJECTS (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
-
-#if 0
-	/* Check if it's properties, and hand off to property handler. */
-	if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
-		return gkd_sercets_objects_property_handler (conn, message, self);
-
-	/* org.freedesktop.Secrets.Objects.Close() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Close"))
-		return gkd_secrets_objects_close (self, conn, message);
-
-	/* org.freedesktop.Secrets.Objects.Negotiate() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Negotiate"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Objects.GetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Objects.SetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "SetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Objects.GetSecrets() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecrets"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Objects.GetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-#endif
-
-	if (reply == NULL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	dbus_connection_send (conn, reply, NULL);
-	dbus_message_unref (reply);
-	return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -153,11 +106,6 @@ gkd_secrets_objects_constructor (GType type, guint n_props, GObjectConstructPara
 	g_return_val_if_fail (self->pkcs11_slot, NULL);
 	g_return_val_if_fail (self->service, NULL);
 
-	/* Register all the collections, and items paths */
-	if (!dbus_connection_register_fallback (gkd_secrets_service_get_connection (self->service), SECRETS_COLLECTION_PREFIX,
-	                                        &GKD_SECRETS_OBJECTS_GET_CLASS (self)->dbus_vtable, self))
-		g_return_val_if_reached (NULL);
-
 	return G_OBJECT (self);
 }
 
@@ -178,9 +126,6 @@ gkd_secrets_objects_dispose (GObject *obj)
 	}
 
 	if (self->service) {
-		if (!dbus_connection_unregister_object_path (gkd_secrets_service_get_connection (self->service), 
-		                                             SECRETS_COLLECTION_PREFIX))
-			g_return_if_reached ();
 		g_object_remove_weak_pointer (G_OBJECT (self->service),
 		                              (gpointer*)&(self->service));
 		self->service = NULL;
@@ -255,8 +200,6 @@ gkd_secrets_objects_class_init (GkdSecretsObjectsClass *klass)
 	gobject_class->set_property = gkd_secrets_objects_set_property;
 	gobject_class->get_property = gkd_secrets_objects_get_property;
 
-	klass->dbus_vtable.message_function = gkd_secrets_objects_message_handler;
-
 	g_object_class_install_property (gobject_class, PROP_PKCS11_SLOT,
 	        g_param_spec_object ("pkcs11-slot", "Pkcs11 Slot", "PKCS#11 slot that we use for secrets",
 	                             GP11_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -276,3 +219,44 @@ gkd_secrets_objects_get_pkcs11_slot (GkdSecretsObjects *self)
 	g_return_val_if_fail (GKD_SECRETS_IS_OBJECTS (self), NULL);
 	return self->pkcs11_slot;
 }
+
+DBusMessage*
+gkd_secrets_objects_dispatch (GkdSecretsObjects *self, DBusMessage *message)
+{
+	DBusMessage *reply = NULL;
+
+	g_return_val_if_fail (GKD_SECRETS_IS_OBJECTS (self), NULL);
+	g_return_val_if_fail (message, NULL);
+
+#if 0
+	/* Check if it's properties, and hand off to property handler. */
+	if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
+		return gkd_sercets_objects_property_handler (conn, message, self);
+
+	/* org.freedesktop.Secrets.Objects.Close() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Close"))
+		return gkd_secrets_objects_close (self, conn, message);
+
+	/* org.freedesktop.Secrets.Objects.Negotiate() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Negotiate"))
+		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Objects.GetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
+		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Objects.SetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "SetSecret"))
+		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Objects.GetSecrets() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecrets"))
+		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Objects.GetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
+		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+#endif
+
+	return reply;
+}
diff --git a/daemon/dbus/gkd-secrets-objects.h b/daemon/dbus/gkd-secrets-objects.h
index 1a179d3..6bef63a 100644
--- a/daemon/dbus/gkd-secrets-objects.h
+++ b/daemon/dbus/gkd-secrets-objects.h
@@ -39,11 +39,13 @@ typedef struct _GkdSecretsObjectsClass GkdSecretsObjectsClass;
 
 struct _GkdSecretsObjectsClass {
 	GObjectClass parent_class;
-	DBusObjectPathVTable dbus_vtable;
 };
 
 GType               gkd_secrets_objects_get_type               (void);
 
+DBusMessage*        gkd_secrets_objects_dispatch               (GkdSecretsObjects *self,
+                                                                DBusMessage *message);
+
 GP11Slot*           gkd_secrets_objects_get_pkcs11_slot        (GkdSecretsObjects *self);
 
 #endif /* __GKD_SECRETS_OBJECTS_H__ */
diff --git a/daemon/dbus/gkd-secrets-service.c b/daemon/dbus/gkd-secrets-service.c
index d1f0283..6b06a54 100644
--- a/daemon/dbus/gkd-secrets-service.c
+++ b/daemon/dbus/gkd-secrets-service.c
@@ -31,6 +31,10 @@
 
 #include "gp11/gp11.h"
 
+#include "pkcs11/pkcs11i.h"
+
+#include <string.h>
+
 enum {
 	PROP_0,
 	PROP_CONNECTION,
@@ -45,7 +49,7 @@ enum {
 struct _GkdSecretsService {
 	GObject parent;
 	DBusConnection *connection;
-	GHashTable *sessions;
+	GHashTable *clients;
 	gchar *match_rule;
 	GkdSecretsObjects *objects;
 #if 0
@@ -57,6 +61,18 @@ struct _GkdSecretsService {
 #define LOC_DEFAULT_FILE    (gkd_location_from_string ("LOCAL:/keyrings/default"))
 #endif
 
+typedef struct _ServiceClient {
+	gchar *caller_peer;
+	gchar *caller_exec;
+	pid_t caller_pid;
+	CK_G_APPLICATION app;
+	GP11Session *pkcs11_session;
+	GList *sessions;
+} ServiceClient;
+
+/* Forward declaration */
+static void service_dispatch_message (GkdSecretsService *, DBusMessage *);
+
 G_DEFINE_TYPE (GkdSecretsService, gkd_secrets_service, G_TYPE_OBJECT);
 
 /* -----------------------------------------------------------------------------
@@ -81,64 +97,56 @@ update_default (GkdSecretsService *self)
 }
 #endif
 
-static void
-dispose_session (GkdSecretsSession *session)
-{
-	g_object_run_dispose (G_OBJECT (session));
-	g_object_unref (session);
-}
-
-static void
-take_session (GkdSecretsService *self, GkdSecretsSession *session)
+static gboolean
+object_path_has_prefix (const gchar *path, const gchar *prefix)
 {
-	GPtrArray *sessions;
-	const gchar *caller;
+	gsize len;
 
-	g_assert (GKD_SECRETS_SERVICE (self));
-	g_assert (GKD_SECRETS_SESSION (session));
+	g_assert (prefix);
 
-	caller = gkd_secrets_session_get_caller (session);
-	sessions = g_hash_table_lookup (self->sessions, caller);
-	if (!sessions) {
-		sessions = g_ptr_array_new ();
-		g_hash_table_replace (self->sessions, g_strdup (caller), sessions);
-	}
+	if (!path)
+		return FALSE;
 
-	g_ptr_array_add (sessions, session);
+	len = strlen (prefix);
+	return g_ascii_strncasecmp (path, prefix, len) == 0 &&
+	       (path[len] == '\0' || path[len] == '/');
 }
 
 static void
-remove_session (GkdSecretsService *self, GkdSecretsSession *session)
+dispose_session (GkdSecretsSession *session)
 {
-	GPtrArray *sessions;
-	const gchar *caller;
+	g_object_run_dispose (G_OBJECT (session));
+	g_object_unref (session);
+}
 
-	g_assert (GKD_SECRETS_SERVICE (self));
-	g_assert (GKD_SECRETS_SESSION (session));
+static void
+free_client (gpointer data)
+{
+	ServiceClient *client = data;
+	GList *l;
 
-	caller = gkd_secrets_session_get_caller (session);
-	sessions = g_hash_table_lookup (self->sessions, caller);
-	g_return_if_fail (sessions);
+	if (!client)
+		return;
 
-	g_ptr_array_remove_fast (sessions, session);
-	if (sessions->len == 0)
-		g_hash_table_remove (self->sessions, caller);
+	/* Info about our client */
+	g_free (client->caller_peer);
+	g_free (client->caller_exec);
 
-	dispose_session (session);
-}
+	/* The session we use for accessing as our client */
+	if (client->pkcs11_session) {
+#if 0
+		gp11_session_close (client->pkcs11_session, NULL);
+#endif
+		g_object_unref (client->pkcs11_session);
+	}
 
-static void
-free_sessions (gpointer data)
-{
-	GPtrArray *sessions = data;
-	guint i;
+	/* The secrets API sessions client has open */
+	for (l = client->sessions; l; l = g_list_next (l))
+		dispose_session (l->data);
 
-	for (i = 0; i < sessions->len; ++i)
-		dispose_session (g_ptr_array_index (sessions, i));
-	g_ptr_array_free (sessions, TRUE);
+	g_free (client);
 }
 
-
 typedef struct _on_get_connection_unix_process_id_args {
 	GkdSecretsService *self;
 	DBusMessage *message;
@@ -161,89 +169,76 @@ on_get_connection_unix_process_id (DBusPendingCall *pending, gpointer user_data)
 	on_get_connection_unix_process_id_args *args = user_data;
 	DBusMessage *reply = NULL;
 	DBusError error = DBUS_ERROR_INIT;
-	gchar *caller_exec = NULL;
 	dbus_uint32_t caller_pid = 0;
-	GkdSecretsSession *session;
 	GkdSecretsService *self;
+	ServiceClient *client;
 	const gchar *caller;
-	const gchar *path;
 
 	g_return_if_fail (GKD_SECRETS_IS_SERVICE (args->self));
 	self = args->self;
 
-	caller = dbus_message_get_sender (args->message);
-	g_return_if_fail (caller);
-
 	/* Get the resulting process ID */
 	reply = dbus_pending_call_steal_reply (pending);
 	g_return_if_fail (reply);
 
-	/* An error returned from GetConnectionUnixProcessID */
-	if (dbus_set_error_from_message (&error, reply)) {
-		g_message ("couldn't get the caller's unix process id: %s", error.message);
-		caller_pid = 0;
-		dbus_error_free (&error);
+	caller = dbus_message_get_sender (args->message);
+	g_return_if_fail (caller);
 
-	/* A PID was returned from GetConnectionUnixProcessID */
-	} else {
-		if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID))
-			g_return_if_reached ();
-	}
+	client = g_hash_table_lookup (self->clients, caller);
+	if (client == NULL) {
 
-	dbus_message_unref (reply);
+		/* An error returned from GetConnectionUnixProcessID */
+		if (dbus_set_error_from_message (&error, reply)) {
+			g_message ("couldn't get the caller's unix process id: %s", error.message);
+			caller_pid = 0;
+			dbus_error_free (&error);
 
-	/* Dig out the process executable if possible */
-	if (caller_pid != 0)
-		caller_exec = egg_unix_credentials_executable (caller_pid);
+		/* A PID was returned from GetConnectionUnixProcessID */
+		} else {
+			if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID))
+				g_return_if_reached ();
+		}
 
-	/* Now we can create a session with this information */
-	session = g_object_new (GKD_SECRETS_TYPE_SESSION,
-	                        "caller-executable", caller_exec,
-	                        "caller", caller,
-	                        "service", self,
-	                        NULL);
-	g_free (caller_exec);
+		/* Initialize the client object */
+		client = g_new0 (ServiceClient, 1);
+		client->caller_peer = g_strdup (caller);
+		client->caller_pid = caller_pid;
+		if (caller_pid != 0)
+			client->caller_exec = egg_unix_credentials_executable (caller_pid);
+		client->app.applicationData = client;
 
-	/* Take ownership of the session */
-	take_session (self, session);
+		g_hash_table_replace (self->clients, client->caller_peer, client);
+	}
 
-	path = gkd_secrets_session_get_object_path (session);
-	reply = dbus_message_new_method_return (args->message);
-	dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
-	dbus_connection_send (args->self->connection, reply, NULL);
 	dbus_message_unref (reply);
-}
 
-/* -----------------------------------------------------------------------------
- * DBUS
- */
+	/* Dispatch the original message again */
+	service_dispatch_message (self, args->message);
+}
 
-static DBusHandlerResult
-service_begin_open_session (GkdSecretsService *self, DBusConnection *conn, DBusMessage *message)
+static void
+initialize_service_client (GkdSecretsService *self, DBusMessage *message)
 {
 	on_get_connection_unix_process_id_args *args;
-	DBusMessage *request, *reply;
+	DBusMessage *request;
 	DBusPendingCall *pending;
 	const gchar *caller;
 
 	g_assert (GKD_SECRETS_IS_SERVICE (self));
-	g_assert (conn && message);
+	g_assert (message);
+
+	args = g_new0 (on_get_connection_unix_process_id_args, 1);
+	args->self = g_object_ref (self);
+	args->message = dbus_message_ref (message);
 
-	/* Who is the caller of this message? */
 	caller = dbus_message_get_sender (message);
-	if (caller == NULL) {
-		reply = dbus_message_new_error (message, DBUS_ERROR_FAILED,
-		                                "Could not not identify calling client application");
-		dbus_connection_send (conn, reply, NULL);
-		dbus_message_unref (reply);
-		return DBUS_HANDLER_RESULT_HANDLED;
-	}
+	g_return_if_fail (caller);
 
 	/* Message org.freedesktop.DBus.GetConnectionUnixProcessID(IN String caller) */
 	request = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus",
 	                                        "org.freedesktop.DBus", "GetConnectionUnixProcessID");
 	if (!request || !dbus_message_append_args (request, DBUS_TYPE_STRING, &caller, DBUS_TYPE_INVALID))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+		g_return_if_reached ();
 
 	/*
 	 * Send of request for GetConnectionUnixProcessID, with lowish timeout.
@@ -251,22 +246,21 @@ service_begin_open_session (GkdSecretsService *self, DBusConnection *conn, DBusM
 	 * In addition we want to send off a reply to our caller, before it
 	 * times out.
 	 */
-	if (!dbus_connection_send_with_reply (conn, request, &pending, 2000))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+	if (!dbus_connection_send_with_reply (self->connection, request, &pending, 2000))
+		g_return_if_reached ();
 	dbus_message_unref (request);
 
-	args = g_new0 (on_get_connection_unix_process_id_args, 1);
-	args->self = g_object_ref (self);
-	args->message = dbus_message_ref (message);
-
 	/* Track our new session object, on this call */
 	dbus_pending_call_set_notify (pending, on_get_connection_unix_process_id, args,
 	                              free_on_get_connection_unix_process_id_args);
 	dbus_pending_call_unref (pending);
-
-	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+
+/* -----------------------------------------------------------------------------
+ * DBUS
+ */
+
 static DBusMessage*
 service_property_handler (GkdSecretsService *self, DBusMessage *message)
 {
@@ -290,45 +284,118 @@ service_property_handler (GkdSecretsService *self, DBusMessage *message)
 #endif
 }
 
-static DBusHandlerResult
-gkd_secrets_service_message_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data)
+static DBusMessage*
+service_method_open_session (GkdSecretsService *self, DBusMessage *message)
+{
+	GkdSecretsSession *session;
+	ServiceClient *client;
+	DBusMessage *reply;
+	const gchar *caller;
+	const gchar *path;
+
+	if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
+		return NULL;
+
+	caller = dbus_message_get_sender (message);
+
+	/* Now we can create a session with this information */
+	session = g_object_new (GKD_SECRETS_TYPE_SESSION,
+	                        "caller", caller,
+	                        "service", self,
+	                        NULL);
+
+	/* Take ownership of the session */
+	client = g_hash_table_lookup (self->clients, caller);
+	g_return_val_if_fail (client, NULL);
+	client->sessions = g_list_prepend (client->sessions, session);
+
+	/* Return the response */
+	path = gkd_secrets_session_get_object_path (session);
+	reply = dbus_message_new_method_return (message);
+	dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
+	return reply;
+}
+
+static DBusMessage*
+service_method_handler (GkdSecretsService *self, DBusMessage *message)
 {
-	GkdSecretsService *self = user_data;
 	DBusMessage *reply = NULL;
 
-	g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
-	g_return_val_if_fail (GKD_SECRETS_IS_SERVICE (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+	g_return_val_if_fail (message, NULL);
+	g_return_val_if_fail (GKD_SECRETS_IS_SERVICE (self), NULL);
+
+	if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "OpenSession"))
+		reply = service_method_open_session (self, message);
+
+	return reply;
+}
+
+static void
+service_dispatch_message (GkdSecretsService *self, DBusMessage *message)
+{
+	DBusMessage *reply = NULL;
+	const gchar *caller;
+	ServiceClient *client;
+	const gchar *path;
+	GList *l;
+
+	g_assert (GKD_SECRETS_IS_SERVICE (self));
+	g_assert (message);
+
+	/* The first thing we do is try to allocate a client context */
+	caller = dbus_message_get_sender (message);
+	if (caller == NULL) {
+		reply = dbus_message_new_error (message, DBUS_ERROR_FAILED,
+		                                "Could not not identify calling client application");
+		dbus_connection_send (self->connection, reply, NULL);
+		dbus_message_unref (reply);
+		return;
+	}
 
-	/* Check if it's properties, and hand off to property handler. */
-	if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
-		reply = service_property_handler (self, message);
+	client = g_hash_table_lookup (self->clients, caller);
+	if (client == NULL) {
+		initialize_service_client (self, message);
+		return; /* This function called again, when client is initialized */
+	}
 
-	/* org.freedesktop.Secrets.Service.OpenSession() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "OpenSession"))
-		return service_begin_open_session (self, conn, message);
+	path = dbus_message_get_path (message);
+	g_return_if_fail (path);
 
-	/* org.freedesktop.Secrets.Service.CreateCollection() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "CreateCollection"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+	/* Dispatched to a session, find a session in this client */
+	if (object_path_has_prefix (path, SECRETS_SESSION_PREFIX)) {
+		for (l = client->sessions; l; l = g_list_next (l)) {
+			if (g_str_equal (path, gkd_secrets_session_get_object_path (l->data))) {
+				reply = gkd_secrets_session_dispatch (l->data, message);
+				break;
+			}
+		}
 
-	/* org.freedesktop.Secrets.Service.LockService() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "CreateCollection"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+	/* Dispatched to a collection, off it goes */
+	} else if (object_path_has_prefix (path, SECRETS_COLLECTION_PREFIX)) {
+		reply = gkd_secrets_objects_dispatch (self->objects, message);
 
-	/* org.freedesktop.Secrets.Service.SearchItems() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "SearchItems"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+	} else if (g_str_equal (path, SECRETS_SERVICE_PATH)) {
 
-	/* org.freedesktop.Secrets.Service.RetrieveSecrets() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "RetrieveSecrets"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
+		/* Check if it's properties, and hand off to property handler. */
+		if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
+			reply = service_property_handler (self, message);
+		else
+			reply = service_method_handler (self, message);
+	}
 
-	if (reply == NULL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	/* Should we send an error? */
+	if (!reply && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
+		reply = dbus_message_new_error_printf (message, DBUS_ERROR_UNKNOWN_METHOD, 
+		                                       "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
+		                                       dbus_message_get_member (message),
+		                                       dbus_message_get_signature (message),
+		                                       dbus_message_get_interface (message));
+	}
 
-	dbus_connection_send (conn, reply, NULL);
-	dbus_message_unref (reply);
-	return DBUS_HANDLER_RESULT_HANDLED;
+	if (reply) {
+		dbus_connection_send (self->connection, reply, NULL);
+		dbus_message_unref (reply);
+	}
 }
 
 static DBusHandlerResult
@@ -338,25 +405,62 @@ gkd_secrets_service_filter_handler (DBusConnection *conn, DBusMessage *message,
 	const gchar *object_name;
 	const gchar *old_owner;
 	const gchar *new_owner;
+	const gchar *path;
+	const gchar *interface;
 
 	g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
 	g_return_val_if_fail (GKD_SECRETS_IS_SERVICE (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
 
 	/* org.freedesktop.DBus.NameOwnerChanged(STRING name, STRING old_owner, STRING new_owner) */
-	if (!dbus_message_is_signal (message, BUS_INTERFACE, "NameOwnerChanged") || 
-	    !dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &object_name, 
-	                            DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner,
-	                            DBUS_TYPE_INVALID))
+	if (dbus_message_is_signal (message, BUS_INTERFACE, "NameOwnerChanged") && 
+	    dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &object_name, 
+	                           DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner,
+	                           DBUS_TYPE_INVALID)) {
+
+		/*
+		 * A peer is connecting or disconnecting from the bus,
+		 * remove any client info, when client gone.
+		 */
+
+		g_return_val_if_fail (object_name && new_owner, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+		if (g_str_equal (new_owner, "") && object_name[0] == ':')
+			g_hash_table_remove (self->clients, object_name);
+
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	/*
+	 * If the path is a within our object tree, then we do our own dispatch.
+	 */
+	path = dbus_message_get_path (message);
+	switch (dbus_message_get_type (message)) {
+
+	/* Dispatch any method call on our interfaces, for our objects */
+	case DBUS_MESSAGE_TYPE_METHOD_CALL:
+		if (object_path_has_prefix (path, SECRETS_SERVICE_PATH)) {
+			interface = dbus_message_get_interface (message);
+			if (interface == NULL ||
+			    g_str_has_prefix (interface, SECRETS_INTERFACE_PREFIX) ||
+			    g_str_equal (interface, DBUS_INTERFACE_PROPERTIES)) {
+				service_dispatch_message (self, message);
+				return DBUS_HANDLER_RESULT_HANDLED;
+			}
+		}
+		break;
 
-	g_return_val_if_fail (object_name && new_owner, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+	/* Dispatch any signal for one of our objects */
+	case DBUS_MESSAGE_TYPE_SIGNAL:
+		if (object_path_has_prefix (path, SECRETS_SERVICE_PATH)) {
+			service_dispatch_message (self, message);
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+		break;
 
-	/* See if it's something that owns our sessions, close if so */
-	if (g_str_equal (new_owner, "") && object_name[0] == ':')
-		g_hash_table_remove (self->sessions, object_name);
+	default:
+		break;
+	}
 
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
 }
 
 /* -----------------------------------------------------------------------------
@@ -374,11 +478,6 @@ gkd_secrets_service_constructor (GType type, guint n_props, GObjectConstructPara
 	g_return_val_if_fail (self, NULL);
 	g_return_val_if_fail (self->connection, NULL);
 
-	/* Now register the object */
-	if (!dbus_connection_register_object_path (self->connection, SECRETS_SERVICE_PATH,
-	                                           &GKD_SECRETS_SERVICE_GET_CLASS (self)->dbus_vtable, self))
-		g_return_val_if_reached (NULL);
-
 	/* Find the pkcs11-slot parameter */
 	for (i = 0; !slot && i < n_props; ++i) {
 		if (g_str_equal (props[i].pspec->name, "pkcs11-slot"))
@@ -399,17 +498,18 @@ gkd_secrets_service_constructor (GType type, guint n_props, GObjectConstructPara
 		dbus_error_free (&error);
 		g_free (self->match_rule);
 		self->match_rule = NULL;
-	} else {
-		dbus_connection_add_filter (self->connection, gkd_secrets_service_filter_handler, self, NULL);
 	}
 
+	if (!dbus_connection_add_filter (self->connection, gkd_secrets_service_filter_handler, self, NULL))
+		g_return_val_if_reached (NULL);
+
 	return G_OBJECT (self);
 }
 
 static void
 gkd_secrets_service_init (GkdSecretsService *self)
 {
-	self->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_sessions);
+	self->clients = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_client);
 }
 
 static void
@@ -419,14 +519,13 @@ gkd_secrets_service_dispose (GObject *obj)
 
 	if (self->match_rule) {
 		g_return_if_fail (self->connection);
-		dbus_connection_remove_filter (self->connection, gkd_secrets_service_filter_handler, self);
 		dbus_bus_remove_match (self->connection, self->match_rule, NULL);
 		g_free (self->match_rule);
 		self->match_rule = NULL;
 	}
 
 	/* Closes all the sessions */
-	g_hash_table_remove_all (self->sessions);
+	g_hash_table_remove_all (self->clients);
 
 	/* Hide all the objects */
 	if (self->objects) {
@@ -436,8 +535,7 @@ gkd_secrets_service_dispose (GObject *obj)
 	}
 
 	if (self->connection) {
-		if (!dbus_connection_unregister_object_path (self->connection, SECRETS_SERVICE_PATH))
-			g_return_if_reached ();
+		dbus_connection_remove_filter (self->connection, gkd_secrets_service_filter_handler, self);
 		dbus_connection_unref (self->connection);
 		self->connection = NULL;
 	}
@@ -450,9 +548,9 @@ gkd_secrets_service_finalize (GObject *obj)
 {
 	GkdSecretsService *self = GKD_SECRETS_SERVICE (obj);
 
-	g_assert (g_hash_table_size (self->sessions) == 0);
-	g_hash_table_destroy (self->sessions);
-	self->sessions = NULL;
+	g_assert (g_hash_table_size (self->clients) == 0);
+	g_hash_table_destroy (self->clients);
+	self->clients = NULL;
 
 #if 0
 	g_free (self->pv->default_collection);
@@ -513,8 +611,6 @@ gkd_secrets_service_class_init (GkdSecretsServiceClass *klass)
 	gobject_class->set_property = gkd_secrets_service_set_property;
 	gobject_class->get_property = gkd_secrets_service_get_property;
 
-	klass->dbus_vtable.message_function = gkd_secrets_service_message_handler;
-
 	g_object_class_install_property (gobject_class, PROP_CONNECTION,
 		g_param_spec_boxed ("connection", "Connection", "DBus Connection",
 		                    GKD_DBUS_TYPE_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -545,10 +641,18 @@ gkd_secrets_service_get_pkcs11_slot (GkdSecretsService *self)
 void
 gkd_secrets_service_close_session (GkdSecretsService *self, GkdSecretsSession *session)
 {
+	ServiceClient *client;
+	const gchar *caller;
+
 	g_return_if_fail (GKD_SECRETS_IS_SERVICE (self));
 	g_return_if_fail (GKD_SECRETS_IS_SESSION (session));
 
-	remove_session (self, session);
+	caller = gkd_secrets_session_get_caller (session);
+	client = g_hash_table_lookup (self->clients, caller);
+	g_return_if_fail (client);
+
+	client->sessions = g_list_remove (client->sessions, session);
+	dispose_session (session);
 }
 
 #if 0
diff --git a/daemon/dbus/gkd-secrets-service.h b/daemon/dbus/gkd-secrets-service.h
index 83c182d..27fc76c 100644
--- a/daemon/dbus/gkd-secrets-service.h
+++ b/daemon/dbus/gkd-secrets-service.h
@@ -41,7 +41,6 @@ typedef struct _GkdSecretsServiceClass GkdSecretsServiceClass;
 
 struct _GkdSecretsServiceClass {
 	GObjectClass parent_class;
-	DBusObjectPathVTable dbus_vtable;
 #if 0
 	/* signals --------------------------------------------------------- */
 
diff --git a/daemon/dbus/gkd-secrets-session.c b/daemon/dbus/gkd-secrets-session.c
index 63c1cc3..af02216 100644
--- a/daemon/dbus/gkd-secrets-session.c
+++ b/daemon/dbus/gkd-secrets-session.c
@@ -41,7 +41,6 @@ struct _GkdSecretsSession {
 	GkdSecretsService *service;
 	gchar *caller_exec;
 	gchar *caller;
-	gboolean registered;
 };
 
 G_DEFINE_TYPE (GkdSecretsSession, gkd_secrets_session, G_TYPE_OBJECT);
@@ -96,58 +95,6 @@ session_property_handler (GkdSecretsSession *self, DBusMessage *message)
 #endif
 }
 
-static DBusHandlerResult
-gkd_secrets_session_message_handler (DBusConnection *conn, DBusMessage *message, gpointer user_data)
-{
-	GkdSecretsSession *self = user_data;
-	DBusMessage *reply = NULL;
-	const gchar *caller;
-
-	g_return_val_if_fail (conn && message, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
-	g_return_val_if_fail (GKD_SECRETS_IS_SESSION (self), DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
-
-	/* Who is the caller of this message? */
-	caller = dbus_message_get_sender (message);
-	if (!caller || !g_str_equal (caller, self->caller)) {
-		reply = dbus_message_new_error (message, DBUS_ERROR_ACCESS_DENIED, 
-		                                "This session does not belong to your application");
-
-	/* Check if it's properties, and hand off to property handler. */
-	} else if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
-		reply = session_property_handler (self, message);
-
-	/* org.freedesktop.Secrets.Session.Close() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Close"))
-		reply = session_method_close (self, message);
-
-	/* org.freedesktop.Secrets.Session.Negotiate() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Negotiate"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Session.GetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Session.SetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "SetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Session.GetSecrets() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecrets"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	/* org.freedesktop.Secrets.Session.GetSecret() */
-	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
-		g_return_val_if_reached (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); /* TODO: Need to implement */
-
-	if (reply == NULL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	dbus_connection_send (conn, reply, NULL);
-	dbus_message_unref (reply);
-	return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -161,11 +108,8 @@ gkd_secrets_session_constructor (GType type, guint n_props, GObjectConstructPara
 	g_return_val_if_fail (self->caller, NULL);
 	g_return_val_if_fail (self->service, NULL);
 
-	/* Now register the object */
+	/* Setup the path for the object */
 	self->object_path = g_strdup_printf (SECRETS_SESSION_PREFIX "/s%d", ++unique_session_number);
-	if (!dbus_connection_register_object_path (gkd_secrets_service_get_connection (self->service), self->object_path,
-	                                           &GKD_SECRETS_SESSION_GET_CLASS (self)->dbus_vtable, self))
-		g_return_val_if_reached (NULL);
 
 	return G_OBJECT (self);
 }
@@ -181,15 +125,8 @@ gkd_secrets_session_dispose (GObject *obj)
 {
 	GkdSecretsSession *self = GKD_SECRETS_SESSION (obj);
 
-	if (self->object_path) {
-		if (self->service) {
-			if (!dbus_connection_unregister_object_path (gkd_secrets_service_get_connection (self->service), 
-			                                             self->object_path))
-				g_return_if_reached ();
-		}
-		g_free (self->object_path);
-		self->object_path = NULL;
-	}
+	g_free (self->object_path);
+	self->object_path = NULL;
 
 	if (self->service) {
 		g_object_remove_weak_pointer (G_OBJECT (self->service),
@@ -281,8 +218,6 @@ gkd_secrets_session_class_init (GkdSecretsSessionClass *klass)
 	gobject_class->set_property = gkd_secrets_session_set_property;
 	gobject_class->get_property = gkd_secrets_session_get_property;
 
-	klass->dbus_vtable.message_function = gkd_secrets_session_message_handler;
-
 	g_object_class_install_property (gobject_class, PROP_CALLER,
 		g_param_spec_string ("caller", "Caller", "DBus caller name",
 		                     NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
@@ -304,6 +239,51 @@ gkd_secrets_session_class_init (GkdSecretsSessionClass *klass)
  * PUBLIC
  */
 
+DBusMessage*
+gkd_secrets_session_dispatch (GkdSecretsSession *self, DBusMessage *message)
+{
+	DBusMessage *reply = NULL;
+	const gchar *caller;
+
+	g_return_val_if_fail (message, NULL);
+	g_return_val_if_fail (GKD_SECRETS_IS_SESSION (self), NULL);
+
+	/* This should already have been caught elsewhere */
+	caller = dbus_message_get_sender (message);
+	if (!caller || !g_str_equal (caller, self->caller))
+		g_return_val_if_reached (NULL);
+
+	/* Check if it's properties, and hand off to property handler. */
+	if (dbus_message_has_interface (message, PROPERTIES_INTERFACE))
+		reply = session_property_handler (self, message);
+
+	/* org.freedesktop.Secrets.Session.Close() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Close"))
+		reply = session_method_close (self, message);
+
+	/* org.freedesktop.Secrets.Session.Negotiate() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "Negotiate"))
+		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Session.GetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
+		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Session.SetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "SetSecret"))
+		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Session.GetSecrets() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecrets"))
+		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+
+	/* org.freedesktop.Secrets.Session.GetSecret() */
+	else if (dbus_message_is_method_call (message, SECRETS_SERVICE_INTERFACE, "GetSecret"))
+		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+
+	return reply;
+}
+
 const gchar*
 gkd_secrets_session_get_caller (GkdSecretsSession *self)
 {
diff --git a/daemon/dbus/gkd-secrets-session.h b/daemon/dbus/gkd-secrets-session.h
index 346ce4d..4680107 100644
--- a/daemon/dbus/gkd-secrets-session.h
+++ b/daemon/dbus/gkd-secrets-session.h
@@ -37,11 +37,13 @@ typedef struct _GkdSecretsSessionClass GkdSecretsSessionClass;
 
 struct _GkdSecretsSessionClass {
 	GObjectClass parent_class;
-	DBusObjectPathVTable dbus_vtable;
 };
 
 GType               gkd_secrets_session_get_type               (void);
 
+DBusMessage*        gkd_secrets_session_dispatch               (GkdSecretsSession *self,
+                                                                DBusMessage *message);
+
 const gchar*        gkd_secrets_session_get_caller             (GkdSecretsSession *self);
 
 const gchar*        gkd_secrets_session_get_caller_executable  (GkdSecretsSession *self);
diff --git a/daemon/dbus/gkd-secrets-types.h b/daemon/dbus/gkd-secrets-types.h
index 6db292a..426500b 100644
--- a/daemon/dbus/gkd-secrets-types.h
+++ b/daemon/dbus/gkd-secrets-types.h
@@ -29,8 +29,8 @@
 #define SECRETS_SERVICE_PATH           "/org/freedesktop/secrets"
 #define SECRETS_SERVICE                "org.freedesktop.secrets"
 
+#define SECRETS_INTERFACE_PREFIX       "org.freedesktop.Secrets"
 #define SECRETS_COLLECTION_PREFIX      "/org/freedesktop/secrets/collection"
-
 #define SECRETS_SESSION_PREFIX         "/org/freedesktop/secrets/session"
 
 #define SECRETS_ERROR_ALREADY_EXISTS   "org.freedesktop.Secrets.Error.AlreadyExists"
diff --git a/pkcs11/pkcs11i.h b/pkcs11/pkcs11i.h
index d1018a3..05beda6 100644
--- a/pkcs11/pkcs11i.h
+++ b/pkcs11/pkcs11i.h
@@ -53,9 +53,7 @@
 typedef CK_ULONG CK_G_APPLICATION_ID;
 
 typedef struct CK_G_APPLICATION {
-	CK_UTF8CHAR applicationName;
 	CK_VOID_PTR applicationData;
-	CK_FLAGS flags;
 	CK_G_APPLICATION_ID applicationId;
 } CK_G_APPLICATION;
 



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