--- pam_keyring-0.0.8/src/pam_keyring.c.orig 2007-02-10 21:11:38.000000000 +0100 +++ pam_keyring-0.0.8/src/pam_keyring.c 2007-02-10 21:32:09.000000000 +0100 @@ -48,6 +48,8 @@ #define PAM_USE_FPASS_ARG 0x0002 #define PAM_TRY_FPASS_ARG 0x0004 +static struct sigaction saved_handler = {.sa_handler = SIG_DFL}; + /* ============================ preexec_t ================================== */ typedef struct preexec_t { const char *user; @@ -100,6 +102,38 @@ return ctrl; } +/* spawn_set_sigchld + + Save the old SIGCHLD handler and then set SIGCHLD to SIG_DFL. This is used + against GDM which does not reap childs as we wanted in its SIGCHLD handler, + so we install our own handler. Returns the value from sigaction(). +*/ +static int spawn_set_sigchld(void) { + struct sigaction nh; + + if(saved_handler.sa_handler != SIG_DFL) { + return 0; + } + + memset(&nh, 0, sizeof(nh)); + nh.sa_handler = SIG_DFL; + sigemptyset(&nh.sa_mask); + return sigaction(SIGCHLD, &nh, &saved_handler); +} + + +/* spawn_restore_sigchld + + Restore the SIGCHLD handler that was saved during spawn_set_sigchld(). + Returns the value from sigaction(). +*/ +static int spawn_restore_sigchld(void) { + int ret; + if((ret = sigaction(SIGCHLD, &saved_handler, NULL)) == 0) + saved_handler.sa_handler = SIG_DFL; + return ret; +} + /* ============================ read_password () =========================== */ /* INPUT: pamh; prompt1 * SIDE AFFECTS: pass points to PAM's (user's) response to prompt @@ -231,6 +265,10 @@ cmd_line = g_strdup_printf("%s %d", KILL, pid); + if (spawn_set_sigchld()) { + return FALSE; + } + if (!g_shell_parse_argv(cmd_line, NULL, &argv, &err)) { pam_syslog(pamh, LOG_ERR, "pam_keyring: error parsing %s", cmd_line); goto _return; @@ -248,6 +286,7 @@ goto _return; } _return: + spawn_restore_sigchld(); return retval; } @@ -275,6 +314,13 @@ assert(pamh != NULL); assert(data != NULL); assert(data->user != NULL); + + /* Save current SIGCHLD handler and set it to SIG_DFL to avoid GDM to reap our children */ + if (spawn_set_sigchld()) { + pam_syslog(pamh, LOG_ERR, "pam_keyring: failed to set signal"); + return 0; + } + if (!g_shell_parse_argv(GNOME_KEYRING_DAEMON, NULL, &argv, &err)) { pam_syslog(pamh, LOG_ERR, "pam_keyring: error parsing: %s", GNOME_KEYRING_DAEMON); goto _return; @@ -285,33 +331,40 @@ g_error_free(err); goto _return; } - if (WIFEXITED(status) == 0 && standard_out != NULL) { - lines = g_strsplit(standard_out, "\n", 3); - if (lines[0] != NULL && - lines[1] != NULL && - g_str_has_prefix(lines[1], "GNOME_KEYRING_PID=")) { - pid_str = lines[1] + strlen("GNOME_KEYRING_PID="); - pid = strtol(pid_str, &end, 10); - if (end != pid_str) { - fnval = pid; - /* set variable for ulock operation */ - data->evar = g_strdup(lines[0]); - /* FIXME: memory leak */ - /* ensure variable will be set in login session */ - if (pam_putenv (pamh, g_strdup(lines[0])) != PAM_SUCCESS) { - fnval = 0; - pam_syslog(pamh, LOG_ERR, "pam_keyring: error setting %s", lines[0]); - goto _return; + + if (WIFEXITED(status) && standard_out != NULL) { + if (WEXITSTATUS(status) == 0) { + lines = g_strsplit(standard_out, "\n", 3); + if (lines[0] != NULL && + lines[1] != NULL && + g_str_has_prefix(lines[1], "GNOME_KEYRING_PID=")) { + pid_str = lines[1] + strlen("GNOME_KEYRING_PID="); + pid = strtol(pid_str, &end, 10); + if (end != pid_str) { + fnval = pid; + /* set variable for ulock operation */ + data->evar = g_strdup(lines[0]); + /* FIXME: memory leak */ + /* ensure variable will be set in login session */ + if (pam_putenv (pamh, g_strdup(lines[0])) != PAM_SUCCESS) { + fnval = 0; + pam_syslog(pamh, LOG_ERR, "pam_keyring: error setting %s", lines[0]); + goto _return; + } } } + g_strfreev(lines); + } else { + pam_syslog(pamh, LOG_ERR, "pam_keyring: gnome-keyring-daemon failed to start correctly, exit code: %d", WEXITSTATUS(status)); } - g_strfreev(lines); } else { /* daemon failed for some reason */ - pam_syslog(pamh, LOG_ERR, "pam_keyring: gnome-keyring-daemon failed to start correctly, exit code: %d", WEXITSTATUS(status)); + pam_syslog(pamh, LOG_ERR, "pam_keyring: gnome-keyring-daemon failed to start correctly."); } g_free(standard_out); _return: + /* Restore old signal handler */ + spawn_restore_sigchld(); g_strfreev(argv); return fnval; } @@ -336,6 +389,12 @@ assert(data->user); assert(authtok); + /* Save current SIGCHLD handler and set it to SIG_DFL to avoid GDM to reap our children */ + if (spawn_set_sigchld()) { + pam_syslog(pamh, LOG_ERR, "pam_keyring: failed to set signal"); + return PAM_SERVICE_ERR; + } + if (keyring == NULL) { cmd_line = g_strconcat(PAM_KEYRING_TOOL, " -u -s", NULL); @@ -371,7 +430,9 @@ close(cstderr); retval = WEXITSTATUS(child_exit) ? PAM_SERVICE_ERR : PAM_SUCCESS; _return: - + /* Restore old signal handler */ + spawn_restore_sigchld(); + g_strfreev(argv); g_free(cmd_line); return retval;