[gnome-keyring/dbus-api] [dbus] Implement Service.CreateCollection()



commit 41e7dd756876fd3a33866703ad4739a7eac45fea
Author: Stef Walter <stef memberwebs com>
Date:   Thu Nov 12 04:00:32 2009 +0000

    [dbus] Implement Service.CreateCollection()
    
    Implement creating of collections, including prompting for
    the password.

 daemon/data/introspect-service.xml |    5 +-
 daemon/dbus/Makefile.am            |    1 +
 daemon/dbus/gkd-secret-create.c    |  267 ++++++++++++++++++++++++++++++++++++
 daemon/dbus/gkd-secret-create.h    |   51 +++++++
 daemon/dbus/gkd-secret-prompt.c    |   24 ++--
 daemon/dbus/gkd-secret-prompt.h    |    3 -
 daemon/dbus/gkd-secret-service.c   |   58 ++++++++-
 daemon/dbus/gkd-secret-unlock.c    |   18 ++-
 8 files changed, 403 insertions(+), 24 deletions(-)
---
diff --git a/daemon/data/introspect-service.xml b/daemon/data/introspect-service.xml
index 31f92cf..056175c 100644
--- a/daemon/data/introspect-service.xml
+++ b/daemon/data/introspect-service.xml
@@ -35,8 +35,9 @@
 		</method>
 
 		<method name="CreateCollection">
-			<arg name="label" type="s" direction="in"/>
-			<arg name="private" type="b" direction="in"/>
+			<arg name="props" type="a{sv}" direction="in"/>
+			<arg name="collection" type="o" direction="out"/>
+			<arg name="prompt" type="o" direction="out"/>
 		</method>
 
 		<method name="LockService">
diff --git a/daemon/dbus/Makefile.am b/daemon/dbus/Makefile.am
index ab99cad..f6116e7 100644
--- a/daemon/dbus/Makefile.am
+++ b/daemon/dbus/Makefile.am
@@ -18,6 +18,7 @@ libgkr_dbus_la_SOURCES = \
 	gkd-dbus-service.c \
 	gkd-dbus-session.c \
 	gkd-dbus-util.c gkd-dbus-util.h \
+	gkd-secret-create.c gkd-secret-create.h \
 	gkd-secret-objects.c gkd-secret-objects.h \
 	gkd-secret-property.c gkd-secret-property.h \
 	gkd-secret-prompt.c gkd-secret-prompt.h \
