gnome-keyring r1369 - in trunk: . common daemon library



Author: nnielsen
Date: Sun Nov  9 23:02:22 2008
New Revision: 1369
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1369&view=rev

Log:
	* configure.in:
	* common/gkr-daemon-util.c:
	* common/gkr-daemon-util.h:
	* daemon/Makefile.am:
	* daemon/gkr-daemon-dbus.c:
	* daemon/gkr-daemon-ops.c:
	* daemon/gkr-daemon.c:
	* daemon/gkr-daemon.h:
	* daemon/gnome-keyring-daemon.desktop.in:
	* library/Makefile.am:
	* library/gnome-keyring-private.h:
	* library/gnome-keyring-socket.c:
	* library/gnome-keyring-utils.c:
	* library/gnome-keyring.c: Add --start option to daemon which allows 
	initialization of a running daemon or start one if none found. 
	This reworks the startup interactions with gnome-session.

Added:
   trunk/daemon/gnome-keyring-daemon.desktop.in
   trunk/library/gnome-keyring-socket.c
Modified:
   trunk/ChangeLog
   trunk/common/gkr-daemon-util.c
   trunk/common/gkr-daemon-util.h
   trunk/configure.in
   trunk/daemon/   (props changed)
   trunk/daemon/Makefile.am
   trunk/daemon/gkr-daemon-dbus.c
   trunk/daemon/gkr-daemon-ops.c
   trunk/daemon/gkr-daemon.c
   trunk/daemon/gkr-daemon.h
   trunk/library/Makefile.am
   trunk/library/gnome-keyring-private.h
   trunk/library/gnome-keyring-utils.c
   trunk/library/gnome-keyring.c

Modified: trunk/common/gkr-daemon-util.c
==============================================================================
--- trunk/common/gkr-daemon-util.c	(original)
+++ trunk/common/gkr-daemon-util.c	Sun Nov  9 23:02:22 2008
@@ -335,6 +335,18 @@
 	g_array_append_val (published_environ, env);
 }
 
