gnome-keyring r1381 - in trunk: . common daemon library pam



Author: nnielsen
Date: Thu Dec 11 23:33:20 2008
New Revision: 1381
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1381&view=rev

Log:
	* common/gkr-crypto.c:
	* common/gkr-secure-memory.c:
	* common/gkr-secure-memory.h:
	* daemon/gkr-daemon.c:
	* daemon/gkr-daemon.h:
	* daemon/gkr-daemon-dbus.c:
	* daemon/gkr-daemon-ops.c: 
	* pam/gkr-pam-module.c: Rework initialization of the daemon
	so that most initialization can happen after starting via PAM.
	Fixes bug #558181

Modified:
   trunk/ChangeLog
   trunk/common/gkr-crypto.c
   trunk/common/gkr-secure-memory.c
   trunk/common/gkr-secure-memory.h
   trunk/daemon/gkr-daemon-dbus.c
   trunk/daemon/gkr-daemon-ops.c
   trunk/daemon/gkr-daemon.c
   trunk/daemon/gkr-daemon.h
   trunk/library/gnome-keyring-private.h
   trunk/library/gnome-keyring-socket.c
   trunk/library/gnome-keyring.c
   trunk/pam/gkr-pam-module.c

Modified: trunk/common/gkr-crypto.c
==============================================================================
--- trunk/common/gkr-crypto.c	(original)
+++ trunk/common/gkr-crypto.c	Thu Dec 11 23:33:20 2008
@@ -66,6 +66,8 @@
 void
 gkr_crypto_setup (void)
 {
+	unsigned seed;
+
 	if (gcrypt_initialized)
 		return;
 		
@@ -80,6 +82,9 @@
 	                             gkr_secure_free);
 	                             
 	gcrypt_initialized = TRUE;
+	
+	gcry_create_nonce (&seed, sizeof (seed));
+	srand (seed);
 }
 
 static const char HEXC[] = "0123456789ABCDEF";

Modified: trunk/common/gkr-secure-memory.c
==============================================================================
--- trunk/common/gkr-secure-memory.c	(original)
+++ trunk/common/gkr-secure-memory.c	Thu Dec 11 23:33:20 2008
@@ -774,7 +774,7 @@
 }
 
 void
-gkr_secure_strfree (char *str)
+gkr_secure_strclear (char *str)
 {
 	volatile char *vp;
 	size_t len;
@@ -782,12 +782,6 @@
 	if (!str)
 		return;
 		
-	/*
-	 * If we're using unpageable 'secure' memory, then the free call
-	 * should zero out the memory, but because on certain platforms 
-	 * we may be using normal memory, zero it out here just in case.
-	 */
-		
         vp = (volatile char*)str;
        	len = strlen (str);
         while (len) { 
@@ -795,6 +789,17 @@
         	vp++;
         	len--; 
         } 
+}
+
+void
+gkr_secure_strfree (char *str)
+{
+	/*
+	 * If we're using unpageable 'secure' memory, then the free call
+	 * should zero out the memory, but because on certain platforms 
+	 * we may be using normal memory, zero it out here just in case.
+	 */
 	
+	gkr_secure_strclear (str);
 	gkr_secure_free_full (str, GKR_SECURE_USE_FALLBACK);
 }

Modified: trunk/common/gkr-secure-memory.h
==============================================================================
--- trunk/common/gkr-secure-memory.h	(original)
+++ trunk/common/gkr-secure-memory.h	Thu Dec 11 23:33:20 2008
@@ -80,6 +80,8 @@
 
 char*  gkr_secure_strdup       (const char *str);
 
+void   gkr_secure_strclear     (char *str);
+
 void   gkr_secure_strfree      (char *str);
 
 #endif /* GKR_SECURE_MEMORY_H */

