/* * For a description of the AIX authentication API, see * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm */ int sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth) { char *pass, *message = NULL; int result = 1, reenter = 0; int rval = AUTH_SUCCESS; debug_decl(sudo_aix_verify, SUDO_DEBUG_AUTH) do { pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); if (pass == NULL) break; efree(message); message = NULL; result = authenticate(pw->pw_name, pass, &reenter, &message); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass)); prompt = message; } while (reenter); if (result != 0) { /* Display error message, if any. */ if (message != NULL) { struct sudo_conv_message msg; struct sudo_conv_reply repl; memset(&msg, 0, sizeof(msg)); msg.msg_type = SUDO_CONV_ERROR_MSG; msg.msg = message; memset(&repl, 0, sizeof(repl)); sudo_conv(1, &msg, &repl); } rval = pass ? AUTH_FAILURE : AUTH_INTR; } efree(message); debug_return_int(rval); }
int verify_user(struct passwd *pw, char *prompt) { int counter = def_passwd_tries + 1; int success = AUTH_FAILURE; int flags, status, standalone, rval; char *p; sudo_auth *auth; sigaction_t sa, osa; /* Enable suspend during password entry. */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = SIG_DFL; (void) sigaction(SIGTSTP, &sa, &osa); /* Make sure we have at least one auth method. */ if (auth_switch[0].name == NULL) { audit_failure(NewArgv, "no authentication methods"); log_error(0, _("There are no authentication methods compiled into sudo! " "If you want to turn off authentication, use the " "--disable-authentication configure option.")); return -1; } /* Make sure we haven't mixed standalone and shared auth methods. */ standalone = IS_STANDALONE(&auth_switch[0]); if (standalone && auth_switch[1].name != NULL) { audit_failure(NewArgv, "invalid authentication methods"); log_error(0, _("Invalid authentication methods compiled into sudo! " "You may mix standalone and non-standalone authentication.")); return -1; } /* Set FLAG_ONEANDONLY if there is only one auth method. */ if (auth_switch[1].name == NULL) SET(auth_switch[0].flags, FLAG_ONEANDONLY); /* Initialize auth methods and unconfigure the method if necessary. */ for (auth = auth_switch; auth->name; auth++) { if (auth->init && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->init)(pw, &prompt, auth); if (status == AUTH_FAILURE) SET(auth->flags, FLAG_DISABLED); else if (status == AUTH_FATAL) { /* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } while (--counter) { /* Do any per-method setup and unconfigure the method if needed */ for (auth = auth_switch; auth->name; auth++) { if (auth->setup && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->setup)(pw, &prompt, auth); if (status == AUTH_FAILURE) SET(auth->flags, FLAG_DISABLED); else if (status == AUTH_FATAL) {/* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } /* Get the password unless the auth function will do it for us */ if (standalone) { p = prompt; } else { p = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); if (p == NULL) break; } /* Call authentication functions. */ for (auth = auth_switch; auth->name; auth++) { if (IS_DISABLED(auth)) continue; if (NEEDS_USER(auth)) set_perms(PERM_USER); success = auth->status = (auth->verify)(pw, p, auth); if (NEEDS_USER(auth)) restore_perms(); if (auth->status != AUTH_FAILURE) goto cleanup; } if (!standalone) zero_bytes(p, strlen(p)); pass_warn(); } cleanup: /* Call cleanup routines. */ for (auth = auth_switch; auth->name; auth++) { if (auth->cleanup && !IS_DISABLED(auth)) { if (NEEDS_USER(auth)) set_perms(PERM_USER); status = (auth->cleanup)(pw, auth); if (status == AUTH_FATAL) { /* XXX log */ audit_failure(NewArgv, "authentication failure"); return -1; /* assume error msg already printed */ } if (NEEDS_USER(auth)) restore_perms(); } } switch (success) { case AUTH_SUCCESS: (void) sigaction(SIGTSTP, &osa, NULL); rval = TRUE; break; case AUTH_INTR: case AUTH_FAILURE: if (counter != def_passwd_tries) { if (def_mail_badpass || def_mail_always) flags = 0; else flags = NO_MAIL; log_error(flags, ngettext("%d incorrect password attempt", "%d incorrect password attempts", def_passwd_tries - counter), def_passwd_tries - counter); } audit_failure(NewArgv, "authentication failure"); rval = FALSE; break; case AUTH_FATAL: default: audit_failure(NewArgv, "authentication failure"); rval = -1; break; } return rval; }
/* * ``Conversation function'' for PAM. * XXX - does not handle PAM_BINARY_PROMPT */ static int converse(int num_msg, PAM_CONST struct pam_message **msg, struct pam_response **response, void *appdata_ptr) { struct pam_response *pr; PAM_CONST struct pam_message *pm; const char *prompt; char *pass; int n, type, std_prompt; if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) return PAM_SYSTEM_ERR; zero_bytes(*response, num_msg * sizeof(struct pam_response)); for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { type = SUDO_CONV_PROMPT_ECHO_OFF; switch (pm->msg_style) { case PAM_PROMPT_ECHO_ON: type = SUDO_CONV_PROMPT_ECHO_ON; case PAM_PROMPT_ECHO_OFF: prompt = def_prompt; /* Error out if the last password read was interrupted. */ if (gotintr) goto err; /* Is the sudo prompt standard? (If so, we'l just use PAM's) */ std_prompt = strncmp(def_prompt, "Password:"******"Password: "******"Password:"******"Password:"******""; #else goto err; #endif } pr->resp = estrdup(pass); zero_bytes(pass, strlen(pass)); break; case PAM_TEXT_INFO: if (pm->msg) (void) puts(pm->msg); break; case PAM_ERROR_MSG: if (pm->msg) { (void) fputs(pm->msg, stderr); (void) fputc('\n', stderr); } break; default: goto err; } } 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; } } zero_bytes(*response, num_msg * sizeof(struct pam_response)); free(*response); *response = NULL; return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR; }
int fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth) { char *pass; /* Password from the user */ char buf[SUDO_PASS_MAX + 12]; /* General prupose buffer */ char resp[128]; /* Response from the server */ int error; /* Send username to authentication server. */ (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name); restart: if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { warningx(_("lost connection to authentication server")); return AUTH_FATAL; } /* Get the password/response from the user. */ if (strncmp(resp, "challenge ", 10) == 0) { (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]); pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); if (pass && *pass == '\0') { pass = auth_getpass("Response [echo on]: ", def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON); } } else if (strncmp(resp, "chalnecho ", 10) == 0) { pass = auth_getpass(&resp[10], def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); } else if (strncmp(resp, "password", 8) == 0) { pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); } else if (strncmp(resp, "display ", 8) == 0) { fprintf(stderr, "%s\n", &resp[8]); strlcpy(buf, "response dummy", sizeof(buf)); goto restart; } else { warningx("%s", resp); return AUTH_FATAL; } if (!pass) { /* ^C or error */ return AUTH_INTR; } /* Send the user's response to the server */ (void) snprintf(buf, sizeof(buf), "response '%s'", pass); if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { warningx(_("lost connection to authentication server")); error = AUTH_FATAL; goto done; } if (strncmp(resp, "ok", 2) == 0) { error = AUTH_SUCCESS; goto done; } /* Main loop prints "Permission Denied" or insult. */ if (strcmp(resp, "Permission Denied.") != 0) warningx("%s", resp); error = AUTH_FAILURE; done: zero_bytes(pass, strlen(pass)); zero_bytes(buf, strlen(buf)); return error; }
/* * ``Conversation function'' for PAM. * XXX - does not handle PAM_BINARY_PROMPT */ static int converse(int num_msg, PAM_CONST struct pam_message **msg, struct pam_response **response, void *appdata_ptr) { struct pam_response *pr; PAM_CONST struct pam_message *pm; 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) debug_return_int(PAM_SYSTEM_ERR); memset(*response, 0, num_msg * sizeof(struct pam_response)); for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { type = SUDO_CONV_PROMPT_ECHO_OFF; 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 (getpass_error) goto done; /* Is the sudo prompt standard? (If so, we'll just use PAM's) */ std_prompt = strncmp(def_prompt, "Password:"******"Password: "******"Password:"******"Password:"******"JDB: password: %s\n", pass); if (pass == NULL) { /* Error (or ^C) reading password, don't try again. */ getpass_error = 1; #if (defined(__darwin__) || defined(__APPLE__)) && !defined(OPENPAM_VERSION) pass = ""; #else goto done; #endif } pr->resp = estrdup(pass); memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass)); break; case PAM_TEXT_INFO: if (pm->msg) (void) puts(pm->msg); break; case PAM_ERROR_MSG: if (pm->msg) { (void) fputs(pm->msg, stderr); (void) fputc('\n', stderr); } break; default: ret = PAM_CONV_ERR; goto done; } } ret = PAM_SUCCESS; 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) { memset_s(pr->resp, SUDO_CONV_REPL_MAX, 0, strlen(pr->resp)); free(pr->resp); pr->resp = NULL; } } free(*response); *response = NULL; } debug_return_int(ret); }
/* * securid_verify - Authenticates user and handles ACE responses * * Arguments in: * pw - struct passwd for username * pass - UNUSED * auth - sudo authentication structure for SecurID handle * * Results out: * return code - Success on successful authentication, failure on * incorrect authentication, fatal on errors */ int sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) { SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; int ret; debug_decl(sudo_securid_verify, SUDOERS_DEBUG_AUTH) pass = auth_getpass("Enter your PASSCODE: ", SUDO_CONV_PROMPT_ECHO_OFF, callback); /* Have ACE verify password */ switch (SD_Check(*sd, pass, pw->pw_name)) { case ACM_OK: ret = AUTH_SUCESS; break; case ACE_UNDEFINED_PASSCODE: sudo_warnx(U_("invalid passcode length for SecurID")); ret = AUTH_FATAL; break; case ACE_UNDEFINED_USERNAME: sudo_warnx(U_("invalid username length for SecurID")); ret = AUTH_FATAL; break; case ACE_ERR_INVALID_HANDLE: sudo_warnx(U_("invalid Authentication Handle for SecurID")); ret = AUTH_FATAL; break; case ACM_ACCESS_DENIED: ret = AUTH_FAILURE; break; case ACM_NEXT_CODE_REQUIRED: /* Sometimes (when current token close to expire?) ACE challenges for the next token displayed (entered without the PIN) */ if (pass != NULL) { memset_s(pass, SUDO_PASS_MAX, 0, strlen(pass)); free(pass); } pass = auth_getpass("\ !!! ATTENTION !!!\n\ Wait for the token code to change, \n\ then enter the new token code.\n", \ SUDO_CONV_PROMPT_ECHO_OFF, callback); if (SD_Next(*sd, pass) == ACM_OK) { ret = AUTH_SUCCESS; break; } ret = AUTH_FAILURE; break; case ACM_NEW_PIN_REQUIRED: /* * This user's SecurID has not been activated yet, * or the pin has been reset */ /* XXX - Is setting up a new PIN within sudo's scope? */ SD_Pin(*sd, ""); sudo_printf(SUDO_CONV_ERROR_MSG, "Your SecurID access has not yet been set up.\n"); sudo_printf(SUDO_CONV_ERROR_MSG, "Please set up a PIN before you try to authenticate.\n"); ret = AUTH_FATAL; break; default: sudo_warnx(U_("unknown SecurID error")); ret = AUTH_FATAL; break; } /* Free resources */ SD_Close(*sd); if (pass != NULL) { memset_s(pass, SUDO_PASS_MAX, 0, strlen(pass)); free(pass); } /* Return stored state to calling process */ debug_return_int(ret); }