+void 
+gkr_daemon_util_push_environment_full (const gchar *var)
+{
+	gchar *env;
+	
+	g_return_if_fail (strchr (var, '=') != NULL);
+	init_environment ();
+	
+	env = g_strdup (var);
+	g_array_append_val (published_environ, env);
+}
+
 const gchar**
 gkr_daemon_util_get_environment (void)
 {

Modified: trunk/common/gkr-daemon-util.h
==============================================================================
--- trunk/common/gkr-daemon-util.h	(original)
+++ trunk/common/gkr-daemon-util.h	Sun Nov  9 23:02:22 2008
@@ -35,6 +35,8 @@
 
 void            gkr_daemon_util_push_environment        (const gchar *name, const gchar *value);
 
+void            gkr_daemon_util_push_environment_full   (const gchar *env);
+
 const gchar**   gkr_daemon_util_get_environment         (void);
 
 #define GKR_TYPE_DAEMON_CLIENT             (gkr_daemon_client_get_type ())

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Sun Nov  9 23:02:22 2008
@@ -484,11 +484,15 @@
 AC_SUBST(LIBRARY_CFLAGS)
 AC_SUBST(LIBRARY_LIBS)
 
+BINDIR="$bindir"
+AC_SUBST(BINDIR)
+
 AC_OUTPUT([
 Makefile
 common/Makefile
 common/tests/Makefile
 daemon/Makefile
+daemon/gnome-keyring-daemon.desktop
 daemon/data/Makefile
 daemon/keyrings/Makefile
 daemon/keyrings/tests/Makefile

Modified: trunk/daemon/Makefile.am
==============================================================================
--- trunk/daemon/Makefile.am	(original)
+++ trunk/daemon/Makefile.am	Sun Nov  9 23:02:22 2008
@@ -51,8 +51,13 @@
 	$(GOBJECT_LIBS) \
 	$(GLIB_LIBS)
 
-EXTRA_DIST = org.gnome.keyring.service.in
-CLEANFILES = org.gnome.keyring.service
+EXTRA_DIST = \
+	org.gnome.keyring.service.in \
+	gnome-keyring-daemon.desktop.in
+
+CLEANFILES = \
+	org.gnome.keyring.service \
+	gnome-keyring-daemon.desktop
 
 servicedir       = $(DBUS_SERVICES_DIR)
 service_in_files = org.gnome.keyring.service.in
@@ -61,3 +66,5 @@
 $(service_DATA): $(service_in_files) Makefile
 	@sed -e "s|\ BINDIR\@|$(bindir)|" $< > $@
 
+desktopdir       = $(datadir)/gnome/autostart
+desktop_DATA = gnome-keyring-daemon.desktop

Modified: trunk/daemon/gkr-daemon-dbus.c
==============================================================================
--- trunk/daemon/gkr-daemon-dbus.c	(original)
+++ trunk/daemon/gkr-daemon-dbus.c	Sun Nov  9 23:02:22 2008
@@ -26,14 +26,21 @@
 
 #include "common/gkr-cleanup.h"
 #include "common/gkr-dbus.h"
+#include "common/gkr-daemon-util.h"
 
 #include "library/gnome-keyring.h"
 #include "library/gnome-keyring-private.h"
 
 #include <dbus/dbus.h>
 
+#include <string.h>
+
+/* Rule to send to DBus bus for which signals we're interested in */
+#define SIGNAL_MATCH_RULE "type='signal',interface='org.gnome.SessionManager'"
+
 static DBusConnection *dbus_conn = NULL;
 static const char* socket_path = NULL;
+static gboolean dbus_initialized = FALSE;
 
 static DBusHandlerResult 
 message_handler_cb (DBusConnection *conn, DBusMessage *message, void *user_data)
@@ -63,17 +70,29 @@
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+static DBusHandlerResult
+signal_filter (DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+	/* Quit the daemon when the session is over */
+	if (dbus_message_is_signal (msg, "org.gnome.SessionManager", "SessionOver")) {
+		gkr_daemon_quit ();
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+	
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 static DBusObjectPathVTable object_vtable  = {
 	NULL,
 	message_handler_cb,
 	NULL, 
 };
 
-
 static void 
 daemon_dbus_cleanup (gpointer unused)
 {
 	if (dbus_conn) {
+		dbus_bus_remove_match (dbus_conn, SIGNAL_MATCH_RULE, NULL);
 		dbus_connection_unregister_object_path (dbus_conn, GNOME_KEYRING_DAEMON_PATH);
 		gkr_dbus_disconnect_from_mainloop (dbus_conn, NULL);
 		dbus_connection_unref (dbus_conn);
@@ -81,16 +100,138 @@
 	}
 }
 
+/* 
+ * Here we register our environment variables with a gnome-session style
+ * session manager via DBus. 
+ */
+static void 
+register_environment_in_session (void)
+{
+	DBusMessageIter args;
+	DBusMessage *msg;
+	DBusMessage *reply;
+	DBusError derr = { 0 };
+	const gchar **envp;
+	const gchar *value;
+	gchar *name;
+	
+	g_return_if_fail (dbus_conn);
+	
+	/* 
+	 * The list of all environment variables registered by
+	 * various components in the daemon.
+	 */ 
+	envp = gkr_daemon_util_get_environment ();
+	
+	for (; *envp; ++envp) {
+		
+		/* Find the value part of the environment variable */
+		value = strchr (*envp, '=');
+		if (!value)
+			continue;
+		
+		name = g_strndup (*envp, value - *envp);
+		++value;
+		
+		msg = dbus_message_new_method_call ("org.gnome.SessionManager",
+		                                    "/org/gnome/SessionManager",
+		                                    "org.gnome.SessionManager",
+		                                    "Setenv");
+		g_return_if_fail (msg);
+		
+		dbus_message_iter_init_append (msg, &args); 
+		if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &name) ||
+		    !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &value))
+			g_return_if_reached ();
+		
+		g_free (name);
+		value = name = NULL;
+		
+		/* Send message and get a handle for a reply */
+		reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
+		dbus_message_unref (msg);
+		
+		if (!reply) {
+			g_warning ("couldn't set environment variable in session: %s", derr.message);
+			return;
+		}
+		
+		dbus_message_unref (reply);
+	}
+}
+
+/* 
+ * Here we register our desktop autostart id gnome-session style
+ * session manager via DBus. 
+ */
+static void 
+register_daemon_in_session (void)
+{
+	DBusMessageIter args;
+	DBusMessage *msg;
+	DBusMessage *reply;
+	DBusError derr = { 0 };
+	const gchar *app_id = "gnome-keyring-daemon";
+	const gchar *client_id;
+	
+	client_id = g_getenv ("DESKTOP_AUTOSTART_ID");
+	if(!client_id)
+		return;
+	
+	g_return_if_fail (dbus_conn);
+	
+	msg = dbus_message_new_method_call ("org.gnome.SessionManager",
+	                                    "/org/gnome/SessionManager",
+	                                    "org.gnome.SessionManager",
+	                                    "RegisterClient");
+	g_return_if_fail (msg);
+	
+	dbus_message_iter_init_append (msg, &args); 
+	if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &app_id) ||
+	    !dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &client_id))
+		g_return_if_reached ();
+	
+	/* Send message and get a handle for a reply */
+	reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
+	dbus_message_unref (msg);
+	
+	if (!reply) {
+		g_warning ("couldn't register in session: %s", derr.message);
+		return;
+	}
+	
+	dbus_message_unref (reply);
+	
+	/* 
+	 * Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
+	 * use the same client id. 
+	 */
+	g_unsetenv ("DESKTOP_AUTOSTART_ID");
+}
+
 void 
-gkr_daemon_dbus_setup (GMainLoop *loop)
+gkr_daemon_dbus_setup (void)
 {
 	dbus_uint32_t res = 0;
 	DBusError derr = { 0 };
+	const gchar *env;
+	
+	/* 
+	 * We may be launched before the DBUS session, (ie: via PAM) 
+	 * and DBus tries to launch itself somehow, so double check 
+	 * that it has really started.
+	 */ 
+	env = getenv ("DBUS_SESSION_BUS_ADDRESS");
+	if (!env || !env[0])
+		return;
+	
+	if (dbus_initialized)
+		return;
 	
 #ifdef WITH_TESTS
 	/* If running as a test, don't do DBUS stuff */
-	const gchar *env = g_getenv ("GNOME_KEYRING_TEST_PATH");
-	if (env && *env) 
+	env = g_getenv ("GNOME_KEYRING_TEST_PATH");
+	if (env && env[0])
 		return;
 #endif
 
@@ -114,7 +255,7 @@
 
 	/* Try and grab our name */
 	res = dbus_bus_request_name (dbus_conn, GNOME_KEYRING_DAEMON_SERVICE,
-					     DBUS_NAME_FLAG_DO_NOT_QUEUE, &derr);
+				     DBUS_NAME_FLAG_DO_NOT_QUEUE, &derr);
 	if (dbus_error_is_set (&derr)) { 
 		g_warning ("couldn't request name on session bus: %s", derr.message);
 		dbus_error_free (&derr);
@@ -144,4 +285,13 @@
 		g_warning ("couldn't register dbus object path");
 		return;
 	}
