X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/12408a1b16c3ce5b7e203bec879ceb3d67ae09a8..9cb1827beb97ef775b73d81402cc084ec8c316a3:/openssh/auth-pam.c?ds=sidebyside diff --git a/openssh/auth-pam.c b/openssh/auth-pam.c index 9f0bec0..6d55b75 100644 --- a/openssh/auth-pam.c +++ b/openssh/auth-pam.c @@ -34,11 +34,7 @@ RCSID("$Id$"); #ifdef USE_PAM -#if defined(HAVE_SECURITY_PAM_APPL_H) #include -#elif defined (HAVE_PAM_PAM_APPL_H) -#include -#endif #include "auth.h" #include "auth-pam.h" @@ -56,19 +52,17 @@ RCSID("$Id$"); #include "auth-options.h" extern ServerOptions options; -extern Buffer loginmsg; -extern int compat20; #define __unused #ifdef USE_POSIX_THREADS #include /* - * Avoid namespace clash when *not* using pthreads for systems *with* - * pthreads, which unconditionally define pthread_t via sys/types.h + * Avoid namespace clash when *not* using pthreads for systems *with* + * pthreads, which unconditionally define pthread_t via sys/types.h * (e.g. Linux) */ -typedef pthread_t sp_pthread_t; +typedef pthread_t sp_pthread_t; #else /* * Simulate threads with processes. @@ -123,8 +117,6 @@ static int sshpam_authenticated = 0; static int sshpam_new_authtok_reqd = 0; static int sshpam_session_open = 0; static int sshpam_cred_established = 0; -static int sshpam_account_status = -1; -static char **sshpam_env = NULL; struct pam_ctxt { sp_pthread_t pam_thread; @@ -134,73 +126,6 @@ struct pam_ctxt { }; static void sshpam_free_ctx(void *); -static struct pam_ctxt *cleanup_ctxt; - -/* Some PAM implementations don't implement this */ -#ifndef HAVE_PAM_GETENVLIST -static char ** -pam_getenvlist(pam_handle_t *pamh) -{ - /* - * XXX - If necessary, we can still support envrionment passing - * for platforms without pam_getenvlist by searching for known - * env vars (e.g. KRB5CCNAME) from the PAM environment. - */ - return NULL; -} -#endif - -void -pam_password_change_required(int reqd) -{ - sshpam_new_authtok_reqd = reqd; - if (reqd) { - no_port_forwarding_flag |= 2; - no_agent_forwarding_flag |= 2; - no_x11_forwarding_flag |= 2; - } else { - no_port_forwarding_flag &= ~2; - no_agent_forwarding_flag &= ~2; - no_x11_forwarding_flag &= ~2; - - } -} -/* Import regular and PAM environment from subprocess */ -static void -import_environments(Buffer *b) -{ - char *env; - u_int i, num_env; - int err; - - /* Import variables set by do_pam_account */ - sshpam_account_status = buffer_get_int(b); - pam_password_change_required(buffer_get_int(b)); - - /* Import environment from subprocess */ - num_env = buffer_get_int(b); - sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env)); - debug3("PAM: num env strings %d", num_env); - for(i = 0; i < num_env; i++) - sshpam_env[i] = buffer_get_string(b, NULL); - - sshpam_env[num_env] = NULL; - - /* Import PAM environment from subprocess */ - num_env = buffer_get_int(b); - debug("PAM: num PAM env strings %d", num_env); - for(i = 0; i < num_env; i++) { - env = buffer_get_string(b, NULL); - -#ifdef HAVE_PAM_PUTENV - /* Errors are not fatal here */ - if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { - error("PAM: pam_putenv: %s", - pam_strerror(sshpam_handle, sshpam_err)); - } -#endif - } -} /* * Conversation function for authentication thread. @@ -228,42 +153,36 @@ sshpam_thread_conv(int n, const struct pam_message **msg, for (i = 0; i < n; ++i) { switch (PAM_MSG_MEMBER(msg, i, msg_style)) { case PAM_PROMPT_ECHO_OFF: - buffer_put_cstring(&buffer, + buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg)); - if (ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) - goto fail; - if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) - goto fail; + ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer); + ssh_msg_recv(ctxt->pam_csock, &buffer); if (buffer_get_char(&buffer) != PAM_AUTHTOK) goto fail; reply[i].resp = buffer_get_string(&buffer, NULL); break; case PAM_PROMPT_ECHO_ON: - buffer_put_cstring(&buffer, + buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg)); - if (ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) - goto fail; - if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) - goto fail; + ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer); + ssh_msg_recv(ctxt->pam_csock, &buffer); if (buffer_get_char(&buffer) != PAM_AUTHTOK) goto fail; reply[i].resp = buffer_get_string(&buffer, NULL); break; case PAM_ERROR_MSG: - buffer_put_cstring(&buffer, + buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg)); - if (ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) - goto fail; + ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer); break; case PAM_TEXT_INFO: - buffer_put_cstring(&buffer, + buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg)); - if (ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) - goto fail; + ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer); break; default: goto fail; @@ -294,14 +213,10 @@ sshpam_thread(void *ctxtp) Buffer buffer; struct pam_conv sshpam_conv; #ifndef USE_POSIX_THREADS - extern char **environ; - char **env_from_pam; - u_int i; const char *pam_user; pam_get_item(sshpam_handle, PAM_USER, (const void **)&pam_user); setproctitle("%s [pam]", pam_user); - environ[0] = NULL; #endif sshpam_conv.conv = sshpam_thread_conv; @@ -315,43 +230,7 @@ sshpam_thread(void *ctxtp) sshpam_err = pam_authenticate(sshpam_handle, 0); if (sshpam_err != PAM_SUCCESS) goto auth_fail; - - if (compat20) { - if (!do_pam_account()) - goto auth_fail; - if (sshpam_new_authtok_reqd) { - sshpam_err = pam_chauthtok(sshpam_handle, - PAM_CHANGE_EXPIRED_AUTHTOK); - if (sshpam_err != PAM_SUCCESS) - goto auth_fail; - pam_password_change_required(0); - } - } - buffer_put_cstring(&buffer, "OK"); - -#ifndef USE_POSIX_THREADS - /* Export variables set by do_pam_account */ - buffer_put_int(&buffer, sshpam_account_status); - buffer_put_int(&buffer, sshpam_new_authtok_reqd); - - /* Export any environment strings set in child */ - for(i = 0; environ[i] != NULL; i++) - ; /* Count */ - buffer_put_int(&buffer, i); - for(i = 0; environ[i] != NULL; i++) - buffer_put_cstring(&buffer, environ[i]); - - /* Export any environment strings set by PAM in child */ - env_from_pam = pam_getenvlist(sshpam_handle); - for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) - ; /* Count */ - buffer_put_int(&buffer, i); - for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) - buffer_put_cstring(&buffer, env_from_pam[i]); -#endif /* USE_POSIX_THREADS */ - - /* XXX - can't do much about an error here */ ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); buffer_free(&buffer); pthread_exit(NULL); @@ -359,27 +238,22 @@ sshpam_thread(void *ctxtp) auth_fail: buffer_put_cstring(&buffer, pam_strerror(sshpam_handle, sshpam_err)); - /* XXX - can't do much about an error here */ ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); buffer_free(&buffer); pthread_exit(NULL); - + return (NULL); /* Avoid warning for non-pthread case */ } -void -sshpam_thread_cleanup(void) +static void +sshpam_thread_cleanup(void *ctxtp) { - struct pam_ctxt *ctxt = cleanup_ctxt; - - if (ctxt != NULL && ctxt->pam_thread != 0) { - pthread_cancel(ctxt->pam_thread); - pthread_join(ctxt->pam_thread, NULL); - close(ctxt->pam_psock); - close(ctxt->pam_csock); - memset(ctxt, 0, sizeof(*ctxt)); - cleanup_ctxt = NULL; - } + struct pam_ctxt *ctxt = ctxtp; + + pthread_cancel(ctxt->pam_thread); + pthread_join(ctxt->pam_thread, NULL); + close(ctxt->pam_psock); + close(ctxt->pam_csock); } static int @@ -391,9 +265,10 @@ sshpam_null_conv(int n, const struct pam_message **msg, static struct pam_conv null_conv = { sshpam_null_conv, NULL }; -void -sshpam_cleanup(void) +static void +sshpam_cleanup(void *arg) { + (void)arg; debug("PAM: cleanup"); if (sshpam_handle == NULL) return; @@ -424,6 +299,7 @@ sshpam_init(const char *user) PAM_USER, (const void **)&pam_user); if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) return (0); + fatal_remove_cleanup(sshpam_cleanup, NULL); pam_end(sshpam_handle, sshpam_err); sshpam_handle = NULL; } @@ -444,11 +320,11 @@ sshpam_init(const char *user) return (-1); } #ifdef PAM_TTY_KLUDGE - /* - * Some silly PAM modules (e.g. pam_time) require a TTY to operate. - * sshd doesn't set the tty until too late in the auth process and + /* + * Some silly PAM modules (e.g. pam_time) require a TTY to operate. + * sshd doesn't set the tty until too late in the auth process and * may not even set one (for tty-less connections) - */ + */ debug("PAM: setting PAM_TTY to \"ssh\""); sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); if (sshpam_err != PAM_SUCCESS) { @@ -457,6 +333,7 @@ sshpam_init(const char *user) return (-1); } #endif + fatal_add_cleanup(sshpam_cleanup, NULL); return (0); } @@ -477,7 +354,7 @@ sshpam_init_ctx(Authctxt *authctxt) } ctxt = xmalloc(sizeof *ctxt); - memset(ctxt, 0, sizeof(*ctxt)); + ctxt->pam_done = 0; /* Start the authentication thread */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { @@ -495,7 +372,7 @@ sshpam_init_ctx(Authctxt *authctxt) xfree(ctxt); return (NULL); } - cleanup_ctxt = ctxt; + fatal_add_cleanup(sshpam_thread_cleanup, ctxt); return (ctxt); } @@ -533,23 +410,26 @@ sshpam_query(void *ctx, char **name, char **info, case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* accumulate messages */ - len = plen + strlen(msg) + 2; + len = plen + strlen(msg) + 1; **prompts = xrealloc(**prompts, len); - plen += snprintf(**prompts + plen, len, "%s\n", msg); + plen += snprintf(**prompts + plen, len, "%s", msg); xfree(msg); break; case PAM_SUCCESS: case PAM_AUTH_ERR: if (**prompts != NULL) { /* drain any accumulated messages */ - debug("PAM: %s", **prompts); - buffer_append(&loginmsg, **prompts, - strlen(**prompts)); +#if 0 /* XXX - not compatible with privsep */ + packet_start(SSH2_MSG_USERAUTH_BANNER); + packet_put_cstring(**prompts); + packet_put_cstring(""); + packet_send(); + packet_write_wait(); +#endif xfree(**prompts); **prompts = NULL; } if (type == PAM_SUCCESS) { - import_environments(&buffer); *num = 0; **echo_on = 0; ctxt->pam_done = 1; @@ -557,7 +437,6 @@ sshpam_query(void *ctx, char **name, char **info, return (0); } error("PAM: %s", msg); - /* FALLTHROUGH */ default: *num = 0; **echo_on = 0; @@ -592,10 +471,7 @@ sshpam_respond(void *ctx, u_int num, char **resp) } buffer_init(&buffer); buffer_put_cstring(&buffer, *resp); - if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { - buffer_free(&buffer); - return (-1); - } + ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer); buffer_free(&buffer); return (1); } @@ -605,7 +481,8 @@ sshpam_free_ctx(void *ctxtp) { struct pam_ctxt *ctxt = ctxtp; - sshpam_thread_cleanup(); + fatal_remove_cleanup(sshpam_thread_cleanup, ctxt); + sshpam_thread_cleanup(ctxtp); xfree(ctxt); /* * We don't call sshpam_cleanup() here because we may need the PAM @@ -647,28 +524,44 @@ start_pam(const char *user) void finish_pam(void) { - sshpam_cleanup(); + fatal_remove_cleanup(sshpam_cleanup, NULL); + sshpam_cleanup(NULL); } u_int do_pam_account(void) { - if (sshpam_account_status != -1) - return (sshpam_account_status); - sshpam_err = pam_acct_mgmt(sshpam_handle, 0); debug3("%s: pam_acct_mgmt = %d", __func__, sshpam_err); - if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { - sshpam_account_status = 0; - return (sshpam_account_status); + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) + return (0); + + if (sshpam_err == PAM_NEW_AUTHTOK_REQD) { + sshpam_new_authtok_reqd = 1; + + /* Prevent forwardings until password changed */ + no_port_forwarding_flag |= 2; + no_agent_forwarding_flag |= 2; + no_x11_forwarding_flag |= 2; } - if (sshpam_err == PAM_NEW_AUTHTOK_REQD) - pam_password_change_required(1); + return (1); +} - sshpam_account_status = 1; - return (sshpam_account_status); +void +do_pam_session(void) +{ + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&null_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: failed to set PAM_CONV: %s", + pam_strerror(sshpam_handle, sshpam_err)); + sshpam_err = pam_open_session(sshpam_handle, 0); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: pam_open_session(): %s", + pam_strerror(sshpam_handle, sshpam_err)); + sshpam_session_open = 1; } void @@ -717,7 +610,7 @@ is_pam_password_change_required(void) } static int -pam_tty_conv(int n, const struct pam_message **msg, +pam_chauthtok_conv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { char input[PAM_MAX_MSG_SIZE]; @@ -726,7 +619,7 @@ pam_tty_conv(int n, const struct pam_message **msg, *resp = NULL; - if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) + if (n <= 0 || n > PAM_MAX_NUM_MSG) return (PAM_CONV_ERR); if ((reply = malloc(n * sizeof(*reply))) == NULL) @@ -737,19 +630,19 @@ pam_tty_conv(int n, const struct pam_message **msg, switch (PAM_MSG_MEMBER(msg, i, msg_style)) { case PAM_PROMPT_ECHO_OFF: reply[i].resp = - read_passphrase(PAM_MSG_MEMBER(msg, i, msg), + read_passphrase(PAM_MSG_MEMBER(msg, i, msg), RP_ALLOW_STDIN); reply[i].resp_retcode = PAM_SUCCESS; break; case PAM_PROMPT_ECHO_ON: - fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); + fputs(PAM_MSG_MEMBER(msg, i, msg), stderr); fgets(input, sizeof input, stdin); reply[i].resp = xstrdup(input); reply[i].resp_retcode = PAM_SUCCESS; break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: - fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); + fputs(PAM_MSG_MEMBER(msg, i, msg), stderr); reply[i].resp_retcode = PAM_SUCCESS; break; default: @@ -768,8 +661,6 @@ pam_tty_conv(int n, const struct pam_message **msg, return (PAM_CONV_ERR); } -static struct pam_conv tty_conv = { pam_tty_conv, NULL }; - /* * XXX this should be done in the authentication phase, but ssh1 doesn't * support that @@ -777,10 +668,15 @@ static struct pam_conv tty_conv = { pam_tty_conv, NULL }; void do_pam_chauthtok(void) { + struct pam_conv pam_conv; + + pam_conv.conv = pam_chauthtok_conv; + pam_conv.appdata_ptr = NULL; + if (use_privsep) fatal("Password expired (unable to change with privsep)"); sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, - (const void *)&tty_conv); + (const void *)&pam_conv); if (sshpam_err != PAM_SUCCESS) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); @@ -791,31 +687,17 @@ do_pam_chauthtok(void) pam_strerror(sshpam_handle, sshpam_err)); } -void -do_pam_session(void) -{ - sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, - (const void *)&tty_conv); - if (sshpam_err != PAM_SUCCESS) - fatal("PAM: failed to set PAM_CONV: %s", - pam_strerror(sshpam_handle, sshpam_err)); - sshpam_err = pam_open_session(sshpam_handle, 0); - if (sshpam_err != PAM_SUCCESS) - fatal("PAM: pam_open_session(): %s", - pam_strerror(sshpam_handle, sshpam_err)); - sshpam_session_open = 1; -} - -/* +/* * Set a PAM environment string. We need to do this so that the session * modules can handle things like Kerberos/GSI credentials that appear * during the ssh authentication process. */ + int -do_pam_putenv(char *name, char *value) +do_pam_putenv(char *name, char *value) { int ret = 1; -#ifdef HAVE_PAM_PUTENV +#ifdef HAVE_PAM_PUTENV char *compound; size_t len; @@ -836,16 +718,15 @@ print_pam_messages(void) /* XXX */ } -char ** -fetch_pam_child_environment(void) -{ - return sshpam_env; -} - char ** fetch_pam_environment(void) { +#ifdef HAVE_PAM_GETENVLIST + debug("PAM: retrieving environment"); return (pam_getenvlist(sshpam_handle)); +#else + return (NULL); +#endif } void