Modified: trunk/daemon/gkr-daemon-dbus.c
==============================================================================
--- trunk/daemon/gkr-daemon-dbus.c	(original)
+++ trunk/daemon/gkr-daemon-dbus.c	Thu Dec 11 23:33:20 2008
@@ -202,7 +202,7 @@
 		dbus_message_unref (msg);
 		
 		if (!reply) {
-			g_warning ("couldn't set environment variable in session: %s", derr.message);
+			g_message ("couldn't set environment variable in session: %s", derr.message);
 			return;
 		}
 		
@@ -357,15 +357,6 @@
 	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;
 	
@@ -414,7 +405,7 @@
 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
 		g_message ("another gnome-keyring-daemon is running");
-		return;
+		break;
 	default:
 		g_return_if_reached ();
 		break;

Modified: trunk/daemon/gkr-daemon-ops.c
==============================================================================
--- trunk/daemon/gkr-daemon-ops.c	(original)
+++ trunk/daemon/gkr-daemon-ops.c	Thu Dec 11 23:33:20 2008
@@ -1713,8 +1713,11 @@
 	
 	g_strfreev (environment);
 	
-	/* We may have received DBUS environment variable so try and setup DBUS */
-	gkr_daemon_dbus_setup ();
+	/* 
+	 * We've now definitely received everything we need to run. Ask
+	 * the daemon to complete the initialization. 
+	 */
+	gkr_daemon_complete_initialization();
 
 	gkr_buffer_add_uint32 (result, GNOME_KEYRING_RESULT_OK);
 

Modified: trunk/daemon/gkr-daemon.c
==============================================================================
--- trunk/daemon/gkr-daemon.c	(original)
+++ trunk/daemon/gkr-daemon.c	Thu Dec 11 23:33:20 2008
@@ -90,28 +90,30 @@
 
 /* All the components to run on startup if not set in gconf */
 #ifdef WITH_SSH
-#define DEFAULT_COMPONENTS  "ssh,keyring,pkcs11"
+#define DEFAULT_COMPONENTS  "ssh,pkcs11"
 #else
-#define DEFAULT_COMPONENTS  "keyring,pkcs11"
+#define DEFAULT_COMPONENTS  "pkcs11"
 #endif
 
 static gboolean run_foreground = FALSE;
 static gboolean run_daemonized = FALSE;
-static gboolean unlock_with_login = FALSE;
-static gboolean start_any_daemon = FALSE;
+static gboolean run_for_login = FALSE;
+static gboolean run_for_start = FALSE;
 static gchar* run_components = NULL;
+static gchar* login_password = NULL;
+static gboolean initialization_completed = FALSE;
 
 static GOptionEntry option_entries[] = {
 	{ "foreground", 'f', 0, G_OPTION_ARG_NONE, &run_foreground, 
 	  "Run in the foreground", NULL }, 
 	{ "daemonize", 'd', 0, G_OPTION_ARG_NONE, &run_daemonized, 
 	  "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" },
+	{ "login", 'l', 0, G_OPTION_ARG_NONE, &run_for_login, 
+	  "Run for a user login. Read login password from stdin", NULL },
+	{ "start", 's', 0, G_OPTION_ARG_NONE, &run_for_start,
+	  "Start a dameon or initialize an already running daemon." },
 	{ "components", 'c', 0, G_OPTION_ARG_STRING, &run_components,
-	  "The components to run", DEFAULT_COMPONENTS },
+	  "The optional components to run", DEFAULT_COMPONENTS },
 	{ NULL }
 };
 
@@ -136,9 +138,9 @@
 	}
 	
 	/* Check the arguments */
-	if (unlock_with_login && start_any_daemon) {
+	if (run_for_login && run_for_start) {
 		g_printerr ("gnome-keyring-daemon: The --start option is incompatible with --login");
-		start_any_daemon = FALSE;
+		run_for_login = FALSE;
 	}
 		
 	
@@ -369,6 +371,12 @@
 	/* We only accept a max of 8K as the login password */
 	#define MAX_LENGTH 8192
 	#define MAX_BLOCK 256
+
+	/* 
+	 * When --login is specified then the login password is passed 
+	 * in on stdin. All data (including newlines) are part of the 
+	 * password.
+	 */
 	
 	gchar *buf = gkr_secure_alloc (MAX_BLOCK);
 	gchar *ret = NULL;
@@ -401,28 +409,18 @@
 }
 
 static void