+	
+	/* Listen in to signals that tell us when the session will be over */
+	dbus_bus_add_match (dbus_conn, SIGNAL_MATCH_RULE, NULL);
+	dbus_connection_add_filter (dbus_conn, signal_filter, NULL, NULL);
+
+	dbus_initialized = TRUE;
+	
+	register_environment_in_session ();
+	register_daemon_in_session ();
 }

Modified: trunk/daemon/gkr-daemon-ops.c
==============================================================================
--- trunk/daemon/gkr-daemon-ops.c	(original)
+++ trunk/daemon/gkr-daemon-ops.c	Sun Nov  9 23:02:22 2008
@@ -1689,6 +1689,7 @@
 	const gchar **daemonenv;
 	gchar **environment, **e;
 	gchar *x;
+	gint i;
 
 	if (!gkr_proto_decode_prepare_environment (packet, &environment))
 		return FALSE;
@@ -1699,24 +1700,25 @@
 		if (x) {
 			*(x++) = 0;
 			
-			/* We're only interested in these guys */
-			if (g_str_equal (*e, "DISPLAY")) 
-				g_setenv ("DISPLAY", x, FALSE);
-			else if (g_str_equal (*e, "DBUS_SESSION_BUS_ADDRESS"))
-				g_setenv ("DBUS_SESSION_BUS_ADDRESS", x, FALSE);
-			else if (g_str_equal (*e, "XAUTHORITY"))
-				g_setenv ("XAUTHORITY", x, FALSE);
-			else if (g_str_equal (*e, "XDG_SESSION_COOKIE"))
-				g_setenv ("XDG_SESSION_COOKIE", x, FALSE);	
-			else if (g_str_equal (*e, "LANG"))
-				g_setenv ("LANG", x, FALSE);
+			/* We're only interested in these environment variables */
+			for (i = 0; GNOME_KEYRING_IN_ENVIRONMENT[i] != NULL; ++i) {
+				if (g_str_equal (*e, GNOME_KEYRING_IN_ENVIRONMENT[i]))
+				{
+					g_setenv (*e, x, FALSE);
+					break;
+				}
+			}
 		}
 	}
 	
 	g_strfreev (environment);
+	
+	/* We may have received DBUS environment variable so try and setup DBUS */
+	gkr_daemon_dbus_setup ();
 
 	gkr_buffer_add_uint32 (result, GNOME_KEYRING_RESULT_OK);
 
+	/* These are the environment variables that the daemon setup */
 	daemonenv = gkr_daemon_util_get_environment ();
 	g_return_val_if_fail (daemonenv, FALSE);
 	

Modified: trunk/daemon/gkr-daemon.c
==============================================================================
--- trunk/daemon/gkr-daemon.c	(original)
+++ trunk/daemon/gkr-daemon.c	Sun Nov  9 23:02:22 2008
@@ -29,6 +29,7 @@
 #include "common/gkr-crypto.h"
 #include "common/gkr-daemon-util.h"
 #include "common/gkr-secure-memory.h"
+#include "common/gkr-unix-credentials.h"
 #include "common/gkr-unix-signal.h"
 
 #include "keyrings/gkr-keyring-login.h"
@@ -97,6 +98,7 @@
 static gboolean run_foreground = FALSE;
 static gboolean run_daemonized = FALSE;
 static gboolean unlock_with_login = FALSE;
+static gboolean start_any_daemon = FALSE;
 static gchar* run_components = NULL;
 
 static GOptionEntry option_entries[] = {
@@ -106,6 +108,8 @@
 	  "Run as a daemon", NULL }, 
 	{ "login", 'l', 0, G_OPTION_ARG_NONE, &unlock_with_login, 
 	  "Use login password from stdin", NULL },
+	{ "start", 's', 0, G_OPTION_ARG_NONE, &start_any_daemon,
+	  "Start or initialize an already running daemon" },
 	{ "components", 'c', 0, G_OPTION_ARG_STRING, &run_components,
 	  "The components to run", DEFAULT_COMPONENTS },
 	{ NULL }
@@ -131,6 +135,13 @@
 		gkr_cleanup_register (g_free, run_components);
 	}
 	
+	/* Check the arguments */
+	if (unlock_with_login && start_any_daemon) {
+		g_printerr ("gnome-keyring-daemon: The --start option is incompatible with --login");
+		start_any_daemon = FALSE;
+	}
+		
+	
 	g_option_context_free (context);
 }
 
@@ -326,10 +337,16 @@
     g_log_set_default_handler (log_handler, NULL);
 }
 
+void
+gkr_daemon_quit (void)
+{
+	g_main_loop_quit (loop);
+}
+
 static gboolean
 signal_handler (guint sig, gpointer unused)
 {
-	g_main_loop_quit (loop);
+	gkr_daemon_quit ();
 	return TRUE;
 }
 
