[gnome-keyring: 6/8] [gpg-agent] Finish up the GPG Agent.



commit ea21ca7f082f141998b2498fd7c14b982c25a460
Author: Stef Walter <stef memberwebs com>
Date:   Sun Jun 13 01:52:17 2010 +0000

    [gpg-agent] Finish up the GPG Agent.
    
     * Tested with GPG 1.4

 daemon/gkd-pkcs11.c                         |    1 +
 daemon/gpg-agent/Makefile.am                |    3 +-
 daemon/gpg-agent/gkd-gpg-agent-ops.c        |  255 ++++++++++++++++++++++++---
 daemon/gpg-agent/gkd-gpg-agent-standalone.c |   11 +-
 daemon/gpg-agent/gkd-gpg-agent.c            |   11 +-
 po/POTFILES.in                              |    1 +
 6 files changed, 242 insertions(+), 40 deletions(-)
---
diff --git a/daemon/gkd-pkcs11.c b/daemon/gkd-pkcs11.c
index 8790508..ff6a111 100644
--- a/daemon/gkd-pkcs11.c
+++ b/daemon/gkd-pkcs11.c
@@ -50,6 +50,7 @@ pkcs11_daemon_cleanup (gpointer unused)
 
 	gkd_ssh_agent_uninitialize ();
 	gkm_rpc_layer_uninitialize ();
+	gkd_gpg_agent_uninitialize ();
 	rv = (pkcs11_roof->C_Finalize) (NULL);
 
 	if (rv != CKR_OK)
diff --git a/daemon/gpg-agent/Makefile.am b/daemon/gpg-agent/Makefile.am
index 585b6d2..b53bba4 100644
--- a/daemon/gpg-agent/Makefile.am
+++ b/daemon/gpg-agent/Makefile.am
@@ -28,8 +28,9 @@ gkd_gpg_agent_standalone_SOURCES = \
 
 gkd_gpg_agent_standalone_LDADD = \
 	libgkd-gpg-agent.la \
+	$(top_builddir)/ui/libgku-prompt.la \
 	$(top_builddir)/gp11/libgp11.la \
-	$(top_builddir)/egg/libegg-secure.la \
+	$(top_builddir)/egg/libegg.la \
 	$(GOBJECT_LIBS) \
 	$(GTHREAD_LIBS) \
 	$(LIBGCRYPT_LIBS) \
diff --git a/daemon/gpg-agent/gkd-gpg-agent-ops.c b/daemon/gpg-agent/gkd-gpg-agent-ops.c
index e84941d..28371c7 100644
--- a/daemon/gpg-agent/gkd-gpg-agent-ops.c
+++ b/daemon/gpg-agent/gkd-gpg-agent-ops.c
@@ -29,6 +29,10 @@
 
 #include "pkcs11/pkcs11i.h"
 
+#include "ui/gku-prompt.h"
+
+#include <glib/gi18n.h>
+
 #include <ctype.h>
 #include <string.h>
 
@@ -47,6 +51,9 @@ keyid_to_field_attribute (const gchar *keyid, GP11Attributes *attrs)
 {
 	GString *fields = g_string_sized_new (128);
 
+	g_assert (keyid);
+	g_assert (attrs);
+
 	/* Remember that attribute names are sorted */
 
 	g_string_append (fields, "keyid");
@@ -63,6 +70,149 @@ keyid_to_field_attribute (const gchar *keyid, GP11Attributes *attrs)
 	g_string_free (fields, TRUE);
 }
 
