diff -ur gnome-keyring-2.20.orig/daemon/gkr-daemon.c gnome-keyring-2.20/daemon/gkr-daemon.c --- gnome-keyring-2.20.orig/daemon/gkr-daemon.c 2007-10-05 12:40:28.000000000 +0200 +++ gnome-keyring-2.20/daemon/gkr-daemon.c 2007-10-05 12:55:26.000000000 +0200 @@ -27,6 +27,7 @@ #include "common/gkr-async.h" #include "common/gkr-cleanup.h" #include "common/gkr-unix-signal.h" +#include "common/gkr-location.h" #include "keyrings/gkr-keyrings.h" @@ -183,6 +184,10 @@ GIOChannel *channel; GMainContext *ctx; int i; + gboolean login; + char *login_password; + int len; + GkrKeyring *login_keyring; g_type_init (); g_thread_init (NULL); @@ -211,6 +216,7 @@ foreground = FALSE; daemon = FALSE; + login = FALSE; if (argc > 1) { for (i = 1; i < argc; i++) { @@ -218,8 +224,19 @@ foreground = TRUE; if (strcmp (argv[i], "-d") == 0) daemon = TRUE; + if (strcmp (argv[i], "--login") == 0) + login = TRUE; } } + + login_password = NULL; + if (login) { + login_password = gnome_keyring_memory_alloc (256); + fgets (login_password, 256, stdin); + len = strlen (login_password); + if (login_password[len-1] == '\n') + login_password[len-1] = 0; + } if (!foreground) { pid = fork (); @@ -315,6 +332,27 @@ gkr_daemon_dbus_setup (loop, path); #endif + + if (login_password) { + login_keyring = gkr_keyrings_get_login (); + if (login_keyring) { + if (!gkr_keyring_unlock (login_keyring, + login_password)) { + g_warning ("Failed to unlock login keyring"); + } + } else { + login_keyring = + gkr_keyring_create (GKR_LOCATION_BASE_LOCAL, + "login", + login_password); + if (login_keyring) { + gkr_keyrings_add (login_keyring); + g_object_unref (login_keyring); + } + } + gnome_keyring_memory_free (login_password); + } + g_main_loop_run (loop); /* Make sure no other threads are running */ diff -ur gnome-keyring-2.20.orig/pam/gkr-pam-module.c gnome-keyring-2.20/pam/gkr-pam-module.c --- gnome-keyring-2.20.orig/pam/gkr-pam-module.c 2007-10-05 12:40:28.000000000 +0200 +++ gnome-keyring-2.20/pam/gkr-pam-module.c 2007-10-05 12:42:05.000000000 +0200 @@ -249,15 +249,20 @@ } static void -setup_child (int outp[2], int errp[2], struct passwd *pwd) +setup_child (int inp[2], int outp[2], int errp[2], struct passwd *pwd, const char *password) { - char *args[] = { GNOME_KEYRING_DAEMON, "-d", NULL}; - + char *args[] = { GNOME_KEYRING_DAEMON, "-d", "--login", NULL}; + assert (pwd); assert (pwd->pw_dir); - + + /* If no password, don't pas in --login */ + if (password == NULL) + args[2] = NULL; + /* Fix up our end of the pipes */ - if (dup2 (outp[WRITE_END], STDOUT) < 0 || + if (dup2 (inp[READ_END], STDIN) < 0 || + dup2 (outp[WRITE_END], STDOUT) < 0 || dup2 (errp[WRITE_END], STDERR) < 0) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't setup pipes: %s", strerror (errno)); @@ -265,6 +270,8 @@ } /* Close unnecessary file descriptors */ + close (inp[READ_END]); + close (inp[WRITE_END]); close (outp[READ_END]); close (outp[WRITE_END]); close (errp[READ_END]); @@ -348,9 +355,10 @@ } static int -start_daemon (pam_handle_t *ph, struct passwd *pwd) +start_daemon (pam_handle_t *ph, struct passwd *pwd, const char *password) { struct sigaction defsact, oldsact; + int inp[2] = { -1, -1 }; int outp[2] = { -1, -1 }; int errp[2] = { -1, -1 }; int ret = PAM_SERVICE_ERR; @@ -372,7 +380,7 @@ sigaction (SIGCHLD, &defsact, &oldsact); /* Create the necessary pipes */ - if (pipe (outp) < 0 || pipe (errp) < 0) { + if (pipe (inp) < 0 || pipe (outp) < 0 || pipe (errp) < 0) { syslog (GKR_LOG_ERR, "gkr-pam: couldn't create pipes: %s", strerror (errno)); goto done; @@ -387,7 +395,7 @@ /* This is the child */ case 0: - setup_child (outp, errp, pwd); + setup_child (inp, outp, errp, pwd, password); /* Should never be reached */ break; @@ -397,9 +405,16 @@ }; /* Close our unneeded ends of the pipes */ + close (inp[READ_END]); close (outp[WRITE_END]); close (errp[WRITE_END]); - outp[WRITE_END] = errp[WRITE_END] = -1; + inp[READ_END] = outp[WRITE_END] = errp[WRITE_END] = -1; + + if (password) { + /* Write the login keyring password */ + write (inp[WRITE_END], password, strlen (password)); + write (inp[WRITE_END], "\n", 1); + } /* * Note that we're not using select() or any such. We know how the @@ -438,6 +453,8 @@ /* Restore old handler */ sigaction (SIGCHLD, &oldsact, NULL); + close_safe (inp[0]); + close_safe (inp[1]); close_safe (outp[0]); close_safe (outp[1]); close_safe (errp[0]); @@ -450,7 +467,7 @@ } static int -start_daemon_if_necessary (pam_handle_t *ph, struct passwd *pwd) +start_daemon_if_necessary (pam_handle_t *ph, struct passwd *pwd, const char *password) { const char *socket; int ret; @@ -470,7 +487,7 @@ } /* Not running, start process */ - return start_daemon (ph, pwd); + return start_daemon (ph, pwd, password); } static int @@ -691,6 +708,7 @@ struct passwd *pwd; const char *user, *password; const char *socket; + int started_daemon; uint args; int ret; @@ -728,9 +746,11 @@ } + started_daemon = 0; /* Should we start the daemon? */ if (args & ARG_AUTO_START) { - ret = start_daemon_if_necessary (ph, pwd); + started_daemon = 1; + ret = start_daemon_if_necessary (ph, pwd, password); if (ret != PAM_SUCCESS) return ret; } @@ -739,10 +759,12 @@ /* If gnome keyring is running, then unlock now */ if (socket) { - ret = unlock_keyring (ph, pwd, password); - if (ret != PAM_SUCCESS) - return ret; - + /* If we started the daemon, its already unlocked, since we passed the password */ + if (!started_daemon) { + ret = unlock_keyring (ph, pwd, password); + if (ret != PAM_SUCCESS) + return ret; + } /* Otherwise start in open session, store password */ } else { if (pam_set_data (ph, "gkr_system_authtok", strdup (password), @@ -762,6 +784,7 @@ struct passwd *pwd; int ret; uint args = parse_args (argc, argv); + int started_daemon; /* Figure out the user name */ ret = pam_get_user (ph, &user, NULL); @@ -777,29 +800,32 @@ return PAM_SERVICE_ERR; } - /* Should we start the daemon? */ - if (args & ARG_AUTO_START) { - ret = start_daemon_if_necessary (ph, pwd); - if (ret != PAM_SUCCESS) - return ret; - } - /* Get the stored authtok here */ if (pam_get_data (ph, "gkr_system_authtok", (const void**)&password) != PAM_SUCCESS) { - /* * No password, no worries, maybe this (PAM using) application * didn't do authentication, or is hopeless and wants to call * different PAM callbacks from different processes. * * No use complaining - */ - return PAM_SUCCESS; + */ + password = NULL; } - if (unlock_keyring (ph, pwd, password) != PAM_SUCCESS) - return PAM_SERVICE_ERR; + started_daemon = 0; + /* Should we start the daemon? */ + if (args & ARG_AUTO_START) { + started_daemon = 1; + ret = start_daemon_if_necessary (ph, pwd, password); + if (ret != PAM_SUCCESS) + return ret; + } + if (!started_daemon && password != NULL) { + if (unlock_keyring (ph, pwd, password) != PAM_SUCCESS) + return PAM_SERVICE_ERR; + } + return PAM_SUCCESS; } @@ -897,7 +923,7 @@ * argument. Because if the password is being changed, then making * the 'login' keyring match it is a priority. */ - ret = start_daemon_if_necessary (ph, pwd); + ret = start_daemon_if_necessary (ph, pwd, original); if (ret != PAM_SUCCESS) return ret;