@@ -423,7 +440,96 @@
 	const gchar **env;
 	for (env = gkr_daemon_util_get_environment (); *env; ++env)
 		printf ("%s\n", *env);
-	printf ("GNOME_KEYRING_PID=%d\n", (gint)pid);
+	if (pid)
+		printf ("GNOME_KEYRING_PID=%d\n", (gint)pid);
+}
+
+static gboolean
+initialize_running_daemon (int sock)
+{
+	GnomeKeyringResult res;
+	gchar **envp, **e;
+	GkrBuffer buf;
+	gboolean ret;
+	
+	if (gkr_unix_credentials_write (sock) < 0)
+		return FALSE;
+
+	gkr_buffer_init_full (&buf, 128, (GkrBufferAllocator)g_realloc);
+	
+	envp = gnome_keyring_build_environment (GNOME_KEYRING_IN_ENVIRONMENT);
+	ret = gkr_proto_encode_prepare_environment (&buf, (const gchar**)envp);
+	g_strfreev (envp);
+	
+	if (!ret) {
+		gkr_buffer_uninit (&buf);
+		g_return_val_if_reached (FALSE);
+	}
+
+	envp = NULL;
+
+	ret = gnome_keyring_socket_write_buffer (sock, &buf) && 
+	      gnome_keyring_socket_read_buffer (sock, &buf) && 
+	      gkr_proto_decode_prepare_environment_reply (&buf, &res, &envp);
+	
+	
+	gkr_buffer_uninit (&buf);
+	
+	if(!ret) {
+		g_warning ("couldn't initialize running daemon");
+		return FALSE;
+	}
+
+	if (res == GNOME_KEYRING_RESULT_OK) {
+		g_return_val_if_fail (envp, FALSE);
+		for (e = envp; *e; ++e)
+			gkr_daemon_util_push_environment_full (*e);
+		ret = TRUE;
+	} else {
+		g_warning ("couldn't initialize running daemon: %s", gnome_keyring_result_to_message (res));
+		ret = FALSE;
+	}
+	
+	g_strfreev (envp);
+
+	return ret;
+}
+
+static gboolean
+start_or_initialize_daemon (void)
+{
+	gboolean ret;
+	int sock;
+	
+	/* 
+	 * Is a daemon already running? If not we need to run
+	 * a daemon process, just return and let things go 
+	 * their normal way. 
+	 */
+	sock = gnome_keyring_socket_connect_daemon (FALSE);
+	if (sock == -1)
+		return FALSE;
+	
+	ret = initialize_running_daemon (sock);
+	close (sock);
+	
+	/* Initialization failed, start this process up as a daemon */
+	if (!ret)
+		return FALSE;
+	
+	/* 
+	 * Now we've initialized the daemon, we need to print out 
+	 * the daemon's environment for any callers, and possibly
+	 * block if we've been asked to remain in the foreground.
+	 */
+	print_environment (0);
+	
+	/* TODO: Better way to sleep forever? */
+	if (run_foreground) {
+		while (sleep(0x08000000) == 0);
+	}
+	
+	return TRUE;
 }
 
 int
@@ -441,7 +547,7 @@
 	g_thread_init (NULL);
 	
 	parse_arguments (&argc, &argv);
-
+	
 #ifdef HAVE_LOCALE_H
 	/* internationalisation */
 	setlocale (LC_ALL, "");
@@ -453,6 +559,15 @@
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 #endif
 
+	/* 
+	 * If asked to start a daemon, see if one is already running 
+	 * and initialize it if so. 
+	 */
+	if (start_any_daemon) {
+		if (start_or_initialize_daemon ())
+			return 0;
+	}
+	
 	gkr_crypto_setup ();
 
 	gcry_create_nonce (&seed, sizeof (seed));
@@ -578,19 +693,10 @@
 					lifetime_slave_pipe_io, NULL);
 			g_io_channel_unref (channel);
 		}
-		
 	}
 	
 	gkr_async_workers_init (loop);
-	
-	/* 
-	 * We may be launched before the DBUS session, (ie: via PAM) 
-	 * and DBus tries to launch itself somehow, so double check 
-	 * that it has really started.
-	 */ 
-	env = getenv ("DBUS_SESSION_BUS_ADDRESS");
-	if (env && env[0])
-		gkr_daemon_dbus_setup (loop);
+	gkr_daemon_dbus_setup ();
 
 	/*
 	 * Unlock the login keyring if we were given a password on STDIN.

Modified: trunk/daemon/gkr-daemon.h
==============================================================================
--- trunk/daemon/gkr-daemon.h	(original)
+++ trunk/daemon/gkr-daemon.h	Sun Nov  9 23:02:22 2008
@@ -45,10 +45,12 @@
 
 extern GkrDaemonOperation keyring_ops[];
 
+void           gkr_daemon_quit (void);
+
 gboolean       gkr_daemon_io_create_master_socket (void);
 const gchar*   gkr_daemon_io_get_socket_path      (void);
 
 /* Dbus Initialization/Cleanup */
-void gkr_daemon_dbus_setup (GMainLoop *loop);
+void gkr_daemon_dbus_setup (void);
 
 #endif /* GNOME_KEYRING_DAEMON_H */