-close_stdinout (void)
+cleanup_and_exit (int code)
 {
-	int fd;
-	
-	fd = open ("/dev/null", O_RDONLY);
-	sane_dup2 (fd, 0);
-	close (fd);
-	
-	fd = open ("/dev/null", O_WRONLY);
-	sane_dup2 (fd, 1);
-	close (fd);
-
-	fd = open ("/dev/null", O_WRONLY);
-	sane_dup2 (fd, 2);
-	close (fd);
+	gkr_cleanup_perform ();
+	exit (code);
 }
 
 static void
-cleanup_and_exit (int code)
+clear_login_password (void)
 {
-	gkr_cleanup_perform ();
-	_exit (code);
+	if(login_password)
+		gkr_secure_strfree (login_password);
+	login_password = NULL;
 }
 
 static gboolean
@@ -430,11 +428,32 @@
 			GIOCondition cond,
 			gpointer     callback_data)
 {
-	cleanup_and_exit (2);
+	gkr_cleanup_perform ();
+	_exit (2);
 	return FALSE;
 }
 
 static void
+slave_lifetime_to_fd (void)
+{
+	const char *env;
+	GIOChannel *channel;
+	int fd;
+	
+	env = getenv ("GNOME_KEYRING_LIFETIME_FD");
+	if (env && env[0]) {
+		fd = atoi (env);
+		if (fd != 0) {
+			channel = g_io_channel_unix_new (fd);
+			g_io_add_watch (channel,
+					G_IO_IN | G_IO_HUP,
+					lifetime_slave_pipe_io, NULL);
+			g_io_channel_unref (channel);
+		}
+	}
+}
+
+static void
 print_environment (pid_t pid)
 {
 	const gchar **env;
@@ -445,7 +464,7 @@
 }
 
 static gboolean
-initialize_running_daemon (int sock)
+initialize_other_running_daemon (int sock)
 {
 	GnomeKeyringResult res;
 	gchar **envp, **e;
@@ -506,11 +525,11 @@
 	 * a daemon process, just return and let things go 
 	 * their normal way. 
 	 */
-	sock = gnome_keyring_socket_connect_daemon (FALSE);
+	sock = gnome_keyring_socket_connect_daemon (FALSE, TRUE);
 	if (sock == -1)
 		return FALSE;
 	
-	ret = initialize_running_daemon (sock);
+	ret = initialize_other_running_daemon (sock);
 	close (sock);
 	
 	/* Initialization failed, start this process up as a daemon */
@@ -532,147 +551,194 @@
 	return TRUE;
 }
 
