Pam conversation function changes:

o use PAM_BUF_ERR as the return value when calloc() fails.
 o sanity check the value of num_msg
 o remove the workaround for old Apple PAM
 o PAM_AUTH_ERR is not a valid PAM conversation function return value

If getpass_error is set after a call to pam_verify (usually because
the user pressed ^C), return AUTH_INTR immediately instead of
checking the pam_verify return value.
This commit is contained in:
Todd C. Miller
2015-02-23 11:12:45 -07:00
parent e11f32fd42
commit a604f0f02d

View File

@@ -78,20 +78,19 @@
static int converse(int, PAM_CONST struct pam_message **, static int converse(int, PAM_CONST struct pam_message **,
struct pam_response **, void *); struct pam_response **, void *);
static struct pam_conv pam_conv = { converse, NULL };
static char *def_prompt = PASSPROMPT; static char *def_prompt = PASSPROMPT;
static int getpass_error; static bool getpass_error;
static pam_handle_t *pamh; static pam_handle_t *pamh;
int int
sudo_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; static int pam_status;
debug_decl(sudo_pam_init, SUDOERS_DEBUG_AUTH) debug_decl(sudo_pam_init, SUDOERS_DEBUG_AUTH)
/* Initial PAM setup */ /* Initial PAM setup */
auth->data = (void *) &pam_status; auth->data = (void *) &pam_status;
pam_conv.conv = converse;
pam_status = pam_start(ISSET(sudo_mode, MODE_LOGIN_SHELL) ? pam_status = pam_start(ISSET(sudo_mode, MODE_LOGIN_SHELL) ?
def_pam_login_service : def_pam_service, pw->pw_name, &pam_conv, &pamh); def_pam_login_service : def_pam_service, pw->pw_name, &pam_conv, &pamh);
if (pam_status != PAM_SUCCESS) { if (pam_status != PAM_SUCCESS) {
@@ -136,9 +135,14 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
debug_decl(sudo_pam_verify, SUDOERS_DEBUG_AUTH) debug_decl(sudo_pam_verify, SUDOERS_DEBUG_AUTH)
def_prompt = prompt; /* for converse */ def_prompt = prompt; /* for converse */
getpass_error = false; /* set by converse if user presses ^C */
/* PAM_SILENT prevents the authentication service from generating output. */ /* PAM_SILENT prevents the authentication service from generating output. */
*pam_status = pam_authenticate(pamh, PAM_SILENT); *pam_status = pam_authenticate(pamh, PAM_SILENT);
if (getpass_error) {
/* error or ^C from tgetpass() */
debug_return_int(AUTH_INTR);
}
switch (*pam_status) { switch (*pam_status) {
case PAM_SUCCESS: case PAM_SUCCESS:
*pam_status = pam_acct_mgmt(pamh, PAM_SILENT); *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
@@ -174,11 +178,6 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
/* FALLTHROUGH */ /* FALLTHROUGH */
case PAM_AUTH_ERR: case PAM_AUTH_ERR:
case PAM_AUTHINFO_UNAVAIL: case PAM_AUTHINFO_UNAVAIL:
if (getpass_error) {
/* error or ^C from tgetpass() */
debug_return_int(AUTH_INTR);
}
/* FALLTHROUGH */
case PAM_MAXTRIES: case PAM_MAXTRIES:
case PAM_PERM_DENIED: case PAM_PERM_DENIED:
debug_return_int(AUTH_FAILURE); debug_return_int(AUTH_FAILURE);
@@ -262,7 +261,7 @@ sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth)
/* Merge pam env with user env. */ /* Merge pam env with user env. */
env_init(*user_envp); env_init(*user_envp);
if (!env_merge(pam_envp)) if (!env_merge(pam_envp))
status = PAM_SYSTEM_ERR; status = AUTH_FAILURE;
*user_envp = env_get(); *user_envp = env_get();
env_init(NULL); env_init(NULL);
sudo_efree(pam_envp); sudo_efree(pam_envp);
@@ -325,11 +324,14 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
const char *prompt; const char *prompt;
char *pass; char *pass;
int n, type; int n, type;
int ret = PAM_AUTH_ERR; int ret = PAM_SUCCESS;
debug_decl(converse, SUDOERS_DEBUG_AUTH) debug_decl(converse, SUDOERS_DEBUG_AUTH)
if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
debug_return_int(PAM_CONV_ERR);
if ((*response = calloc(num_msg, sizeof(struct pam_response))) == NULL) if ((*response = calloc(num_msg, sizeof(struct pam_response))) == NULL)
debug_return_int(PAM_SYSTEM_ERR); debug_return_int(PAM_BUF_ERR);
for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
type = SUDO_CONV_PROMPT_ECHO_OFF; type = SUDO_CONV_PROMPT_ECHO_OFF;
@@ -365,12 +367,12 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
pass = auth_getpass(prompt, def_passwd_timeout * 60, type); pass = auth_getpass(prompt, def_passwd_timeout * 60, type);
if (pass == NULL) { if (pass == NULL) {
/* Error (or ^C) reading password, don't try again. */ /* Error (or ^C) reading password, don't try again. */
getpass_error = 1; getpass_error = true;
#if (defined(__darwin__) || defined(__APPLE__)) && !defined(OPENPAM_VERSION) goto done;
pass = ""; }
#else if (strlen(pass) >= PAM_MAX_RESP_SIZE) {
ret = PAM_CONV_ERR;
goto done; goto done;
#endif
} }
pr->resp = sudo_estrdup(pass); pr->resp = sudo_estrdup(pass);
memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass)); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
@@ -390,7 +392,6 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
goto done; goto done;
} }
} }
ret = PAM_SUCCESS;
done: done:
if (ret != PAM_SUCCESS) { if (ret != PAM_SUCCESS) {