+static gchar*
+calculate_label_for_key (const gchar *keyid, const gchar *description)
+{
+	gchar *label = NULL;
+	gchar **lines, **l;
+	const gchar *line;
+	gsize len;
+
+	/* Use the line that starts and ends with quotes */
+	if (description) {
+		lines = g_strsplit (description, "\n", -1);
+		for (l = lines, line = *l; !label && line; l++, line = *l) {
+			len = strlen (line);
+			if (len > 2 && line[0] == '\"' && line[len - 1] == '\"')
+				label = g_strndup (line + 1, len - 2);
+		}
+		g_strfreev (lines);
+	}
+
+	/* Use last eight characters of keyid */
+	if (!label && keyid) {
+		len = strlen (keyid);
+		if (len > 8)
+			label = g_strdup (keyid + (len - 8));
+		else
+			label = g_strdup (keyid);
+	}
+
+	if (!label)
+		label = g_strdup (_("Unknown"));
+
+	return label;
+}
+
+static GList*
+find_saved_items (GP11Session *session, GP11Attributes *attrs)
+{
+	GP11Attributes *template;
+	GError *error = NULL;
+	GP11Attribute *attr;
+	GP11Object *search;
+	GList *results;
+	gpointer data;
+	gsize n_data;
+
+	template = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_G_SEARCH,
+	                                 CKA_TOKEN, GP11_BOOLEAN, FALSE,
+	                                 GP11_INVALID);
+
+	attr = gp11_attributes_find (attrs, CKA_G_COLLECTION);
+	if (attr != NULL)
+		gp11_attributes_add (template, attr);
+
+	attr = gp11_attributes_find (attrs, CKA_G_FIELDS);
+	g_return_val_if_fail (attr != NULL, NULL);
+	gp11_attributes_add (template, attr);
+
+	search = gp11_session_create_object_full (session, template, NULL, &error);
+	gp11_attributes_unref (template);
+
+	if (search == NULL) {
+		g_warning ("couldn't perform search for gpg agent stored passphrases: %s",
+		           egg_error_message (error));
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	gp11_object_set_session (search, session);
+	data = gp11_object_get_data (search, CKA_G_MATCHED, &n_data, &error);
+	gp11_object_destroy (search, NULL);
+	g_object_unref (search);
+
+	if (data == NULL) {
+		g_warning ("couldn't retrieve list of gpg agent stored passphrases: %s",
+		           egg_error_message (error));
+		g_clear_error (&error);
+		return NULL;
+	}
+
+	results = gp11_objects_from_handle_array (gp11_session_get_slot (session),
+	                                          data, n_data / sizeof (CK_ULONG));
+
+	g_free (data);
+	return results;
+}
+
+static void
+do_save_password (GP11Session *session, const gchar *keyid, const gchar *description,
+                  const gchar *password, const gchar *collection_id)
+{
+	GP11Attributes *attrs;
+	gpointer identifier;
+	gsize n_identifier;
+	GList *previous;
+	GError *error = NULL;
+	GP11Object *item;
+	gchar *text;
+	gchar *label;
+
+	g_assert (collection_id);
+	g_assert (password);
+	g_assert (keyid);
+
+	/* Sending a password, needs to be secure */
+	attrs = gp11_attributes_new_full (egg_secure_realloc);
+
+	/* Build up basic set of attributes */
+	gp11_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+	gp11_attributes_add_ulong (attrs, CKA_CLASS, CKO_SECRET_KEY);
+	gp11_attributes_add_string (attrs, CKA_G_COLLECTION, collection_id);
+	keyid_to_field_attribute (keyid, attrs);
+
+	/* Find a previously stored object like this, and replace if so */
+	previous = find_saved_items (session, attrs);
+	if (previous) {
+		gp11_object_set_session (previous->data, session);
+		identifier = gp11_object_get_data (previous->data, CKA_ID, &n_identifier, NULL);
+		if (identifier != NULL)
+			gp11_attributes_add_data (attrs, CKA_ID, identifier, n_identifier);
+		g_free (identifier);
+		gp11_list_unref_free (previous);
+	}
+
+	text = calculate_label_for_key (keyid, description);
+	label = g_strdup_printf (_("PGP Key: %s"), text);
+	g_free (text);
+
+	/* Put in the remainder of the attributes */
+	gp11_attributes_add_string (attrs, CKA_VALUE, password);
+	gp11_attributes_add_string (attrs, CKA_LABEL, label);
+	g_free (label);
+
+	item = gp11_session_create_object_full (session, attrs, NULL, &error);
+	if (item == NULL) {
+		g_warning ("couldn't store gpg agent password: %s", egg_error_message (error));
+		g_clear_error (&error);
+	}
+
+	if (item != NULL)
+		g_object_unref (item);
+	gp11_attributes_unref (attrs);
+}
+
 static gboolean
 do_clear_password (GP11Session *session, const gchar *keyid)
 {
@@ -74,16 +224,9 @@ do_clear_password (GP11Session *session, const gchar *keyid)
 	                              GP11_INVALID);
 	keyid_to_field_attribute (keyid, attrs);
 