diff --git a/daemon/dbus/gkd-secret-create.c b/daemon/dbus/gkd-secret-create.c
new file mode 100644
index 0000000..f2cde76
--- /dev/null
+++ b/daemon/dbus/gkd-secret-create.c
@@ -0,0 +1,267 @@
+/*
+ * 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-create.h"
+#include "gkd-secret-service.h"
+#include "gkd-secret-prompt.h"
+#include "gkd-secret-types.h"
+#include "gkd-secret-util.h"
+
+#include "egg/egg-secure-memory.h"
+
+#include "pkcs11/pkcs11i.h"
+
+#include <glib/gi18n.h>
+
+#include <gp11/gp11.h>
+
+#include <string.h>
+
+enum {
+	PROP_0,
+	PROP_PKCS11_ATTRIBUTES
+};
+
+struct _GkdSecretCreate {
+	GkdSecretPrompt parent;
+	GP11Attributes *pkcs11_attrs;
+	gchar *result_path;
+};
+
+G_DEFINE_TYPE (GkdSecretCreate, gkd_secret_create, GKD_SECRET_TYPE_PROMPT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+prepare_create_prompt (GkdSecretCreate *self)
+{
+	GkdPrompt *prompt;
+	gchar *label;
+	gchar *text;
+
+	g_assert (GKD_SECRET_IS_CREATE (self));
+	g_assert (self->pkcs11_attrs);
+
+	prompt = GKD_PROMPT (self);
+
+	if (!gp11_attributes_find_string (self->pkcs11_attrs, CKA_LABEL, &label))
+		label = g_strdup (_("Unnamed"));
+
+	gkd_prompt_reset (prompt);
+
+	gkd_prompt_set_title (prompt, _("New Keyring Password"));
+	gkd_prompt_set_primary_text (prompt, _("Choose password for new keyring"));
+
+	text = g_markup_printf_escaped (_("An application wants to create a new keyring called '%s'. "
+	                                  "Choose the password you want to use for it."), label);
+	gkd_prompt_set_secondary_text (prompt, text);
+	g_free (text);
+
+	gkd_prompt_hide_widget (prompt, "name_area");
+	gkd_prompt_hide_widget (prompt, "confirm_area");
+	gkd_prompt_hide_widget (prompt, "details_area");
+
+	g_free (label);
+}
+
+static gboolean
+create_collection (GkdSecretCreate *self, const gchar *password)
+{
+	GError *error = NULL;
+	GP11Session *session;
+	GP11Object *collection;
+	GP11Object *cred;
+	gsize n_password;
+	gboolean token;
+
+	g_assert (GKD_SECRET_IS_CREATE (self));
+	g_return_val_if_fail (self->pkcs11_attrs, FALSE);
+	g_return_val_if_fail (!self->result_path, FALSE);
+
+	if (gp11_attributes_find_boolean (self->pkcs11_attrs, CKA_TOKEN, &token))
+		token = FALSE;
+	n_password = password ? strlen (password) : 0;
+
+	session =  gkd_secret_prompt_get_pkcs11_session (GKD_SECRET_PROMPT (self));
+	g_return_val_if_fail (session, FALSE);
+
+	cred = gp11_session_create_object (session, &error,
+	                                   CKA_CLASS, GP11_ULONG, CKO_G_CREDENTIAL,
+	                                   CKA_GNOME_TRANSIENT, GP11_BOOLEAN, TRUE,
+	                                   CKA_TOKEN, GP11_BOOLEAN, token,
+	                                   CKA_VALUE, n_password, password,
+	                                   GP11_INVALID);
+
+	if (!cred) {
+		g_warning ("couldn't create credential for new collection: %s", error->message);
+		g_clear_error (&error);
+		return FALSE;
+	}
+
+	/* Setup remainder of attributes on collection */
+	gp11_attributes_add_ulong (self->pkcs11_attrs, CKA_G_CREDENTIAL,
+	                           gp11_object_get_handle (cred));
+	g_object_unref (cred);
+
+	collection = gp11_session_create_object_full (session, self->pkcs11_attrs, NULL, &error);
+	if (!collection) {
+		g_warning ("couldn't create collection: %s", error->message);
+		g_clear_error (&error);
+		return FALSE;
+	}
+
+	gp11_object_set_session (collection, session);
+	self->result_path = gkd_secret_util_path_for_collection (collection);
+	g_object_unref (collection);
+
+	return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gkd_secret_create_prompt_ready (GkdSecretPrompt *base)
+{
+	GkdSecretCreate *self = GKD_SECRET_CREATE (base);
+	GkdPrompt *prompt = GKD_PROMPT (self);
+	gchar *password;
+
+	if (!gkd_prompt_has_response (prompt)) {
+		prepare_create_prompt (self);
+		return;
+	}
+
+	/* Already prompted, create collection */
+	g_return_if_fail (gkd_prompt_get_response (prompt) == GKD_RESPONSE_OK);
+	password = gkd_prompt_get_password (prompt, "password");
+
+	if (create_collection (self, password))
+		gkd_secret_prompt_complete (GKD_SECRET_PROMPT (self));
+	else
+		gkd_secret_prompt_dismiss (GKD_SECRET_PROMPT (self));
+
+	egg_secure_strfree (password);
+}
+
+static void
+gkd_secret_create_encode_result (GkdSecretPrompt *base, DBusMessageIter *iter)
+{
+	GkdSecretCreate *self = GKD_SECRET_CREATE (base);
+	DBusMessageIter variant;
+	const gchar *path;
+
+	dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "o", &variant);
+	path = self->result_path ? self->result_path : "/";
+	dbus_message_iter_append_basic (&variant, DBUS_TYPE_OBJECT_PATH, &path);
+	dbus_message_iter_close_container (iter, &variant);
+}
+
+static void
+gkd_secret_create_init (GkdSecretCreate *self)
+{
+
+}
+
+static void
+gkd_secret_create_finalize (GObject *obj)
+{
+	GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
+
+	if (self->pkcs11_attrs)
+		gp11_attributes_unref (self->pkcs11_attrs);
+	self->pkcs11_attrs = NULL;
+
+	G_OBJECT_CLASS (gkd_secret_create_parent_class)->finalize (obj);
+}
+
+static void
+gkd_secret_create_set_property (GObject *obj, guint prop_id, const GValue *value,
+                                GParamSpec *pspec)
+{
+	GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
+
+	switch (prop_id) {
+	case PROP_PKCS11_ATTRIBUTES:
+		g_return_if_fail (!self->pkcs11_attrs);
+		self->pkcs11_attrs = g_value_dup_boxed (value);
+		gp11_attributes_add_ulong (self->pkcs11_attrs, CKA_CLASS, CKO_G_COLLECTION);
+		g_return_if_fail (self->pkcs11_attrs);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkd_secret_create_get_property (GObject *obj, guint prop_id, GValue *value,
+                                GParamSpec *pspec)
+{
+	GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
+
+	switch (prop_id) {
+	case PROP_PKCS11_ATTRIBUTES:
+		g_value_set_boxed (value, self->pkcs11_attrs);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gkd_secret_create_class_init (GkdSecretCreateClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GkdSecretPromptClass *prompt_class = GKD_SECRET_PROMPT_CLASS (klass);
+
+	gobject_class->finalize = gkd_secret_create_finalize;
+	gobject_class->get_property = gkd_secret_create_get_property;
+	gobject_class->set_property = gkd_secret_create_set_property;
+
+	prompt_class->prompt_ready = gkd_secret_create_prompt_ready;
+	prompt_class->encode_result = gkd_secret_create_encode_result;
+
+	g_object_class_install_property (gobject_class, PROP_PKCS11_ATTRIBUTES,
+		g_param_spec_boxed ("pkcs11-attributes", "PKCS11 Attributes", "PKCS11 Attributes",
+		                     GP11_TYPE_ATTRIBUTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GkdSecretCreate*
+gkd_secret_create_new (GkdSecretService *service, const gchar *caller,
+                       GP11Attributes *attrs)
+{
+	return g_object_new (GKD_SECRET_TYPE_CREATE,
+	                     "service", service,
+	                     "caller", caller,
+	                     "pkcs11-attributes", attrs,
+	                     NULL);
+}
diff --git a/daemon/dbus/gkd-secret-create.h b/daemon/dbus/gkd-secret-create.h
new file mode 100644
index 0000000..050deff
--- /dev/null
+++ b/daemon/dbus/gkd-secret-create.h
@@ -0,0 +1,51 @@
+/*
+ * 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_CREATE_H__
+#define __GKD_SECRET_CREATE_H__
+
+#include <glib-object.h>
+
+#include "gkd-secret-prompt.h"
+#include "gkd-secret-types.h"
+
+#include "gp11/gp11.h"
+
+#define GKD_SECRET_TYPE_CREATE               (gkd_secret_create_get_type ())
+#define GKD_SECRET_CREATE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKD_SECRET_TYPE_CREATE, GkdSecretCreate))
+#define GKD_SECRET_CREATE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKD_SECRET_TYPE_CREATE, GkdSecretCreateClass))
+#define GKD_SECRET_IS_CREATE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKD_SECRET_TYPE_CREATE))
+#define GKD_SECRET_IS_CREATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKD_SECRET_TYPE_CREATE))
+#define GKD_SECRET_CREATE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKD_SECRET_TYPE_CREATE, GkdSecretCreateClass))
+
+typedef struct _GkdSecretCreateClass GkdSecretCreateClass;
+
+struct _GkdSecretCreateClass {
+	GkdSecretPromptClass parent_class;
+};
+
+GType               gkd_secret_create_get_type                (void);
+
+GkdSecretCreate*    gkd_secret_create_new                     (GkdSecretService *service,
+                                                               const gchar *caller,
+                                                               GP11Attributes *attrs);
+
+#endif /* __GKD_SECRET_CREATE_H__ */
diff --git a/daemon/dbus/gkd-secret-prompt.c b/daemon/dbus/gkd-secret-prompt.c
index aab53af..2ad6c0e 100644
--- a/daemon/dbus/gkd-secret-prompt.c
+++ b/daemon/dbus/gkd-secret-prompt.c
@@ -358,6 +358,15 @@ gkd_secret_prompt_get_object_path (GkdSecretPrompt *self)
 	return self->pv->object_path;
 }
 
+GP11Session*
+gkd_secret_prompt_get_pkcs11_session (GkdSecretPrompt *self)
+{
+	g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
+	g_return_val_if_fail (self->pv->service, NULL);
+
+	return gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
+}
+
 void
 gkd_secret_prompt_complete (GkdSecretPrompt *self)
 {
@@ -375,18 +384,3 @@ gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
 	self->pv->completed = TRUE;
 	emit_completed (self, TRUE);
 }
-
-GP11Object*
-gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
-{
-	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);
-
-	session = gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
-	g_return_val_if_fail (session, NULL);
-
-	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 de8c069..ded1ae4 100644
--- a/daemon/dbus/gkd-secret-prompt.h
+++ b/daemon/dbus/gkd-secret-prompt.h
@@ -66,9 +66,6 @@ const gchar*        gkd_secret_prompt_get_object_path         (GkdSecretPrompt *
 
 GP11Session*        gkd_secret_prompt_get_pkcs11_session      (GkdSecretPrompt *self);
 
-GP11Object*         gkd_secret_prompt_lookup_collection       (GkdSecretPrompt *self,
-                                                               const gchar *objpath);
-
 void                gkd_secret_prompt_complete                (GkdSecretPrompt *self);
 
 void                gkd_secret_prompt_dismiss                 (GkdSecretPrompt *self);
diff --git a/daemon/dbus/gkd-secret-service.c b/daemon/dbus/gkd-secret-service.c
index 8cd42a8..f1e81ce 100644
--- a/daemon/dbus/gkd-secret-service.c
+++ b/daemon/dbus/gkd-secret-service.c
@@ -22,8 +22,10 @@
 #include "config.h"
 
 #include "gkd-dbus-util.h"
+#include "gkd-secret-create.h"
 #include "gkd-secret-objects.h"
 #include "gkd-secret-prompt.h"
+#include "gkd-secret-property.h"
 #include "gkd-secret-service.h"
 #include "gkd-secret-session.h"
 #include "gkd-secret-types.h"
@@ -370,6 +372,60 @@ service_method_open_session (GkdSecretService *self, DBusMessage *message)
 }
 
 static DBusMessage*
+service_method_create_collection (GkdSecretService *self, DBusMessage *message)
+{
+	DBusMessageIter iter, array;
+	GP11Attributes *attrs, *all;
+	GP11Attribute *label;
+	GkdSecretCreate *create;
+	ServiceClient *client;
+	DBusMessage *reply;
+	const gchar *path;
+	const char *caller;
+	const gchar *coll;
+
+	/* Parse the incoming message */
+	if (!dbus_message_has_signature (message, "a{sv}"))
+		return NULL;
+	if (!dbus_message_iter_init (message, &iter))
+		g_return_val_if_reached (NULL);
+	all = gp11_attributes_new ();
+	dbus_message_iter_recurse (&iter, &array);
+	if (!gkd_secret_property_parse_all (&array, all)) {
+		gp11_attributes_unref (all);
+		return dbus_message_new_error_printf (message, DBUS_ERROR_INVALID_ARGS,
+		                                      "Invalid properties");
+	}
+
+	/* The only thing we actually use from the properties right now is the label */
+	label = gp11_attributes_find (all, CKA_LABEL);
+	attrs = gp11_attributes_new ();
+	if (label != NULL)
+		gp11_attributes_add (attrs, label);
+	gp11_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+	gp11_attributes_unref (all);
+
+	/* Create the prompt object, for the password */
+	caller = dbus_message_get_sender (message);
+	create = gkd_secret_create_new (self, caller, attrs);
+	gp11_attributes_unref (attrs);
+
+	path = gkd_secret_prompt_get_object_path (GKD_SECRET_PROMPT (create));
+	client = g_hash_table_lookup (self->clients, caller);
+	g_return_val_if_fail (client, NULL);
+	g_hash_table_replace (client->prompts, (gpointer)path, create);
+
+	coll = "/";
+	reply = dbus_message_new_method_return (message);
+	dbus_message_append_args (reply,
+	                          DBUS_TYPE_OBJECT_PATH, &coll,
+	                          DBUS_TYPE_OBJECT_PATH, &path,
+	                          DBUS_TYPE_INVALID);
+
+	return reply;
+}
+
+static DBusMessage*
 service_method_unlock (GkdSecretService *self, DBusMessage *message)
 {
 	GkdSecretUnlock *unlock;
@@ -430,7 +486,7 @@ service_message_handler (GkdSecretService *self, DBusMessage *message)
 
 	/* org.freedesktop.Secrets.Service.CreateCollection() */
 	if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "CreateCollection"))
-		g_return_val_if_reached (NULL); /* TODO: Need to implement */
+		reply = service_method_create_collection (self, message);
 
 	/* org.freedesktop.Secrets.Service.LockService() */
 	if (dbus_message_is_method_call (message, SECRET_SERVICE_INTERFACE, "LockService"))
diff --git a/daemon/dbus/gkd-secret-unlock.c b/daemon/dbus/gkd-secret-unlock.c
index c416587..b62285a 100644
--- a/daemon/dbus/gkd-secret-unlock.c
+++ b/daemon/dbus/gkd-secret-unlock.c
@@ -25,6 +25,7 @@
 #include "gkd-secret-prompt.h"
 #include "gkd-secret-types.h"
 #include "gkd-secret-unlock.h"
+#include "gkd-secret-util.h"
 
 #include "egg/egg-secure-memory.h"
 
@@ -168,6 +169,17 @@ authenticate_collection (GkdSecretUnlock *self, GP11Object *coll, gboolean *lock
 	}
 }
 
+static GP11Object*
+lookup_collection (GkdSecretUnlock *self, const gchar *path)
+{
+	GP11Session *session;
+
+	session = gkd_secret_prompt_get_pkcs11_session (GKD_SECRET_PROMPT (self));
+	g_return_val_if_fail (session, NULL);
+
+	return gkd_secret_util_path_to_collection (session, path);
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT
  */
@@ -182,7 +194,7 @@ gkd_secret_unlock_prompt_ready (GkdSecretPrompt *base)
 
 	/* Already prompted for an item */
 	if (self->current) {
-		coll = gkd_secret_prompt_lookup_collection (base, self->current);
+		coll = lookup_collection (self, self->current);
 
 		/* If the object or collection is gone, no need to unlock */
 		if (coll == NULL) {
@@ -221,7 +233,7 @@ gkd_secret_unlock_prompt_ready (GkdSecretPrompt *base)
 		}
 
 		/* Find the collection, make sure it's still around */
-		coll = gkd_secret_prompt_lookup_collection (base, objpath);
+		coll = lookup_collection (self, objpath);
 		if (coll == NULL) {
 			g_free (objpath);
 			continue;
@@ -327,7 +339,7 @@ gkd_secret_unlock_queue (GkdSecretUnlock *self, const gchar *objpath)
 	g_return_if_fail (GKD_SECRET_IS_UNLOCK (self));
 	g_return_if_fail (objpath);
 
-	coll = gkd_secret_prompt_lookup_collection (GKD_SECRET_PROMPT (self), objpath);
+	coll = lookup_collection (self, objpath);
 	if (coll == NULL)
 		return;
 



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