Package: libpam-ssh
Version: 1.91.0-6
Followup-For: Bug #294181
If at first it cannot connect to an agent, it removes the old
per-agent file and tries again. If fails again (shouldn't happen)
gives up.
-- System Information:
Debian Release: 3.1
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: i386 (i686)
Kernel: Linux 2.6.10-pisicuta-7
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Versions of packages libpam-ssh depends on:
ii libc6 2.3.2.ds1-20 GNU C Library: Shared libraries an
ii libpam0g 0.76-22 Pluggable Authentication Modules l
ii libssl0.9.7 0.9.7e-3 SSL shared libraries
-- no debconf information
--- libpam-ssh-1.91.0.orig/pam_ssh.c 2004-04-12 08:55:08.000000000 -0500
+++ libpam-ssh-1.91.0/pam_ssh.c 2005-04-03 21:18:58.140936716 -0500
@@ -279,9 +279,8 @@
*/
static int
-add_keys(pam_handle_t *pamh, char *socket)
+add_keys(pam_handle_t *pamh, AuthenticationConnection *ac)
{
- AuthenticationConnection *ac; /* connection to ssh-agent */
char *comment; /* private key comment */
char *data_name; /* PAM state */
int final; /* final return value */
@@ -289,13 +288,6 @@
Key *key; /* user's private key */
int retval; /* from calls */
- /* connect to the agent */
-
- if (!(ac = ssh_get_authentication_connection(socket))) {
- pam_ssh_log(LOG_ERR, "%s: %m", socket);
- return PAM_SESSION_ERR;
- }
-
/* hand off each private key to the agent */
final = 0;
@@ -324,11 +316,177 @@
if (!final)
final = retval;
}
- ssh_close_authentication_connection(ac);
return final ? PAM_SUCCESS : PAM_SESSION_ERR;
}
+static int
+start_ssh_agent(pam_handle_t *pamh, uid_t uid, FILE **env_read)
+{
+ pid_t child_pid; /* child process that spawns agent */
+ int child_pipe[2]; /* pipe to child process */
+ int child_status; /* child process status */
+ char *arg[3], *env[1]; /* to pass to execve() */
+
+ if (pipe(child_pipe) < 0) {
+ pam_ssh_log(LOG_ERR, "pipe: %m");
+ return PAM_SERVICE_ERR;
+ }
+ switch (child_pid = fork()) {
+ case -1: /* error */
+ pam_ssh_log(LOG_ERR, "fork: %m");
+ close(child_pipe[0]);
+ close(child_pipe[1]);
+ return PAM_SERVICE_ERR;
+ /* NOTREACHED */
+ case 0: /* child */
+
+ /* Permanently drop privileges using setuid()
+ before executing ssh-agent so that root
+ privileges can't possibly be regained (some
+ ssh-agents insist that euid == ruid
+ anyway). System V won't let us use
+ setuid() unless euid == 0, so we
+ temporarily regain root privileges first
+ with openpam_restore_cred() (which calls
+ seteuid()). */
+
+ switch (openpam_restore_cred(pamh)) {
+ case PAM_SYSTEM_ERR:
+ pam_ssh_log(LOG_ERR,
+ "can't restore privileges: %m");
+ _exit(EX_OSERR);
+ /* NOTREACHED */
+ case PAM_SUCCESS:
+ if (setuid(uid) == -1) {
+ pam_ssh_log(LOG_ERR,
+ "can't drop privileges: %m",
+ uid);
+ _exit(EX_NOPERM);
+ }
+ break;
+ }
+
+ if (close(child_pipe[0]) == -1) {
+ pam_ssh_log(LOG_ERR, "close: %m");
+ _exit(EX_OSERR);
+ }
+ if (child_pipe[1] != STDOUT_FILENO) {
+ if (dup2(child_pipe[1], STDOUT_FILENO) == -1) {
+ pam_ssh_log(LOG_ERR, "dup: %m");
+ _exit(EX_OSERR);
+ }
+ if (close(child_pipe[1]) == -1) {
+ pam_ssh_log(LOG_ERR, "close: %m");
+ _exit(EX_OSERR);
+ }
+ }
+ arg[0] = "ssh-agent";
+ arg[1] = "-s";
+ arg[2] = NULL;
+ env[0] = NULL;
+ execve(PATH_SSH_AGENT, arg, env);
+ pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
+ _exit(127);
+ /* NOTREACHED */
+ }
+ if (close(child_pipe[1]) == -1) {
+ pam_ssh_log(LOG_ERR, "close: %m");
+ return PAM_SESSION_ERR;
+ }
+ if (!(*env_read = fdopen(child_pipe[0], "r"))) {
+ pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
+ return PAM_SESSION_ERR;
+ }
+
+ child_status = 0;
+ if (waitpid_intr(child_pid, &child_status, 0) == -1 &&
+ errno != ECHILD) {
+ pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
+ return PAM_SESSION_ERR;
+ }
+
+ if (child_status != 0) {
+ if (WIFSIGNALED(child_status))
+ pam_ssh_log(LOG_ERR, "%s exited on signal %d",
+ PATH_SSH_AGENT, WTERMSIG(child_status));
+ else
+ if (WEXITSTATUS(child_status) == 127)
+ pam_ssh_log(LOG_ERR,
+ "cannot execute %s",
+ PATH_SSH_AGENT);
+ else
+ pam_ssh_log(LOG_ERR,
+ "%s exited with status %d",
+ PATH_SSH_AGENT,
+ WEXITSTATUS(child_status));
+ return PAM_SESSION_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
+
+static int
+read_write_agent_env(pam_handle_t *pamh,
+ FILE *env_read,
+ int env_write,
+ char **agent_socket)
+{
+ char *agent_pid; /* copy of agent PID */
+ char *env_end; /* end of env */
+ char env_string[BUFSIZ]; /* environment string */
+ char *env_value; /* envariable value */
+ int retval; /* from calls */
+
+ while (fgets(env_string, sizeof env_string, env_read)) {
+
+ /* parse environment definitions */
+
+ if (env_write >= 0)
+ write(env_write, env_string, strlen(env_string));
+ if (!(env_value = strchr(env_string, '=')) ||
+ !(env_end = strchr(env_value, ';')))
+ continue;
+ *env_end = '\0';
+
+ /* pass to the application */
+
+ if ((retval = pam_putenv(pamh, env_string)) != PAM_SUCCESS)
+ return retval;
+
+ *env_value++ = '\0';
+
+ /* save the agent socket so we can connect to it and add
+ the keys as well as the PID so we can kill the agent on
+ session close. */
+
+ agent_pid = NULL;
+ if (strcmp(&env_string[strlen(env_string) -
+ strlen(ENV_SOCKET_SUFFIX)], ENV_SOCKET_SUFFIX) == 0 &&
+ !(*agent_socket = strdup(env_value))) {
+ pam_ssh_log(LOG_CRIT, "out of memory");
+ return PAM_SERVICE_ERR;
+ } else if (strcmp(&env_string[strlen(env_string) -
+ strlen(ENV_PID_SUFFIX)], ENV_PID_SUFFIX) == 0 &&
+ (!(agent_pid = strdup(env_value)) ||
+ (retval = pam_set_data(pamh, "ssh_agent_pid",
+ agent_pid, ssh_cleanup)) != PAM_SUCCESS)) {
+ if (agent_pid)
+ free(agent_pid);
+ else {
+ pam_ssh_log(LOG_CRIT, "out of memory");
+ return PAM_SERVICE_ERR;
+ }
+ if (agent_socket)
+ free(agent_socket);
+ return retval;
+ }
+
+ }
+
+ return PAM_SUCCESS;
+}
+
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc,
@@ -494,17 +652,10 @@
pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char **argv __unused)
{
- char *agent_pid; /* copy of agent PID */
+ AuthenticationConnection *ac; /* connection to ssh-agent */
char *agent_socket; /* agent socket */
- char *arg[3], *env[1]; /* to pass to execve() */
- pid_t child_pid; /* child process that spawns agent */
- int child_pipe[2]; /* pipe to child process */
- int child_status; /* child process status */
char *cp; /* scratch */
- char *env_end; /* end of env */
FILE *env_read; /* env data source */
- char env_string[BUFSIZ]; /* environment string */
- char *env_value; /* envariable value */
int env_write; /* env file descriptor */
char hname[MAXHOSTNAMELEN]; /* local hostname */
int no_link; /* link per-agent file? */
@@ -515,6 +666,7 @@
int start_agent; /* start agent? */
const char *tty_raw; /* raw tty or display name */
char *tty_nodir; /* tty without / chars */
+ int attempt; /* No. of attempt to contact agent */
log_init(MODULE_NAME, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTHPRIV, 0);
@@ -568,215 +720,70 @@
per-session filename later. Start the agent if we can't open
the file for reading. */
- env_write = child_pid = no_link = start_agent = 0;
- env_read = NULL;
- if ((env_write = open(per_agent, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR))
- < 0 && !(env_read = fopen(per_agent, "r")))
- no_link = 1;
- if (!env_read) {
- start_agent = 1;
- if (pipe(child_pipe) < 0) {
- pam_ssh_log(LOG_ERR, "pipe: %m");
- close(env_write);
- openpam_restore_cred(pamh);
- return PAM_SERVICE_ERR;
- }
- switch (child_pid = fork()) {
- case -1: /* error */
- pam_ssh_log(LOG_ERR, "fork: %m");
- close(child_pipe[0]);
- close(child_pipe[1]);
- close(env_write);
- openpam_restore_cred(pamh);
- return PAM_SERVICE_ERR;
- /* NOTREACHED */
- case 0: /* child */
-
- /* Permanently drop privileges using setuid()
- before executing ssh-agent so that root
- privileges can't possibly be regained (some
- ssh-agents insist that euid == ruid
- anyway). System V won't let us use
- setuid() unless euid == 0, so we
- temporarily regain root privileges first
- with openpam_restore_cred() (which calls
- seteuid()). */
-
- switch (openpam_restore_cred(pamh)) {
- case PAM_SYSTEM_ERR:
- pam_ssh_log(LOG_ERR,
- "can't restore privileges: %m");
- _exit(EX_OSERR);
- /* NOTREACHED */
- case PAM_SUCCESS:
- if (setuid(pwent->pw_uid) == -1) {
- pam_ssh_log(LOG_ERR,
- "can't drop privileges: %m",
- pwent->pw_uid);
- _exit(EX_NOPERM);
- }
- break;
- }
-
- if (close(child_pipe[0]) == -1) {
- pam_ssh_log(LOG_ERR, "close: %m");
- _exit(EX_OSERR);
- }
- if (child_pipe[1] != STDOUT_FILENO) {
- if (dup2(child_pipe[1], STDOUT_FILENO) == -1) {
- pam_ssh_log(LOG_ERR, "dup: %m");
- _exit(EX_OSERR);
- }
- if (close(child_pipe[1]) == -1) {
- pam_ssh_log(LOG_ERR, "close: %m");
- _exit(EX_OSERR);
- }
+ for ( attempt = 0; attempt < 2; ++attempt ) {
+ env_write = no_link = start_agent = 0;
+ env_read = NULL;
+ if ((env_write = open(per_agent, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR))
+ < 0 && !(env_read = fopen(per_agent, "r")))
+ no_link = 1;
+ if (!env_read) {
+ start_agent = 1;
+ if ((retval = start_ssh_agent(pamh, pwent->pw_uid, &env_read))
+ != PAM_SUCCESS) {
+ close(env_write);
+ openpam_restore_cred(pamh);
+ return retval;
}
- arg[0] = "ssh-agent";
- arg[1] = "-s";
- arg[2] = NULL;
- env[0] = NULL;
- execve(PATH_SSH_AGENT, arg, env);
- pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
- _exit(127);
- /* NOTREACHED */
- }
- if (close(child_pipe[1]) == -1) {
- pam_ssh_log(LOG_ERR, "close: %m");
- openpam_restore_cred(pamh);
- return PAM_SESSION_ERR;
- }
- if (!(env_read = fdopen(child_pipe[0], "r"))) {
- pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
- close(env_write);
- openpam_restore_cred(pamh);
- return PAM_SESSION_ERR;
- }
- }
-
- /* save environment for application with pam_putenv() */
-
- agent_socket = NULL;
- while (fgets(env_string, sizeof env_string, env_read)) {
-
- /* parse environment definitions */
-
- if (env_write >= 0)
- write(env_write, env_string, strlen(env_string));
- if (!(env_value = strchr(env_string, '=')) ||
- !(env_end = strchr(env_value, ';')))
- continue;
- *env_end = '\0';
-
- /* pass to the application */
-
- if ((retval = pam_putenv(pamh, env_string)) != PAM_SUCCESS) {
- fclose(env_read);
- if (start_agent)
- waitpid_intr(child_pid, &child_status, 0);
- close(env_write);
- if (agent_socket)
- free(agent_socket);
- openpam_restore_cred(pamh);
- return retval;
}
- *env_value++ = '\0';
-
- /* save the agent socket so we can connect to it and add
- the keys as well as the PID so we can kill the agent on
- session close. */
-
- agent_pid = NULL;
- if (strcmp(&env_string[strlen(env_string) -
- strlen(ENV_SOCKET_SUFFIX)], ENV_SOCKET_SUFFIX) == 0 &&
- !(agent_socket = strdup(env_value))) {
- pam_ssh_log(LOG_CRIT, "out of memory");
- fclose(env_read);
- if (start_agent)
- waitpid_intr(child_pid, &child_status, 0);
- close(env_write);
+ agent_socket = NULL;
+ retval = read_write_agent_env(pamh, env_read, env_write, &agent_socket);
+ close(env_write);
+ if (retval != PAM_SUCCESS) {
if (agent_socket)
free(agent_socket);
- openpam_restore_cred(pamh);
- return PAM_SERVICE_ERR;
- } else if (strcmp(&env_string[strlen(env_string) -
- strlen(ENV_PID_SUFFIX)], ENV_PID_SUFFIX) == 0 &&
- (!(agent_pid = strdup(env_value)) ||
- (retval = pam_set_data(pamh, "ssh_agent_pid",
- agent_pid, ssh_cleanup)) != PAM_SUCCESS)) {
fclose(env_read);
- if (start_agent)
- waitpid_intr(child_pid, &child_status, 0);
- close(env_write);
- if (agent_pid)
- free(agent_pid);
- else {
- pam_ssh_log(LOG_CRIT, "out of memory");
- openpam_restore_cred(pamh);
- return PAM_SERVICE_ERR;
- }
- if (agent_socket)
- free(agent_socket);
openpam_restore_cred(pamh);
return retval;
}
- }
- close(env_write);
-
- if (fclose(env_read) != 0) {
- pam_ssh_log(LOG_ERR, "fclose: %m");
- openpam_restore_cred(pamh);
- return PAM_SESSION_ERR;
- }
-
- if (start_agent) {
-
- /* Ignore ECHILD in case a SIGCHLD handler is installed. */
-
- child_status = 0;
- if (waitpid_intr(child_pid, &child_status, 0) == -1 &&
- errno != ECHILD) {
- pam_ssh_log(LOG_ERR, "%s: %m", PATH_SSH_AGENT);
+ if (fclose(env_read) != 0) {
+ pam_ssh_log(LOG_ERR, "fclose: %m");
if (agent_socket)
free(agent_socket);
openpam_restore_cred(pamh);
return PAM_SESSION_ERR;
}
- if (child_status != 0) {
- if (WIFSIGNALED(child_status))
- pam_ssh_log(LOG_ERR, "%s exited on signal %d",
- PATH_SSH_AGENT, WTERMSIG(child_status));
- else
- if (WEXITSTATUS(retval) == 127)
- pam_ssh_log(LOG_ERR,
- "cannot execute %s",
- PATH_SSH_AGENT);
- else
- pam_ssh_log(LOG_ERR,
- "%s exited with status %d",
- PATH_SSH_AGENT,
- WEXITSTATUS(child_status));
- if (agent_socket)
- free(agent_socket);
+ if (!agent_socket) {
openpam_restore_cred(pamh);
return PAM_SESSION_ERR;
}
+
+ ac = ssh_get_authentication_connection(agent_socket);
+ if (ac) {
+ free(agent_socket);
+ break;
+ }
+ pam_ssh_log(LOG_ERR, "%s: %m", agent_socket);
+ free(agent_socket);
+ if (start_agent)
+ break;
+ unlink(per_agent);
}
- if (!agent_socket) {
- openpam_restore_cred(pamh);
+ if (!ac)
return PAM_SESSION_ERR;
- }
- if (start_agent && (retval = add_keys(pamh, agent_socket))
- != PAM_SUCCESS) {
+ if (start_agent)
+ retval = add_keys(pamh, ac);
+
+ ssh_close_authentication_connection(ac);
+
+ if (start_agent && retval != PAM_SUCCESS) {
openpam_restore_cred(pamh);
return retval;
}
- free(agent_socket);
/* if we couldn't access the per-agent file, don't link a
per-session filename to it */