--- embedaddon/sudo/plugins/sudoers/auth/pam.c 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/plugins/sudoers/auth/pam.c 2012/05/29 12:26:49 1.1.1.2 @@ -71,7 +71,7 @@ static int converse(int, PAM_CONST struct pam_message **, struct pam_response **, void *); static char *def_prompt = "Password:"; -static int gotintr; +static int getpass_error; #ifndef PAM_DATA_SILENT #define PAM_DATA_SILENT 0 @@ -80,10 +80,11 @@ static int gotintr; static pam_handle_t *pamh; int -pam_init(struct passwd *pw, sudo_auth *auth) +sudo_pam_init(struct passwd *pw, sudo_auth *auth) { static struct pam_conv pam_conv; static int pam_status; + debug_decl(sudo_pam_init, SUDO_DEBUG_AUTH) /* Initial PAM setup */ if (auth != NULL) @@ -96,8 +97,8 @@ pam_init(struct passwd *pw, sudo_auth *auth) #endif pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh); if (pam_status != PAM_SUCCESS) { - log_error(USE_ERRNO|NO_EXIT|NO_MAIL, _("unable to initialize PAM")); - return AUTH_FATAL; + log_error(USE_ERRNO|NO_MAIL, _("unable to initialize PAM")); + debug_return_int(AUTH_FATAL); } /* @@ -119,14 +120,15 @@ pam_init(struct passwd *pw, sudo_auth *auth) else (void) pam_set_item(pamh, PAM_TTY, user_ttypath); - return AUTH_SUCCESS; + debug_return_int(AUTH_SUCCESS); } int -pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) { const char *s; int *pam_status = (int *) auth->data; + debug_decl(sudo_pam_verify, SUDO_DEBUG_AUTH) def_prompt = prompt; /* for converse */ @@ -137,65 +139,69 @@ pam_verify(struct passwd *pw, char *prompt, sudo_auth *pam_status = pam_acct_mgmt(pamh, PAM_SILENT); switch (*pam_status) { case PAM_SUCCESS: - return AUTH_SUCCESS; + debug_return_int(AUTH_SUCCESS); case PAM_AUTH_ERR: - log_error(NO_EXIT|NO_MAIL, _("account validation failure, " + log_error(NO_MAIL, _("account validation failure, " "is your account locked?")); - return AUTH_FATAL; + debug_return_int(AUTH_FATAL); case PAM_NEW_AUTHTOK_REQD: - log_error(NO_EXIT|NO_MAIL, _("Account or password is " + log_error(NO_MAIL, _("Account or password is " "expired, reset your password and try again")); *pam_status = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (*pam_status == PAM_SUCCESS) - return AUTH_SUCCESS; + debug_return_int(AUTH_SUCCESS); if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_EXIT|NO_MAIL, _("pam_chauthtok: %s"), s); - return AUTH_FAILURE; + log_error(NO_MAIL, _("pam_chauthtok: %s"), s); + debug_return_int(AUTH_FAILURE); case PAM_AUTHTOK_EXPIRED: - log_error(NO_EXIT|NO_MAIL, + log_error(NO_MAIL, _("Password expired, contact your system administrator")); - return AUTH_FATAL; + debug_return_int(AUTH_FATAL); case PAM_ACCT_EXPIRED: - log_error(NO_EXIT|NO_MAIL, + log_error(NO_MAIL, _("Account expired or PAM config lacks an \"account\" " "section for sudo, contact your system administrator")); - return AUTH_FATAL; + debug_return_int(AUTH_FATAL); } /* FALLTHROUGH */ case PAM_AUTH_ERR: - if (gotintr) { + case PAM_AUTHINFO_UNAVAIL: + if (getpass_error) { /* error or ^C from tgetpass() */ - return AUTH_INTR; + debug_return_int(AUTH_INTR); } + /* FALLTHROUGH */ case PAM_MAXTRIES: case PAM_PERM_DENIED: - return AUTH_FAILURE; + debug_return_int(AUTH_FAILURE); default: if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_EXIT|NO_MAIL, _("pam_authenticate: %s"), s); - return AUTH_FATAL; + log_error(NO_MAIL, _("pam_authenticate: %s"), s); + debug_return_int(AUTH_FATAL); } } int -pam_cleanup(struct passwd *pw, sudo_auth *auth) +sudo_pam_cleanup(struct passwd *pw, sudo_auth *auth) { int *pam_status = (int *) auth->data; + debug_decl(sudo_pam_cleanup, SUDO_DEBUG_AUTH) /* If successful, we can't close the session until pam_end_session() */ if (*pam_status == AUTH_SUCCESS) - return AUTH_SUCCESS; + debug_return_int(AUTH_SUCCESS); *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT); pamh = NULL; - return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE; + debug_return_int(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); } int -pam_begin_session(struct passwd *pw, sudo_auth *auth) +sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth) { int status = PAM_SUCCESS; + debug_decl(sudo_pam_begin_session, SUDO_DEBUG_AUTH) /* * If there is no valid user we cannot open a PAM session. @@ -226,6 +232,26 @@ pam_begin_session(struct passwd *pw, sudo_auth *auth) */ (void) pam_setcred(pamh, PAM_ESTABLISH_CRED); +#ifdef HAVE_PAM_GETENVLIST + /* + * Update environment based on what is stored in pamh. + * If no authentication is done we will only have environment + * variables if pam_env is called via session. + */ + if (user_envp != NULL) { + char **pam_envp = pam_getenvlist(pamh); + if (pam_envp != NULL) { + /* Merge pam env with user env but do not overwrite. */ + env_init(*user_envp); + env_merge(pam_envp, false); + *user_envp = env_get(); + env_init(NULL); + efree(pam_envp); + /* XXX - we leak any duplicates that were in pam_envp */ + } + } +#endif /* HAVE_PAM_GETENVLIST */ + #ifndef NO_PAM_SESSION status = pam_open_session(pamh, 0); if (status != PAM_SUCCESS) { @@ -235,28 +261,31 @@ pam_begin_session(struct passwd *pw, sudo_auth *auth) #endif done: - return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE; + debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); } int -pam_end_session(struct passwd *pw, sudo_auth *auth) +sudo_pam_end_session(struct passwd *pw, sudo_auth *auth) { int status = PAM_SUCCESS; + debug_decl(sudo_pam_end_session, SUDO_DEBUG_AUTH) if (pamh != NULL) { -#ifndef NO_PAM_SESSION /* * Update PAM_USER to reference the user we are running the command - * as to match the call to pam_open_session(). + * as, as opposed to the user we authenticated as. + * XXX - still needed now that session init is in parent? */ (void) pam_set_item(pamh, PAM_USER, pw->pw_name); +#ifndef NO_PAM_SESSION (void) pam_close_session(pamh, PAM_SILENT); #endif + (void) pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); pamh = NULL; } - return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE; + debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); } /* @@ -272,9 +301,11 @@ converse(int num_msg, PAM_CONST struct pam_message **m const char *prompt; char *pass; int n, type, std_prompt; + int ret = PAM_AUTH_ERR; + debug_decl(converse, SUDO_DEBUG_AUTH) if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) - return PAM_SYSTEM_ERR; + debug_return_int(PAM_SYSTEM_ERR); zero_bytes(*response, num_msg * sizeof(struct pam_response)); for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { @@ -282,12 +313,13 @@ converse(int num_msg, PAM_CONST struct pam_message **m switch (pm->msg_style) { case PAM_PROMPT_ECHO_ON: type = SUDO_CONV_PROMPT_ECHO_ON; + /* FALLTHROUGH */ case PAM_PROMPT_ECHO_OFF: prompt = def_prompt; /* Error out if the last password read was interrupted. */ - if (gotintr) - goto err; + if (getpass_error) + goto done; /* Is the sudo prompt standard? (If so, we'l just use PAM's) */ std_prompt = strncmp(def_prompt, "Password:", 9) == 0 && @@ -309,13 +341,12 @@ converse(int num_msg, PAM_CONST struct pam_message **m /* Read the password unless interrupted. */ pass = auth_getpass(prompt, def_passwd_timeout * 60, type); if (pass == NULL) { - /* We got ^C instead of a password; abort quickly. */ - if (errno == EINTR) - gotintr = 1; -#if defined(__darwin__) || defined(__APPLE__) + /* Error (or ^C) reading password, don't try again. */ + getpass_error = 1; +#if (defined(__darwin__) || defined(__APPLE__)) && !defined(OPENPAM_VERSION) pass = ""; #else - goto err; + goto done; #endif } pr->resp = estrdup(pass); @@ -332,23 +363,25 @@ converse(int num_msg, PAM_CONST struct pam_message **m } break; default: - goto err; + ret = PAM_CONV_ERR; + goto done; } } + ret = PAM_SUCCESS; - return PAM_SUCCESS; - -err: - /* Zero and free allocated memory and return an error. */ - for (pr = *response, n = num_msg; n--; pr++) { - if (pr->resp != NULL) { - zero_bytes(pr->resp, strlen(pr->resp)); - free(pr->resp); - pr->resp = NULL; +done: + if (ret != PAM_SUCCESS) { + /* Zero and free allocated memory and return an error. */ + for (pr = *response, n = num_msg; n--; pr++) { + if (pr->resp != NULL) { + zero_bytes(pr->resp, strlen(pr->resp)); + free(pr->resp); + pr->resp = NULL; + } } + zero_bytes(*response, num_msg * sizeof(struct pam_response)); + free(*response); + *response = NULL; } - zero_bytes(*response, num_msg * sizeof(struct pam_response)); - free(*response); - *response = NULL; - return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR; + debug_return_int(ret); }