X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/9108f8d92b8e2b4b5fe61eb8e419bf94ba216d44..699b5bd687b2564532db9bfc36049045ed79f5ad:/openssh/auth-pam.c?ds=sidebyside diff --git a/openssh/auth-pam.c b/openssh/auth-pam.c index c08d472..90ec372 100644 --- a/openssh/auth-pam.c +++ b/openssh/auth-pam.c @@ -30,7 +30,7 @@ */ /* * Copyright (c) 2003,2004 Damien Miller - * Copyright (c) 2003,2004 Darren Tucker + * Copyright (c) 2003,2004,2006 Darren Tucker * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -161,9 +161,9 @@ sshpam_sigchld_handler(int sig) WTERMSIG(sshpam_thread_status) == SIGTERM) return; /* terminated by pthread_cancel */ if (!WIFEXITED(sshpam_thread_status)) - fatal("PAM: authentication thread exited unexpectedly"); + sigdie("PAM: authentication thread exited unexpectedly"); if (WEXITSTATUS(sshpam_thread_status) != 0) - fatal("PAM: authentication thread exited uncleanly"); + sigdie("PAM: authentication thread exited uncleanly"); } /* ARGSUSED */ @@ -272,6 +272,49 @@ sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags) # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) #endif +struct passwd * +sshpam_getpw(const char *user) +{ + struct passwd *pw; + + if ((pw = getpwnam(user)) != NULL) + return(pw); + + debug("PAM: faking passwd struct for user '%.100s'", user); + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + return NULL; + pw->pw_name = xstrdup(user); /* XXX leak */ + pw->pw_shell = "/bin/true"; + pw->pw_gecos = "sshd fake PAM user"; + return (pw); +} + +void +sshpam_check_userchanged(void) +{ + int sshpam_err; + struct passwd *pw; + const char *user; + + debug("sshpam_check_userchanged"); + sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: could not get PAM_USER: %s", + pam_strerror(sshpam_handle, sshpam_err)); + if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { + debug("PAM: user mapped from '%.100s' to '%.100s'", + sshpam_authctxt->pw->pw_name, user); + if ((pw = getpwnam(user)) == NULL) + fatal("PAM: could not get passwd entry for user " + "'%.100s' provided by PAM_USER", user); + pwfree(sshpam_authctxt->pw); + sshpam_authctxt->pw = pw; + sshpam_authctxt->valid = allowed_user(pw); + debug("PAM: user '%.100s' now %svalid", user, + sshpam_authctxt->valid ? "" : "in"); + } +} + void sshpam_password_change_required(int reqd) { @@ -294,7 +337,7 @@ sshpam_password_change_required(int reqd) static void import_environments(Buffer *b) { - char *env; + char *env, *user; u_int i, num_env; int err; @@ -304,6 +347,15 @@ import_environments(Buffer *b) /* Import variables set by do_pam_account */ sshpam_account_status = buffer_get_int(b); sshpam_password_change_required(buffer_get_int(b)); + if (options.permit_pam_user_change) { + user = buffer_get_string(b, NULL); + debug("PAM: got username '%.100s' from thread", user); + if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS) + fatal("PAM: failed to set PAM_USER: %s", + pam_strerror(sshpam_handle, err)); + pwfree(sshpam_authctxt->pw); + sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); + } /* Import environment from subprocess */ num_env = buffer_get_int(b); @@ -469,6 +521,9 @@ sshpam_thread(void *ctxtp) if (sshpam_err != PAM_SUCCESS) goto auth_fail; + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + } if (compat20) { if (!do_pam_account()) { sshpam_err = PAM_ACCT_EXPIRED; @@ -489,6 +544,9 @@ sshpam_thread(void *ctxtp) /* Export variables set by do_pam_account */ buffer_put_int(&buffer, sshpam_account_status); buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); + if (options.permit_pam_user_change) { + buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name); + } /* Export any environment strings set in child */ for(i = 0; environ[i] != NULL; i++) @@ -598,18 +656,20 @@ static struct pam_conv store_conv = { sshpam_store_conv, NULL }; void sshpam_cleanup(void) { - debug("PAM: cleanup"); - if (sshpam_handle == NULL) + if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor())) return; + debug("PAM: cleanup"); pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); - if (sshpam_cred_established) { - pam_setcred(sshpam_handle, PAM_DELETE_CRED); - sshpam_cred_established = 0; - } if (sshpam_session_open) { + debug("PAM: closing session"); pam_close_session(sshpam_handle, PAM_SILENT); sshpam_session_open = 0; } + if (sshpam_cred_established) { + debug("PAM: deleting credentials"); + pam_setcred(sshpam_handle, PAM_DELETE_CRED); + sshpam_cred_established = 0; + } sshpam_authenticated = 0; pam_end(sshpam_handle, sshpam_err); sshpam_handle = NULL; @@ -686,8 +746,7 @@ sshpam_init_ctx(Authctxt *authctxt) return (NULL); } - ctxt = xmalloc(sizeof *ctxt); - memset(ctxt, 0, sizeof(*ctxt)); + ctxt = xcalloc(1, sizeof *ctxt); /* Start the authentication thread */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { @@ -906,6 +965,12 @@ do_pam_account(void) debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, pam_strerror(sshpam_handle, sshpam_err)); + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) + fatal("PAM: completed authentication but PAM account invalid"); + } + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { sshpam_account_status = 0; return (sshpam_account_status); @@ -985,7 +1050,8 @@ sshpam_tty_conv(int n, sshpam_const struct pam_message **msg, break; case PAM_PROMPT_ECHO_ON: fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); - fgets(input, sizeof input, stdin); + if (fgets(input, sizeof input, stdin) == NULL) + input[0] = '\0'; if ((reply[i].resp = strdup(input)) == NULL) goto fail; reply[i].resp_retcode = PAM_SUCCESS; @@ -1130,9 +1196,8 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg, if (n <= 0 || n > PAM_MAX_NUM_MSG) return (PAM_CONV_ERR); - if ((reply = malloc(n * sizeof(*reply))) == NULL) + if ((reply = calloc(n, sizeof(*reply))) == NULL) return (PAM_CONV_ERR); - memset(reply, 0, n * sizeof(*reply)); for (i = 0; i < n; ++i) { switch (PAM_MSG_MEMBER(msg, i, msg_style)) { @@ -1205,6 +1270,9 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) pam_strerror(sshpam_handle, sshpam_err)); sshpam_err = pam_authenticate(sshpam_handle, flags); + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + } sshpam_password = NULL; if (sshpam_err == PAM_SUCCESS && authctxt->valid) { debug("PAM: password authentication accepted for %.100s",