X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/b86c3c30e252d7d65f3965b9e1c8e7ddc715c0ab..cdd66111973295c976f1a0bb57f571eba0513757:/openssh/auth-pam.c?ds=sidebyside diff --git a/openssh/auth-pam.c b/openssh/auth-pam.c index 6d55b75..7157e72 100644 --- a/openssh/auth-pam.c +++ b/openssh/auth-pam.c @@ -34,7 +34,11 @@ 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" @@ -52,22 +56,54 @@ RCSID("$Id$"); #include "auth-options.h" extern ServerOptions options; - -#define __unused +extern Buffer loginmsg; +extern int compat20; #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 +typedef pid_t sp_pthread_t; +#endif + +struct pam_ctxt { + sp_pthread_t pam_thread; + int pam_psock; + int pam_csock; + int pam_done; +}; + +static void sshpam_free_ctx(void *); +static struct pam_ctxt *cleanup_ctxt; + +#ifndef USE_POSIX_THREADS /* * Simulate threads with processes. */ -typedef pid_t sp_pthread_t; + +static int sshpam_thread_status = -1; +static mysig_t sshpam_oldsig; + +static void +sshpam_sigchld_handler(int sig) +{ + if (cleanup_ctxt == NULL) + return; /* handler called after PAM cleanup, shouldn't happen */ + if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) == -1) + return; /* couldn't wait for process */ + if (WIFSIGNALED(sshpam_thread_status) && + WTERMSIG(sshpam_thread_status) == SIGTERM) + return; /* terminated by pthread_cancel */ + if (!WIFEXITED(sshpam_thread_status)) + fatal("PAM: authentication thread exited unexpectedly"); + if (WEXITSTATUS(sshpam_thread_status) != 0) + fatal("PAM: authentication thread exited uncleanly"); +} static void pthread_exit(void *value __unused) @@ -90,6 +126,7 @@ pthread_create(sp_pthread_t *thread, const void *attr __unused, _exit(1); default: *thread = pid; + sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); return (0); } } @@ -97,6 +134,7 @@ pthread_create(sp_pthread_t *thread, const void *attr __unused, static int pthread_cancel(sp_pthread_t thread) { + signal(SIGCHLD, sshpam_oldsig); return (kill(thread, SIGTERM)); } @@ -105,6 +143,9 @@ pthread_join(sp_pthread_t thread, void **value __unused) { int status; + if (sshpam_thread_status != -1) + return (sshpam_thread_status); + signal(SIGCHLD, sshpam_oldsig); waitpid(thread, &status, 0); return (status); } @@ -114,18 +155,80 @@ pthread_join(sp_pthread_t thread, void **value __unused) static pam_handle_t *sshpam_handle = NULL; static int sshpam_err = 0; 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; +static int *force_pwchange; + +/* 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 -struct pam_ctxt { - sp_pthread_t pam_thread; - int pam_psock; - int pam_csock; - int pam_done; -}; +void +pam_password_change_required(int reqd) +{ + debug3("%s %d", __func__, reqd); + *force_pwchange = 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; + } +} -static void sshpam_free_ctx(void *); +/* Import regular and PAM environment from subprocess */ +static void +import_environments(Buffer *b) +{ + char *env; + u_int i, num_env; + int err; + + debug3("PAM: %s entering", __func__); + + /* 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. @@ -139,6 +242,7 @@ sshpam_thread_conv(int n, const struct pam_message **msg, struct pam_response *reply; int i; + debug3("PAM: %s entering, %d messages", __func__, n); *resp = NULL; ctxt = data; @@ -153,36 +257,42 @@ 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)); - ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer); - ssh_msg_recv(ctxt->pam_csock, &buffer); + 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; 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)); - ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer); - ssh_msg_recv(ctxt->pam_csock, &buffer); + 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; 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)); - ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; break; case PAM_TEXT_INFO: - buffer_put_cstring(&buffer, + buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg)); - ssh_msg_send(ctxt->pam_csock, - PAM_MSG_MEMBER(msg, i, msg_style), &buffer); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; break; default: goto fail; @@ -213,10 +323,14 @@ 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; @@ -230,7 +344,43 @@ 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 (*force_pwchange) { + 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, *force_pwchange); + + /* 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); @@ -238,37 +388,43 @@ 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 */ } -static void -sshpam_thread_cleanup(void *ctxtp) +void +sshpam_thread_cleanup(void) { - struct pam_ctxt *ctxt = ctxtp; - - pthread_cancel(ctxt->pam_thread); - pthread_join(ctxt->pam_thread, NULL); - close(ctxt->pam_psock); - close(ctxt->pam_csock); + struct pam_ctxt *ctxt = cleanup_ctxt; + + debug3("PAM: %s entering", __func__); + 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; + } } static int sshpam_null_conv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { + debug3("PAM: %s entering, %d messages", __func__, n); return (PAM_CONV_ERR); } static struct pam_conv null_conv = { sshpam_null_conv, NULL }; -static void -sshpam_cleanup(void *arg) +void +sshpam_cleanup(void) { - (void)arg; debug("PAM: cleanup"); if (sshpam_handle == NULL) return; @@ -281,7 +437,7 @@ sshpam_cleanup(void *arg) pam_close_session(sshpam_handle, PAM_SILENT); sshpam_session_open = 0; } - sshpam_authenticated = sshpam_new_authtok_reqd = 0; + sshpam_authenticated = 0; pam_end(sshpam_handle, sshpam_err); sshpam_handle = NULL; } @@ -299,7 +455,6 @@ 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; } @@ -320,11 +475,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) { @@ -333,7 +488,6 @@ sshpam_init(const char *user) return (-1); } #endif - fatal_add_cleanup(sshpam_cleanup, NULL); return (0); } @@ -343,6 +497,7 @@ sshpam_init_ctx(Authctxt *authctxt) struct pam_ctxt *ctxt; int socks[2]; + debug3("PAM: %s entering", __func__); /* Refuse to start if we don't have PAM enabled */ if (!options.use_pam) return NULL; @@ -354,7 +509,9 @@ sshpam_init_ctx(Authctxt *authctxt) } ctxt = xmalloc(sizeof *ctxt); - ctxt->pam_done = 0; + memset(ctxt, 0, sizeof(*ctxt)); + + force_pwchange = &(authctxt->force_pwchange); /* Start the authentication thread */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { @@ -372,7 +529,7 @@ sshpam_init_ctx(Authctxt *authctxt) xfree(ctxt); return (NULL); } - fatal_add_cleanup(sshpam_thread_cleanup, ctxt); + cleanup_ctxt = ctxt; return (ctxt); } @@ -387,6 +544,7 @@ sshpam_query(void *ctx, char **name, char **info, char *msg; size_t len; + debug3("PAM: %s entering", __func__); buffer_init(&buffer); *name = xstrdup(""); *info = xstrdup(""); @@ -410,26 +568,23 @@ sshpam_query(void *ctx, char **name, char **info, case PAM_ERROR_MSG: case PAM_TEXT_INFO: /* accumulate messages */ - len = plen + strlen(msg) + 1; + len = plen + strlen(msg) + 2; **prompts = xrealloc(**prompts, len); - plen += snprintf(**prompts + plen, len, "%s", msg); + plen += snprintf(**prompts + plen, len, "%s\n", msg); xfree(msg); break; case PAM_SUCCESS: case PAM_AUTH_ERR: if (**prompts != NULL) { /* drain any accumulated messages */ -#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 + debug("PAM: %s", **prompts); + buffer_append(&loginmsg, **prompts, + strlen(**prompts)); xfree(**prompts); **prompts = NULL; } if (type == PAM_SUCCESS) { + import_environments(&buffer); *num = 0; **echo_on = 0; ctxt->pam_done = 1; @@ -437,6 +592,7 @@ sshpam_query(void *ctx, char **name, char **info, return (0); } error("PAM: %s", msg); + /* FALLTHROUGH */ default: *num = 0; **echo_on = 0; @@ -455,7 +611,7 @@ sshpam_respond(void *ctx, u_int num, char **resp) Buffer buffer; struct pam_ctxt *ctxt = ctx; - debug2("PAM: %s", __func__); + debug2("PAM: %s entering, %d responses", __func__, num); switch (ctxt->pam_done) { case 1: sshpam_authenticated = 1; @@ -471,7 +627,10 @@ sshpam_respond(void *ctx, u_int num, char **resp) } buffer_init(&buffer); buffer_put_cstring(&buffer, *resp); - ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer); + if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { + buffer_free(&buffer); + return (-1); + } buffer_free(&buffer); return (1); } @@ -481,8 +640,8 @@ sshpam_free_ctx(void *ctxtp) { struct pam_ctxt *ctxt = ctxtp; - fatal_remove_cleanup(sshpam_thread_cleanup, ctxt); - sshpam_thread_cleanup(ctxtp); + debug3("PAM: %s entering", __func__); + sshpam_thread_cleanup(); xfree(ctxt); /* * We don't call sshpam_cleanup() here because we may need the PAM @@ -524,44 +683,28 @@ start_pam(const char *user) void finish_pam(void) { - fatal_remove_cleanup(sshpam_cleanup, NULL); - sshpam_cleanup(NULL); + sshpam_cleanup(); } 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); + debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err); - 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_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { + sshpam_account_status = 0; + return (sshpam_account_status); } - return (1); -} + if (sshpam_err == PAM_NEW_AUTHTOK_REQD) + pam_password_change_required(1); -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; + sshpam_account_status = 1; + return (sshpam_account_status); } void @@ -603,23 +746,19 @@ do_pam_setcred(int init) pam_strerror(sshpam_handle, sshpam_err)); } -int -is_pam_password_change_required(void) -{ - return (sshpam_new_authtok_reqd); -} - static int -pam_chauthtok_conv(int n, const struct pam_message **msg, +pam_tty_conv(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { char input[PAM_MAX_MSG_SIZE]; struct pam_response *reply; int i; + debug3("PAM: %s called with %d messages", __func__, n); + *resp = NULL; - if (n <= 0 || n > PAM_MAX_NUM_MSG) + if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) return (PAM_CONV_ERR); if ((reply = malloc(n * sizeof(*reply))) == NULL) @@ -630,19 +769,19 @@ pam_chauthtok_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: - fputs(PAM_MSG_MEMBER(msg, i, msg), stderr); + fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); 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: - fputs(PAM_MSG_MEMBER(msg, i, msg), stderr); + fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); reply[i].resp_retcode = PAM_SUCCESS; break; default: @@ -661,6 +800,8 @@ pam_chauthtok_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 @@ -668,15 +809,10 @@ pam_chauthtok_conv(int n, const struct pam_message **msg, 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 *)&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)); @@ -687,17 +823,77 @@ do_pam_chauthtok(void) pam_strerror(sshpam_handle, sshpam_err)); } -/* +static int +pam_store_conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct pam_response *reply; + int i; + size_t len; + + debug3("PAM: %s called with %d messages", __func__, n); + *resp = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + + if ((reply = malloc(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)) { + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + len = strlen(PAM_MSG_MEMBER(msg, i, msg)); + buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); + buffer_append(&loginmsg, "\n", 1 ); + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + goto fail; + } + } + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + return (PAM_CONV_ERR); +} + +static struct pam_conv store_conv = { pam_store_conv, NULL }; + +void +do_pam_session(void) +{ + debug3("PAM: opening session"); + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&store_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; @@ -712,21 +908,16 @@ do_pam_putenv(char *name, char *value) return (ret); } -void -print_pam_messages(void) +char ** +fetch_pam_child_environment(void) { - /* XXX */ + 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