Added: trunk/daemon/gnome-keyring-daemon.desktop.in
==============================================================================
--- (empty file)
+++ trunk/daemon/gnome-keyring-daemon.desktop.in	Sun Nov  9 23:02:22 2008
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Type=Application
+Name=GNOME Keyring Daemon
+Exec=gnome-keyring-daemon --start
+OnlyShowIn=GNOME;
+X-GNOME-Autostart-Phase=Initialization
+X-GNOME-AutoRestart=false
+X-GNOME-Autostart-Notify=true
+X-GNOME-Bugzilla-Bugzilla=GNOME
+X-GNOME-Bugzilla-Product=gnome-keyring
+X-GNOME-Bugzilla-Component=general
+X-GNOME-Bugzilla-Version= VERSION@
\ No newline at end of file

Modified: trunk/library/Makefile.am
==============================================================================
--- trunk/library/Makefile.am	(original)
+++ trunk/library/Makefile.am	Sun Nov  9 23:02:22 2008
@@ -19,6 +19,7 @@
 	gnome-keyring-private.h \
 	gnome-keyring-proto.c \
 	gnome-keyring-proto.h \
+	gnome-keyring-socket.c \
 	gnome-keyring-utils.c
 
 libgnome_keyring_common_la_LIBADD = \

Modified: trunk/library/gnome-keyring-private.h
==============================================================================
--- trunk/library/gnome-keyring-private.h	(original)
+++ trunk/library/gnome-keyring-private.h	Sun Nov  9 23:02:22 2008
@@ -25,6 +25,7 @@
 #define GNOME_KEYRING_PRIVATE_H
 
 #include "gnome-keyring.h"
