X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/0a3700eedf97632e9f494869c1de4788c38b5dd7..556f1c050904b36aa3c83a423d9c50f5ceeff685:/auth-pam.c diff --git a/auth-pam.c b/auth-pam.c index 4781058b..3f0f32f7 100644 --- a/auth-pam.c +++ b/auth-pam.c @@ -25,25 +25,32 @@ #include "includes.h" #ifdef USE_PAM -#include "ssh.h" #include "xmalloc.h" #include "log.h" +#include "auth.h" +#include "auth-options.h" #include "auth-pam.h" #include "servconf.h" #include "canohost.h" #include "readpass.h" +extern char *__progname; + +extern int use_privsep; + RCSID("$Id$"); #define NEW_AUTHTOK_MSG \ - "Warning: Your password has expired, please change it now" + "Warning: Your password has expired, please change it now." +#define NEW_AUTHTOK_MSG_PRIVSEP \ + "Your password has expired, the session cannot proceed." static int do_pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); /* module-local variables */ static struct pam_conv conv = { - do_pam_conversation, + (int (*)())do_pam_conversation, NULL }; static char *__pam_msg = NULL; @@ -52,7 +59,7 @@ static const char *__pampasswd = NULL; /* states for do_pam_conversation() */ enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN; -/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */ +/* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */ static int password_change_required = 0; /* remember whether the last pam_authenticate() succeeded or not */ static int was_authenticated = 0; @@ -85,7 +92,7 @@ int do_pam_authenticate(int flags) * messages with into __pam_msg. This is used during initial * authentication to bypass the normal PAM password prompt. * - * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1) + * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase() * and outputs messages to stderr. This mode is used if pam_chauthtok() * is called to update expired passwords. */ @@ -97,9 +104,7 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg, char buf[1024]; /* PAM will free this later */ - reply = malloc(num_msg * sizeof(*reply)); - if (reply == NULL) - return PAM_CONV_ERR; + reply = xmalloc(num_msg * sizeof(*reply)); for (count = 0; count < num_msg; count++) { if (pamstate == INITIAL_LOGIN) { @@ -109,11 +114,11 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg, */ switch(PAM_MSG_MEMBER(msg, count, msg_style)) { case PAM_PROMPT_ECHO_ON: - free(reply); + xfree(reply); return PAM_CONV_ERR; case PAM_PROMPT_ECHO_OFF: if (__pampasswd == NULL) { - free(reply); + xfree(reply); return PAM_CONV_ERR; } reply[count].resp = xstrdup(__pampasswd); @@ -121,7 +126,7 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg, break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: - if ((*msg)[count].msg != NULL) { + if (PAM_MSG_MEMBER(msg, count, msg) != NULL) { message_cat(&__pam_msg, PAM_MSG_MEMBER(msg, count, msg)); } @@ -129,7 +134,7 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg, reply[count].resp_retcode = PAM_SUCCESS; break; default: - free(reply); + xfree(reply); return PAM_CONV_ERR; } } else { @@ -144,21 +149,21 @@ static int do_pam_conversation(int num_msg, const struct pam_message **msg, reply[count].resp_retcode = PAM_SUCCESS; break; case PAM_PROMPT_ECHO_OFF: - reply[count].resp = xstrdup( - read_passphrase(PAM_MSG_MEMBER(msg, count, - msg), 1)); + reply[count].resp = + read_passphrase(PAM_MSG_MEMBER(msg, count, + msg), RP_ALLOW_STDIN); reply[count].resp_retcode = PAM_SUCCESS; break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: - if ((*msg)[count].msg != NULL) + if (PAM_MSG_MEMBER(msg, count, msg) != NULL) fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, count, msg)); reply[count].resp = xstrdup(""); reply[count].resp_retcode = PAM_SUCCESS; break; default: - free(reply); + xfree(reply); return PAM_CONV_ERR; } } @@ -197,17 +202,18 @@ void do_pam_cleanup_proc(void *context) } /* Attempt password authentation using PAM */ -int auth_pam_password(struct passwd *pw, const char *password) +int auth_pam_password(Authctxt *authctxt, const char *password) { extern ServerOptions options; int pam_retval; + struct passwd *pw = authctxt->pw; do_pam_set_conv(&conv); /* deny if no user. */ if (pw == NULL) return 0; - if (pw->pw_uid == 0 && options.permit_root_login == 2) + if (pw->pw_uid == 0 && options.permit_root_login == PERMIT_NO_PASSWD) return 0; if (*password == '\0' && options.permit_empty_passwd == 0) return 0; @@ -215,7 +221,8 @@ int auth_pam_password(struct passwd *pw, const char *password) __pampasswd = password; pamstate = INITIAL_LOGIN; - pam_retval = do_pam_authenticate(0); + pam_retval = do_pam_authenticate( + options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0); if (pam_retval == PAM_SUCCESS) { debug("PAM Password authentication accepted for " "user \"%.100s\"", pw->pw_name); @@ -244,15 +251,23 @@ int do_pam_account(char *username, char *remote_user) } pam_retval = pam_acct_mgmt(__pamh, 0); + debug2("pam_acct_mgmt() = %d", pam_retval); switch (pam_retval) { case PAM_SUCCESS: /* This is what we want */ break; +#if 0 case PAM_NEW_AUTHTOK_REQD: - message_cat(&__pam_msg, NEW_AUTHTOK_MSG); + message_cat(&__pam_msg, use_privsep ? + NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG); /* flag that password change is necessary */ password_change_required = 1; + /* disallow other functionality for now */ + no_port_forwarding_flag |= 2; + no_agent_forwarding_flag |= 2; + no_x11_forwarding_flag |= 2; break; +#endif default: log("PAM rejected by account configuration[%d]: " "%.200s", pam_retval, PAM_STRERROR(__pamh, @@ -287,14 +302,18 @@ void do_pam_session(char *username, const char *ttyname) } /* Set PAM credentials */ -void do_pam_setcred(void) +void do_pam_setcred(int init) { int pam_retval; + if (__pamh == NULL) + return; + do_pam_set_conv(&conv); debug("PAM establishing creds"); - pam_retval = pam_setcred(__pamh, PAM_ESTABLISH_CRED); + pam_retval = pam_setcred(__pamh, + init ? PAM_ESTABLISH_CRED : PAM_REINITIALIZE_CRED); if (pam_retval != PAM_SUCCESS) { if (was_authenticated) fatal("PAM setcred failed[%d]: %.200s", @@ -316,7 +335,7 @@ int is_pam_password_change_required(void) * Have user change authentication token if pam_acct_mgmt() indicated * it was expired. This needs to be called after an interactive * session is established and the user's pty is connected to - * stdin/stout/stderr. + * stdin/stdout/stderr. */ void do_pam_chauthtok(void) { @@ -325,11 +344,23 @@ void do_pam_chauthtok(void) do_pam_set_conv(&conv); if (password_change_required) { + if (use_privsep) + fatal("Password changing is currently unsupported" + " with privilege separation"); pamstate = OTHER; pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_retval != PAM_SUCCESS) fatal("PAM pam_chauthtok failed[%d]: %.200s", pam_retval, PAM_STRERROR(__pamh, pam_retval)); +#if 0 + /* XXX: This would need to be done in the parent process, + * but there's currently no way to pass such request. */ + no_port_forwarding_flag &= ~2; + no_agent_forwarding_flag &= ~2; + no_x11_forwarding_flag &= ~2; + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) + channel_permit_all_opens(); +#endif } } @@ -345,6 +376,8 @@ void start_pam(const char *user) { int pam_retval; extern ServerOptions options; + extern u_int utmp_len; + const char *rhost; debug("Starting up PAM with username \"%.200s\"", user); @@ -354,10 +387,10 @@ void start_pam(const char *user) fatal("PAM initialisation failed[%d]: %.200s", pam_retval, PAM_STRERROR(__pamh, pam_retval)); - debug("PAM setting rhost to \"%.200s\"", - get_canonical_hostname(options.reverse_mapping_check)); - pam_retval = pam_set_item(__pamh, PAM_RHOST, - get_canonical_hostname(options.reverse_mapping_check)); + rhost = get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping); + debug("PAM setting rhost to \"%.200s\"", rhost); + + pam_retval = pam_set_item(__pamh, PAM_RHOST, rhost); if (pam_retval != PAM_SUCCESS) fatal("PAM set rhost failed[%d]: %.200s", pam_retval, PAM_STRERROR(__pamh, pam_retval)); @@ -369,7 +402,7 @@ void start_pam(const char *user) * not even need one (for tty-less connections) * Kludge: Set a fake PAM_TTY */ - pam_retval = pam_set_item(__pamh, PAM_TTY, "ssh"); + pam_retval = pam_set_item(__pamh, PAM_TTY, "NODEVssh"); if (pam_retval != PAM_SUCCESS) fatal("PAM set tty failed[%d]: %.200s", pam_retval, PAM_STRERROR(__pamh, pam_retval)); @@ -378,7 +411,7 @@ void start_pam(const char *user) fatal_add_cleanup(&do_pam_cleanup_proc, NULL); } -/* Return list of PAM enviornment strings */ +/* Return list of PAM environment strings */ char **fetch_pam_environment(void) { #ifdef HAVE_PAM_GETENVLIST @@ -388,6 +421,16 @@ char **fetch_pam_environment(void) #endif /* HAVE_PAM_GETENVLIST */ } +void free_pam_environment(char **env) +{ + int i; + + if (env != NULL) { + for (i = 0; env[i] != NULL; i++) + xfree(env[i]); + } +} + /* Print any messages that have been generated during authentication */ /* or account checking to stderr */ void print_pam_messages(void)