-	objects = gp11_session_find_objects_full (session, attrs, NULL, &error);
+	objects = find_saved_items (session, attrs);
 	gp11_attributes_unref (attrs);
 
-	if (error) {
-		g_warning ("couldn't search for gpg agent passwords to clear: %s",
-		           egg_error_message (error));
-		g_clear_error (&error);
-		return FALSE;
-	}
-
 	if (!objects)
 		return TRUE;
 
@@ -116,16 +259,9 @@ do_lookup_password (GP11Session *session, const gchar *keyid)
 	                              GP11_INVALID);
 	keyid_to_field_attribute (keyid, attrs);
 
-	objects = gp11_session_find_objects_full (session, attrs, NULL, &error);
+	objects = find_saved_items (session, attrs);
 	gp11_attributes_unref (attrs);
 
-	if (error) {
-		g_warning ("couldn't search for gpg agent passwords to clear: %s",
-		           egg_error_message (error));
-		g_clear_error (&error);
-		return NULL;
-	}
-
 	if (!objects)
 		return NULL;
 
@@ -148,23 +284,92 @@ do_lookup_password (GP11Session *session, const gchar *keyid)
 	return data;
 }
 
+static GkuPrompt*
+prepare_password_prompt (GP11Session *session, const gchar *errmsg, const gchar *prompt_text,
+                         const gchar *description, gboolean confirm)
+{
+	GkuPrompt *prompt;
+	GError *error = NULL;
+	GList *objects;
+
+	g_assert (GP11_IS_SESSION (session));
+
+	prompt = gku_prompt_new ();
+
+	gku_prompt_set_title (prompt, _("Enter Passphrase"));
+	gku_prompt_set_primary_text (prompt, prompt_text ? prompt_text : _("Enter Passphrase"));
+	gku_prompt_set_secondary_text (prompt, description);
+
+	gku_prompt_hide_widget (prompt, "name_area");
+	if (confirm)
+		gku_prompt_show_widget (prompt, "confirm_area");
+	else
+		gku_prompt_hide_widget (prompt, "confirm_area");
+	gku_prompt_show_widget (prompt, "password_area");
+
+	/* Check if the login keyring is usable */
+	objects = gp11_session_find_objects (session, &error,
+	                                     CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
+	                                     CKA_ID, 5, "login",
+	                                     CKA_G_LOCKED, GP11_BOOLEAN, FALSE,
+	                                     GP11_INVALID);
+
+	if (errmsg)
+		gku_prompt_set_warning (prompt, errmsg);
+
+	if (error) {
+		g_warning ("gpg agent couldn't lookup for login keyring: %s", egg_error_message (error));
+		g_clear_error (&error);
+	} else if (objects) {
+		gku_prompt_show_widget (prompt, "details_area");
+		gku_prompt_show_widget (prompt, "lock_area");
+		gku_prompt_hide_widget (prompt, "options_area");
+	}
+
+	gp11_list_unref_free (objects);
+
+	return prompt;
+}
+
+static GkuPrompt*
+on_prompt_attention (gpointer user_data)
+{
+	/* We passed the prompt as the argument */
+	return g_object_ref (user_data);
+}
+
 static gchar*
 do_get_password (GP11Session *session, const gchar *keyid, const gchar *errmsg,
-                 const gchar *prompt, const gchar *description, gboolean confirm)
+                 const gchar *prompt_text, const gchar *description, gboolean confirm)
 {
-	gchar *password;
+	gchar *password = NULL;
+	gint value = 0;
+	GkuPrompt *prompt;
+
+	g_assert (GP11_IS_SESSION (session));
+	g_assert (keyid);
 
 	password = do_lookup_password (session, keyid);
 	if (password != NULL)
 		return password;
 
-	/*
-	 * Need the following to continue:
-	 * - Ability to detect or use default keyring.
-	 * - Ability to prompt to unlock keyring.
-	 */
-	g_assert (FALSE && "Not yet impelmented");
-	return NULL;
+	/* Do we have the keyid? */
+	prompt = prepare_password_prompt (session, errmsg, prompt_text, description, confirm);
+
+	gku_prompt_request_attention_sync (NULL, on_prompt_attention,
+	                                   g_object_ref (prompt), g_object_unref);
+
+	if (gku_prompt_get_response (prompt) == GKU_RESPONSE_OK) {
+		password = gku_prompt_get_password (prompt, "password");
+		g_return_val_if_fail (password, NULL);
+
+		/* Save away the password appropriately */
+		gku_prompt_get_unlock_option (prompt, GKU_UNLOCK_AUTO, &value);
+		do_save_password (session, keyid, description, password, value == 0 ? "session" : "login");
+	}
+
+	g_object_unref (prompt);
+	return password;
 }
 
 /* ----------------------------------------------------------------------------------
diff --git a/daemon/gpg-agent/gkd-gpg-agent-standalone.c b/daemon/gpg-agent/gkd-gpg-agent-standalone.c
index ac24f85..3f8a75f 100644
--- a/daemon/gpg-agent/gkd-gpg-agent-standalone.c
+++ b/daemon/gpg-agent/gkd-gpg-agent-standalone.c
@@ -36,16 +36,7 @@
 #include <string.h>
 #include <unistd.h>
 
-G_LOCK_DEFINE_STATIC (memory_mutex);
-
-void egg_memory_lock (void)
-	{ G_LOCK (memory_mutex); }
-
-void egg_memory_unlock (void)
-	{ G_UNLOCK (memory_mutex); }
-
-void* egg_memory_fallback (void *p, size_t sz)
-	{ return g_realloc (p, sz); }
+EGG_SECURE_GLIB_DEFINITIONS();
 
 static gboolean
 accept_client (GIOChannel *channel, GIOCondition cond, gpointer unused)
diff --git a/daemon/gpg-agent/gkd-gpg-agent.c b/daemon/gpg-agent/gkd-gpg-agent.c
index e87438a..67d7cef 100644
--- a/daemon/gpg-agent/gkd-gpg-agent.c
+++ b/daemon/gpg-agent/gkd-gpg-agent.c
@@ -161,7 +161,7 @@ static gpointer
 run_client_thread (gpointer data)
 {
 	gint *socket = data;
-	GError *error;
+	GError *error = NULL;
 	GkdGpgAgentCall call;
 	gboolean ret;
 	gchar *line;
@@ -175,6 +175,9 @@ run_client_thread (gpointer data)
 	g_io_channel_set_close_on_unref (call.channel, FALSE);
 	call.module = g_object_ref (pkcs11_module);
 
+	/* Initial response on the connection */
+	gkd_gpg_agent_send_reply (&call, TRUE, "your orders please");
+
 	for (;;) {
 
 		/* Read in a line */
@@ -297,7 +300,7 @@ gkd_gpg_agent_accept (void)
 
 	addrlen = sizeof (addr);
 	new_fd = accept (socket_fd, (struct sockaddr*) &addr, &addrlen);
-	if (socket_fd < 0) {
+	if (new_fd < 0) {
 		g_warning ("cannot accept GPG agent connection: %s", strerror (errno));
 		return;
 	}
@@ -408,7 +411,7 @@ gkd_gpg_agent_initialize_with_module (GP11Module *module)
 		if (g_ascii_strcasecmp ("Secret Store", info->slot_description) == 0) {
 
 			/* Try and open a session */
-			session = gp11_slot_open_session (l->data, CKF_SERIAL_SESSION, &error);
+			session = gp11_slot_open_session (l->data, CKF_RW_SESSION | CKF_SERIAL_SESSION, &error);
 			if (!session) {
 				g_warning ("couldn't create pkcs#11 session: %s", error->message);
 				g_clear_error (&error);
@@ -473,7 +476,7 @@ gkd_gpg_agent_startup (const gchar *prefix)
 	 * Need to figure out a way to get the PID in there.
 	 */
 	agent_info = g_strdup_printf ("%s:0:1", socket_path);
-	g_setenv ("SSH_AUTH_SOCK", agent_info, TRUE);
+	g_setenv ("GPG_AGENT_INFO", agent_info, TRUE);
 	g_free (agent_info);
 
 	socket_fd = sock;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8e1567c..971184b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,6 +8,7 @@ daemon/gnome-keyring-pkcs11.desktop.in.in
 daemon/gnome-keyring-secrets.desktop.in.in
 daemon/gnome-keyring-ssh.desktop.in.in
 daemon/gnome-keyring-gpg.desktop.in.in
+daemon/gpg-agent/gkd-gpg-agent-ops.c
 daemon/login/gkd-login.c
 daemon/org.gnome.keyring.service.in
 egg/egg-asn1.c



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