+#include "gnome-keyring-proto.h"
 
 struct GnomeKeyringApplicationRef {
 	char *display_name;
@@ -56,6 +57,18 @@
 #define GNOME_KEYRING_DAEMON_PATH       "/org/gnome/keyring/daemon"
 #define GNOME_KEYRING_DAEMON_INTERFACE  "org.gnome.keyring.Daemon"
 
+int gnome_keyring_socket_connect_daemon (gboolean non_blocking);
+int gnome_keyring_socket_read_all (int fd, guchar *buf, size_t len);
+int gnome_keyring_socket_write_all (int fd, const guchar *buf, size_t len);
+gboolean gnome_keyring_socket_read_buffer (int fd, GkrBuffer *buffer);
+gboolean gnome_keyring_socket_write_buffer (int fd, GkrBuffer *buffer);
+
+extern const gchar *GNOME_KEYRING_OUT_ENVIRONMENT[];
+extern const gchar *GNOME_KEYRING_IN_ENVIRONMENT[];
+
+gchar** gnome_keyring_build_environment (const gchar **names);
+void gnome_keyring_apply_environment (gchar **envp);
+
 void 	_gnome_keyring_memory_dump (void);
 extern  gboolean gnome_keyring_memory_warning;
  

Added: trunk/library/gnome-keyring-socket.c
==============================================================================
--- (empty file)
+++ trunk/library/gnome-keyring-socket.c	Sun Nov  9 23:02:22 2008
@@ -0,0 +1,247 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-keyring.c - library for talking to the keyring daemon.
+
+   Copyright (C) 2003 Red Hat, Inc
+   Copyright (C) 2008 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Alexander Larsson <alexl redhat com>
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gnome-keyring-private.h"
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static gchar* 
+find_daemon_via_dbus ()
+{
+	DBusConnection *dconn;
+	DBusMessage *reply;
+	DBusMessage *msg;
+	DBusMessageIter args;
+	DBusError derr;
+	char* socket = NULL;
+
+	if (!g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
+		return NULL;
+
+	dbus_error_init (&derr);
+	dconn = dbus_bus_get (DBUS_BUS_SESSION, &derr);
+	if (!dconn) {
+		g_warning ("couldn't connect to dbus session bus: %s", derr.message);
+		return NULL;
+	}	
+
+	msg = dbus_message_new_method_call (GNOME_KEYRING_DAEMON_SERVICE,
+	                                    GNOME_KEYRING_DAEMON_PATH,
+	                                    GNOME_KEYRING_DAEMON_INTERFACE,
+	                                    "GetSocketPath");
+	if (!msg) {
+		g_warning ("couldn't create dbus message");
+		dbus_connection_unref (dconn);
+		return NULL;
+	}
+
+	/* Send message and get a handle for a reply */
+	reply = dbus_connection_send_with_reply_and_block (dconn, msg, 1000, &derr);
+	dbus_message_unref (msg);
+	if (!reply) {
+		g_warning ("couldn't communicate with gnome keyring daemon via dbus: %s", derr.message);
+		dbus_connection_unref (dconn);
+		return NULL;
+	}
+
+	/* Read the return value */
+	if (!dbus_message_iter_init(reply, &args) || 
+	    dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
+		g_warning ("gnome-keyring-daemon sent back an invalid reply");
+	} else {
+		dbus_message_iter_get_basic(&args, &socket);
+		socket = g_strdup (socket);
+	}
+
+	dbus_message_unref (reply);
+	dbus_connection_unref (dconn);
+
+	return socket;
+}
+
+static int 
+connect_to_daemon_at (const gchar *path)
+{
+	struct sockaddr_un addr;
+	int sock;
+
+	addr.sun_family = AF_UNIX;
+	strncpy (addr.sun_path, path, sizeof (addr.sun_path));
+	
+	sock = socket (AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		return -1;
+	}
+
+	/* close on exec */
+	if (fcntl (sock, F_SETFD, 1) == -1) {
+		close (sock);
+		return -1;
+	}
+
+	if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
+		close (sock);
+		return -1;
+	}
+
+	return sock;
+}
+
+int
+gnome_keyring_socket_connect_daemon (gboolean non_blocking)
+{
+	const gchar *epath = NULL;
+	int sock = -1;
+	int val;
+
+	/* Try using the environment variable */
+	epath = g_getenv ("GNOME_KEYRING_SOCKET");
+	if (epath && epath[0]) {
+		sock = connect_to_daemon_at (epath);
+		if (sock < 0) {
+			g_warning ("couldn't connect to daemon at $GNOME_KEYRING_SOCKET: %s: %s", 
+				   epath, g_strerror (errno));
+		}
+	}
+
+	/* Try using DBus to find daemon */
+	if (sock < 0) {
+		gchar *dpath = find_daemon_via_dbus ();
+		if (dpath) {
+			sock = connect_to_daemon_at (dpath);
+			g_free (dpath);
+			if (sock < 0) {
+				g_warning ("couldn't connect to daemon at DBus discovered socket: %s: %s", 
+					     dpath, g_strerror (errno));
+			}
+		}
+	}
+
+	if (sock < 0)
+		return -1;
+
+	/* Setup non blocking */
+	if (non_blocking) {
+		val = fcntl (sock, F_GETFL, 0);
+		if (val < 0) {
+			close (sock);
+			return -1;
+		}
+
+		if (fcntl (sock, F_SETFL, val | O_NONBLOCK) < 0) {
+			close (sock);
+			return -1;
+		}
+	}
+	
+	return sock;
+}
+
+int
+gnome_keyring_socket_read_all (int fd, guchar *buf, size_t len)
+{
+	size_t bytes;
+	ssize_t res;
+	
+	bytes = 0;
+	while (bytes < len) {
+		res = read (fd, buf + bytes, len - bytes);
+		if (res <= 0) {
+			if (res == 0)
+				res = -1;
+			else if (errno == EAGAIN)
+				continue;
+			else 
+				g_warning ("couldn't read %u bytes from gnome-keyring socket: %s", 
+					   (unsigned int)len, g_strerror (errno));
+			return res;
+		}
+		bytes += res;
+	}
+	return 0;
+}
+
+
+int
+gnome_keyring_socket_write_all (int fd, const guchar *buf, size_t len)
+{
+	size_t bytes;
+	ssize_t res;
+
+	bytes = 0;
+	while (bytes < len) {
+		res = write (fd, buf + bytes, len - bytes);
+		if (res < 0) {
+			if (errno != EINTR &&
+			    errno != EAGAIN) {
+				g_warning ("write_all write failure: %s", g_strerror (errno));
+				return -1;
+			}
+		} else {
+			bytes += res;
+		}
+	}
+	return 0;
+}
+
+gboolean 
+gnome_keyring_socket_read_buffer (int fd, GkrBuffer *buffer)
+{
+	guint32 packet_size;
+	
+	gkr_buffer_resize (buffer, 4);
+	if (gnome_keyring_socket_read_all (fd, buffer->buf, 4) < 0)
+		return FALSE;
+
+	if (!gkr_proto_decode_packet_size (buffer, &packet_size) ||
+	    packet_size < 4)
+		return FALSE;
+
+	gkr_buffer_resize (buffer, packet_size);
+	if (gnome_keyring_socket_read_all (fd, buffer->buf + 4, packet_size - 4) < 0)
+		return FALSE;
+
+	return TRUE;
+}
+
+gboolean 
+gnome_keyring_socket_write_buffer (int fd, GkrBuffer *buffer)
+{
+	return gnome_keyring_socket_write_all (fd, buffer->buf, buffer->len) >= 0;
+}
+

Modified: trunk/library/gnome-keyring-utils.c
==============================================================================
--- trunk/library/gnome-keyring-utils.c	(original)
+++ trunk/library/gnome-keyring-utils.c	Sun Nov  9 23:02:22 2008
@@ -34,6 +34,68 @@
 
 /* Functions used by both the library and the daemon */
 
+/* 
+ * A list of all the environment variables the daemon can
+ * possibly send out when it starts. 
+ */
+const gchar *GNOME_KEYRING_OUT_ENVIRONMENT[] = {
+	"SSH_AUTH_SOCK",
+	"GNOME_KEYRING_SOCKET",
+	"GNOME_KEYRING_PID",
+	"SSH_AGENT_PID",
+	NULL
+};
+
+/*
+ * A list of all the environment variables the daemon 
+ * is interested in from clients if it was started 
+ * early before these environment variables were set.
+ */
+const gchar *GNOME_KEYRING_IN_ENVIRONMENT[] = {
+	"DISPLAY",
+	"DBUS_SESSION_BUS_ADDRESS",
+	"XAUTHORITY",
+	"XDG_SESSION_COOKIE",
+	"DESKTOP_AUTOSTART_ID",
+	"LANG",
+	NULL
+};
+
+gchar** 
+gnome_keyring_build_environment (const gchar **names)
+{
+	GArray *array = g_array_sized_new (TRUE, TRUE, sizeof (gchar*), 8);
+	const gchar *value;
+	const gchar **name;
+	gchar *env;
+	
+	/* Transform them into NAME=VALUE pairs */
+	for (name = names; *name; ++name) {
+		value = g_getenv (*name);
+		if (value) {
+			env = g_strdup_printf ("%s=%s", *name, value);
+			g_array_append_val (array, env);
+		}
+	}
+
+	return (gchar**)g_array_free (array, FALSE);
+}
+
+void 
+gnome_keyring_apply_environment (gchar **envp)
+{
+	gchar **e, **parts;
+	
+	g_return_if_fail (envp);
+	
+	for (e = envp; *e; ++e) {
+		parts = g_strsplit (*e, "=", 2);
+		if (parts && parts[0] && parts[1])
+			g_setenv (parts[0], parts[1], TRUE);
+		g_strfreev (parts);
+	}
+}
+
 /**
  * gnome_keyring_free_password:
  * @password: the password to be freed

Modified: trunk/library/gnome-keyring.c
==============================================================================
--- trunk/library/gnome-keyring.c	(original)
+++ trunk/library/gnome-keyring.c	Sun Nov  9 23:02:22 2008
@@ -35,7 +35,6 @@
 
 #include <time.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -43,11 +42,8 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
-#include <sys/un.h>
 #include <stdarg.h>
 
-#include <dbus/dbus.h>
-
 typedef enum {
 	CALLBACK_DONE,
 	CALLBACK_GET_STRING,
@@ -98,135 +94,6 @@
 	GDestroyNotify destroy_reply_data;
 };
 
-static gchar* 
-find_daemon_via_dbus ()
-{
-	DBusConnection *dconn;
-	DBusMessage *reply;
-	DBusMessage *msg;
-	DBusMessageIter args;
-	DBusError derr;
-	char* socket = NULL;
-
-	dbus_error_init (&derr);
-	dconn = dbus_bus_get (DBUS_BUS_SESSION, &derr);
-	if (!dconn) {
-		g_warning ("couldn't connect to dbus session bus: %s", derr.message);
-		return NULL;
-	}	
-
-	msg = dbus_message_new_method_call (GNOME_KEYRING_DAEMON_SERVICE,
-	                                    GNOME_KEYRING_DAEMON_PATH,
-	                                    GNOME_KEYRING_DAEMON_INTERFACE,
-	                                    "GetSocketPath");
-	if (!msg) {
-		g_warning ("couldn't create dbus message");
-		dbus_connection_unref (dconn);
-		return NULL;
-	}
-
-	/* Send message and get a handle for a reply */
-	reply = dbus_connection_send_with_reply_and_block (dconn, msg, 1000, &derr);
-	dbus_message_unref (msg);
-	if (!reply) {
-		g_warning ("couldn't communicate with gnome keyring daemon via dbus: %s", derr.message);
-		dbus_connection_unref (dconn);
-		return NULL;
-	}
-
-	/* Read the return value */
-	if (!dbus_message_iter_init(reply, &args) || 
-	    dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
-		g_warning ("gnome-keyring-daemon sent back an invalid reply");
-	} else {
-		dbus_message_iter_get_basic(&args, &socket);
-		socket = g_strdup (socket);
-	}
-
-	dbus_message_unref (reply);
-	dbus_connection_unref (dconn);
-
-	return socket;
-}
-
-static int 
-connect_to_daemon_at (const gchar *path)
-{
-	struct sockaddr_un addr;
-	int sock;
-
-	addr.sun_family = AF_UNIX;
-	strncpy (addr.sun_path, path, sizeof (addr.sun_path));
-	
-	sock = socket (AF_UNIX, SOCK_STREAM, 0);
-	if (sock < 0) {
-		return -1;
-	}
-
-	/* close on exec */
-	if (fcntl (sock, F_SETFD, 1) == -1) {
-		close (sock);
-		return -1;
-	}
-
-	if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
-		close (sock);
-		return -1;
-	}
-
-	return sock;
-}
-
-static int
-connect_to_daemon (gboolean non_blocking)
-{
-	const gchar *epath = NULL;
-	int sock = -1;
-	int val;
-
-	/* Try using the environment variable */
-	epath = g_getenv ("GNOME_KEYRING_SOCKET");
-	if (epath && epath[0]) {
-		sock = connect_to_daemon_at (epath);
-		if (sock < 0) {
-			g_warning ("couldn't connect to daemon at $GNOME_KEYRING_SOCKET: %s: %s", 
-				     epath, g_strerror (errno));
-		}
-	}
-
-	/* Try using DBus to find daemon */
-	if (sock < 0) {
-		gchar *dpath = find_daemon_via_dbus ();
-		if (dpath) {
-			sock = connect_to_daemon_at (dpath);
-			g_free (dpath);
-			if (sock < 0) {
-				g_warning ("couldn't connect to daemon at DBus discovered socket: %s: %s", 
-					     dpath, g_strerror (errno));
-			}
-		}
-	}
-
-	if (sock < 0)
-		return -1;
-
-	/* Setup non blocking */
-	if (non_blocking) {
-		val = fcntl (sock, F_GETFL, 0);
-		if (val < 0) {
-			close (sock);
-			return -1;
-		}
-
-		if (fcntl (sock, F_SETFL, val | O_NONBLOCK) < 0) {
-			close (sock);
-			return -1;
-		}
-	}
-	
-	return sock;
-}
-
 static void
 operation_free (GnomeKeyringOperation *op)
 {
@@ -307,53 +174,6 @@
 		op->idle_watch = g_idle_add (op_failed, op);
 }
 