-int
-main (int argc, char *argv[])
+static void
+fork_and_print_environment (void)
 {
-	const char *env;
-	int fd;
+	int status;
 	pid_t pid;
-	GIOChannel *channel;
-	GMainContext *ctx;
-	gchar *login_password;
-	unsigned seed;
+	int fd, i;
+
+	if (run_foreground) {
+		print_environment (getpid ());
+		return;
+	}
 	
-	g_type_init ();
-	g_thread_init (NULL);
+	pid = fork ();
+		
+	if (pid != 0) {
+
+		/* Here we are in the initial process */
+
+		if (run_daemonized) {
+			
+			/* Initial process, waits for intermediate child */
+			if (pid == -1)
+				exit (1);
+
+			waitpid (pid, &status, 0);
+			if (WEXITSTATUS (status) != 0)
+				exit (WEXITSTATUS (status));
+			
+		} else {
+			/* Not double forking, we know the PID */
+			print_environment (pid);
+		}
+
+		/* The initial process exits successfully */
+		exit (0);
+	}
 	
-	parse_arguments (&argc, &argv);
+	if (!run_daemonized) 
+		return;
 	
-#ifdef HAVE_LOCALE_H
-	/* internationalisation */
-	setlocale (LC_ALL, "");
-#endif
+	/* Double fork if need to daemonize properly */
+	pid = fork ();
+	
+	if (pid != 0) {
 
-#ifdef HAVE_GETTEXT
-	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
-	textdomain (GETTEXT_PACKAGE);
-	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif
+		/* Here we are in the intermediate child process */
+			
+		/* 
+		 * This process exits, so that the final child will inherit 
+		 * init as parent to avoid zombies
+		 */
+		if (pid == -1)
+			exit (1);
 
-	/* 
-	 * If asked to start a daemon, see if one is already running 
-	 * and initialize it if so. 
+		/* We've done two forks. Now we know the PID */
+		print_environment (pid);
+			
+		/* The intermediate child exits */
+		exit (0);
+	}
+
+	/* Here we are in the resulting daemon process. */
+
+	for (i = 0; i < 3; ++i) {
+		fd = open ("/dev/null", O_RDONLY);
+		sane_dup2 (fd, i);
+		close (fd);
+	}
+}
+
+gboolean
+gkr_daemon_complete_initialization(void)
+{
+	/*
+	 * Sometimes we don't initialize the full daemon right on 
+	 * startup. When run with --login is one such case.
 	 */
-	if (start_any_daemon) {
-		if (start_or_initialize_daemon ())
-			return 0;
+	
+	if (initialization_completed) {
+		g_message ("The daemon was already initialized.");
+		return TRUE;
 	}
 	
-	gkr_crypto_setup ();
-
-	gcry_create_nonce (&seed, sizeof (seed));
-	srand (seed);
+	gkr_daemon_dbus_setup ();
 	
 	/* Initialize object storage */
 	if (!gkr_pk_object_storage_initialize ())
-		cleanup_and_exit (1);
+		return FALSE;
 	
 #ifdef ROOT_CERTIFICATES
 	if (!gkr_pk_root_storage_initialize ())
-		cleanup_and_exit (1);
+		return FALSE;
 #endif
 
 	/* Initialize the appropriate components */
-	if (check_run_component ("keyring")) {
-		if (!gkr_daemon_io_create_master_socket ())
-			cleanup_and_exit (1);
-	}
-
+	
 #ifdef WITH_SSH	
 	if (check_run_component ("ssh")) {
 		if (!gkr_daemon_ssh_io_initialize () ||
 		    !gkr_ssh_storage_initialize ())
-			cleanup_and_exit (1);
+			return FALSE;
 	}
 #endif
 	
 	if (check_run_component ("pkcs11")) {
 		if (!gkr_pkcs11_daemon_setup ())
-			cleanup_and_exit (1);
-	}	
-	 
+			return FALSE;
+	}
+	
+	initialization_completed = TRUE;
+	return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+	GMainContext *ctx;
+	
 	/* 
-	 * When --login is specified then the login password is passed 
-	 * in on stdin. All data (including newlines) are part of the 
-	 * password.
+	 * The gnome-keyring startup is not as simple as I wish it could be. 
+	 * 
+	 * It's often started in the primidoral stages of a session, where 
+	 * there's no DBus, no GConf, and no proper X display. This is the 
+	 * strange world of PAM.
+	 * 
+	 * When started with the --login option, we do as little initialization
+	 * as possible. We expect a login password on the stdin, and unlock
+	 * or create the login keyring.
+	 * 
+	 * Then later we expect gnome-keyring-dameon to be run again with the 
+	 * --start option. This second gnome-keyring-daemon will hook the
+	 * original daemon up with environment variables necessary to initialize
+	 * itself and bring it into the session. This second daemon usually exits.
+	 * 
+	 * Without either of these options, we follow a more boring and 
+	 * predictable startup.  
 	 */
-	login_password = unlock_with_login ? read_login_password (STDIN) : NULL;
+	
+	g_type_init ();
+	g_thread_init (NULL);
+	
+#ifdef HAVE_LOCALE_H
+	/* internationalisation */
+	setlocale (LC_ALL, "");
+#endif
+
+#ifdef HAVE_GETTEXT
+	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+	textdomain (GETTEXT_PACKAGE);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+	gkr_crypto_setup ();
+
+	/* Send all warning or error messages to syslog */
+	prepare_logging ();
+	
+	parse_arguments (&argc, &argv);
+	
+	/* The --start option */
+	if (run_for_start) {
+		if (start_or_initialize_daemon ())
+			cleanup_and_exit (0);
+	} 
 	
 	/* 
-	 * The whole forking and daemonizing dance starts here.
+	 * Always initialize the keyring subsystem. This is a necessary
+	 * component that everything else depends on in one way or 
+	 * another. 
 	 */
-	if (!run_foreground) {
-		pid = fork ();
-		
-		/* An intermediate child */
-		if (pid == 0) {
-			if (run_daemonized) {
-				pid = fork ();
-				
-				/* Still in the intermedate child */
-				if (pid != 0) {
-					gkr_secure_free (login_password);
-					
-					/* This process exits, so that the
-					 * final child will inherit init as parent
-					 * to avoid zombies
-					 */
-					if (pid == -1) {
-						exit (1);
-					} else {
-						/* This is where we know the pid of the daemon.
-						 * The initial process will waitpid until we exit,
-						 * so there is no race */
-						print_environment (pid);
-						exit (0);
-					}
-				}
-			}
-			
-			/* final child continues here */
-			
-		/* The initial process */
-		} else {
-			gkr_secure_free (login_password);
-			
-			if (run_daemonized) {
-				int status;
-				
-				/* Initial process, waits for intermediate child */
-				if (pid == -1)
-					exit (1);
-
-				waitpid (pid, &status, 0);
-				if (WEXITSTATUS (status) != 0)
-					exit (WEXITSTATUS (status));
-				
-			} else {
-				print_environment (pid);
-			}
-			
-			exit (0);
-		}
-		
-		/* The final child ... */
-		close_stdinout ();
+	if (!gkr_daemon_io_create_master_socket ())
+		cleanup_and_exit (1);
 
+	/* The --login option. Delayed initialization */
+	if (run_for_login) {
+		login_password = read_login_password (STDIN);
+		atexit (clear_login_password);
+	
+	/* Not a login daemon. Initialize now. */
 	} else {
-		print_environment (getpid ());
+		if (!gkr_daemon_complete_initialization ())
+			cleanup_and_exit (1);
 	}
+	 
+	/* The whole forking and daemonizing dance starts here. */
+	fork_and_print_environment();
 
-	/* Daemon process continues here */
-
-        /* Send all warning or error messages to syslog */
+	/* Prepare logging a second time, since we may be in a different process */
 	prepare_logging();
 
 	loop = g_main_loop_new (NULL, FALSE);
@@ -683,29 +749,19 @@
 	gkr_unix_signal_connect (ctx, SIGHUP, signal_handler, NULL);
 	gkr_unix_signal_connect (ctx, SIGTERM, signal_handler, NULL);
              
-	env = getenv ("GNOME_KEYRING_LIFETIME_FD");
-	if (env && env[0]) {
-		fd = atoi (env);
-		if (fd != 0) {
-			channel = g_io_channel_unix_new (fd);
-			g_io_add_watch (channel,
-					G_IO_IN | G_IO_HUP,
-					lifetime_slave_pipe_io, NULL);
-			g_io_channel_unref (channel);
-		}
-	}
+	/* TODO: Do we still need this? XFCE still seems to use it. */
+	slave_lifetime_to_fd ();
 	
 	gkr_async_workers_init (loop);
-	gkr_daemon_dbus_setup ();
 
 	/*
 	 * Unlock the login keyring if we were given a password on STDIN.
 	 * If it does not exist. We create it. 
 	 */
-	if (unlock_with_login && login_password) {
+	if (login_password) {
 		if (!gkr_keyring_login_unlock (login_password))
 			g_warning ("Failed to unlock login on startup");
-		gkr_secure_free (login_password);
+		gkr_secure_strclear (login_password);
 	}
 	
 	g_main_loop_run (loop);

Modified: trunk/daemon/gkr-daemon.h
==============================================================================
--- trunk/daemon/gkr-daemon.h	(original)
+++ trunk/daemon/gkr-daemon.h	Thu Dec 11 23:33:20 2008
@@ -47,10 +47,12 @@
 
 void           gkr_daemon_quit (void);
 
+gboolean       gkr_daemon_complete_initialization (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 (void);
+void           gkr_daemon_dbus_setup              (void);
 
 #endif /* GNOME_KEYRING_DAEMON_H */

Modified: trunk/library/gnome-keyring-private.h
==============================================================================
--- trunk/library/gnome-keyring-private.h	(original)
+++ trunk/library/gnome-keyring-private.h	Thu Dec 11 23:33:20 2008
@@ -57,7 +57,7 @@
 #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_connect_daemon (gboolean non_blocking, gboolean only_running);
 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);

Modified: trunk/library/gnome-keyring-socket.c
==============================================================================
--- trunk/library/gnome-keyring-socket.c	(original)
+++ trunk/library/gnome-keyring-socket.c	Thu Dec 11 23:33:20 2008
@@ -123,7 +123,7 @@
 }
 
 int
-gnome_keyring_socket_connect_daemon (gboolean non_blocking)
+gnome_keyring_socket_connect_daemon (gboolean non_blocking, gboolean only_running)
 {
 	const gchar *epath = NULL;
 	int sock = -1;
@@ -140,7 +140,7 @@
 	}
 
 	/* Try using DBus to find daemon */
-	if (sock < 0) {
+	if (sock < 0 && !only_running) {
 		gchar *dpath = find_daemon_via_dbus ();
 		if (dpath) {
 			sock = connect_to_daemon_at (dpath);

Modified: trunk/library/gnome-keyring.c
==============================================================================
--- trunk/library/gnome-keyring.c	(original)
+++ trunk/library/gnome-keyring.c	Thu Dec 11 23:33:20 2008
@@ -339,7 +339,7 @@
 		close (op->socket);
 	}
 
-	op->socket = gnome_keyring_socket_connect_daemon (TRUE);
+	op->socket = gnome_keyring_socket_connect_daemon (TRUE, FALSE);
 	if (op->socket < 0) {
 		schedule_op_failed (op, GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON);
 	} else  {
@@ -366,7 +366,7 @@
 	g_assert (buffer != NULL);
 	g_assert (receive_buffer != NULL);
 
-	socket = gnome_keyring_socket_connect_daemon (FALSE);
+	socket = gnome_keyring_socket_connect_daemon (FALSE, FALSE);
 	if (socket < 0)
 		return GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON;
 
@@ -399,7 +399,7 @@
 {
 	int socket;
 	
-	socket = gnome_keyring_socket_connect_daemon (FALSE);
+	socket = gnome_keyring_socket_connect_daemon (FALSE, FALSE);
 	if (socket < 0) {
 		return FALSE;
 	}

Modified: trunk/pam/gkr-pam-module.c
==============================================================================
--- trunk/pam/gkr-pam-module.c	(original)
+++ trunk/pam/gkr-pam-module.c	Thu Dec 11 23:33:20 2008
@@ -271,7 +271,7 @@
 setup_child (int inp[2], int outp[2], int errp[2], 
              pam_handle_t *ph, struct passwd *pwd, const char *password)
 {
-	char *args[] = { GNOME_KEYRING_DAEMON, "-d", "--login", NULL};
+	char *args[] = { GNOME_KEYRING_DAEMON, "--daemonize", "--login", NULL};
 	const char* display;
 	int i, ret;
 	



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