-static int
-read_all (int fd, guchar *buf, size_t len)
-{
-	size_t bytes;
-	ssize_t res;
-	
-	bytes = 0;
-	while (bytes < len) {
-		res = read (fd, buf + bytes, len - bytes);
-		if (res <= 0) {
-			if (res == 0)
-				res = -1;
-			else if (errno == EAGAIN)
-				continue;
-			else 
-				g_warning ("couldn't read %u bytes from gnome-keyring socket: %s", 
-					   (unsigned int)len, g_strerror (errno));
-			return res;
-		}
-		bytes += res;
-	}
-	return 0;
-}
-
-
-static int
-write_all (int fd, const guchar *buf, size_t len)
-{
-	size_t bytes;
-	ssize_t res;
-
-	bytes = 0;
-	while (bytes < len) {
-		res = write (fd, buf + bytes, len - bytes);
-		if (res < 0) {
-			if (errno != EINTR &&
-			    errno != EAGAIN) {
-				perror ("write_all write failure:");
-				return -1;
-			}
-		} else {
-			bytes += res;
-		}
-	}
-	return 0;
-}
-
 static GnomeKeyringResult
 write_credentials_byte_sync (int socket)
 {
@@ -519,7 +339,7 @@
 		close (op->socket);
 	}
 
-	op->socket = connect_to_daemon (TRUE);
+	op->socket = gnome_keyring_socket_connect_daemon (TRUE);
 	if (op->socket < 0) {
 		schedule_op_failed (op, GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON);
 	} else  {
@@ -542,45 +362,27 @@
 {
 	GnomeKeyringResult res;
 	int socket;
-	guint32 packet_size;
 
 	g_assert (buffer != NULL);
 	g_assert (receive_buffer != NULL);
 
-	socket = connect_to_daemon (FALSE);
-	if (socket < 0) {
+	socket = gnome_keyring_socket_connect_daemon (FALSE);
+	if (socket < 0)
 		return GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON;
-	}
+
 	res = write_credentials_byte_sync (socket);
 	if (res != GNOME_KEYRING_RESULT_OK) {
 		close (socket);
 		return res;
 	}
 
-	if (write_all (socket,
-		       buffer->buf, buffer->len) < 0) {
+	if (!gnome_keyring_socket_write_buffer (socket, buffer) || 
+	    !gnome_keyring_socket_read_buffer (socket, receive_buffer)) {
 		close (socket);
 		return GNOME_KEYRING_RESULT_IO_ERROR;
 	}
 
-	gkr_buffer_resize (receive_buffer, 4);
-	if (read_all (socket, receive_buffer->buf, 4) < 0) {
-		close (socket);
-		return GNOME_KEYRING_RESULT_IO_ERROR;
-	}
-
-	if (!gkr_proto_decode_packet_size (receive_buffer, &packet_size) ||
-	    packet_size < 4) {
-		close (socket);
-		return GNOME_KEYRING_RESULT_IO_ERROR;
-	}
-	gkr_buffer_resize (receive_buffer, packet_size);
-	if (read_all (socket, receive_buffer->buf + 4, packet_size - 4) < 0) {
-		close (socket);
-		return GNOME_KEYRING_RESULT_IO_ERROR;
-	}
 	close (socket);
-	
 	return GNOME_KEYRING_RESULT_OK;
 }
 
@@ -597,7 +399,7 @@
 {
 	int socket;
 	
-	socket = connect_to_daemon (FALSE);
+	socket = gnome_keyring_socket_connect_daemon (FALSE);
 	if (socket < 0) {
 		return FALSE;
 	}
@@ -1776,23 +1578,13 @@
 {
 	GkrBuffer send, receive;
 	GnomeKeyringResult res;
-	gchar **envp, **e, *name;
-	gchar **parts;
+	gchar **envp;
 	gboolean ret;
 
 	gkr_buffer_init_full (&send, 128, NORMAL_ALLOCATOR);
 
 	/* Get all the environment names */
-	envp = g_listenv ();
-	g_return_val_if_fail (envp, GNOME_KEYRING_RESULT_BAD_ARGUMENTS);
-	
-	/* Transform them into NAME=VALUE pairs */
-	for (e = envp; *e; ++e) {
-		name = *e;
-		*e = g_strdup_printf ("%s=%s", name, g_getenv (name));
-		g_free (name);
-	}
-
+	envp = gnome_keyring_build_environment (GNOME_KEYRING_IN_ENVIRONMENT);
 	ret = gkr_proto_encode_prepare_environment (&send, (const gchar**)envp);
 	g_strfreev (envp);
 	
@@ -1817,12 +1609,7 @@
 	
 	if (res == GNOME_KEYRING_RESULT_OK) {
 		g_return_val_if_fail (envp, GNOME_KEYRING_RESULT_IO_ERROR);
-		for (e = envp; *e; ++e) {
-			parts = g_strsplit (*e, "=", 2);
-			if (parts && parts[0] && parts[1])
-				g_setenv (parts[0], parts[1], TRUE);
-			g_strfreev (parts);
-		}
+		gnome_keyring_apply_environment (envp);
 	}
 	
 	g_strfreev (envp);



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