static void authenticate (const struct passwd* pw) { const struct passwd* lpw = NULL; const char* cp, *srvname = NULL; int retval; switch (su_mode) { case SU_MODE: srvname = simulate_login ? PAM_SRVNAME_SU_L : PAM_SRVNAME_SU; break; case RUNUSER_MODE: srvname = simulate_login ? PAM_SRVNAME_RUNUSER_L : PAM_SRVNAME_RUNUSER; break; default: abort(); break; } retval = pam_start (srvname, pw->pw_name, &conv, &pamh); if (is_pam_failure(retval)) { goto done; } if (isatty (0) && (cp = ttyname (0)) != NULL) { const char* tty; if (strncmp (cp, "/dev/", 5) == 0) { tty = cp + 5; } else { tty = cp; } retval = pam_set_item (pamh, PAM_TTY, tty); if (is_pam_failure(retval)) { goto done; } } lpw = current_getpwuid (); if (lpw && lpw->pw_name) { retval = pam_set_item (pamh, PAM_RUSER, (const void*) lpw->pw_name); if (is_pam_failure(retval)) { goto done; } } if (su_mode == RUNUSER_MODE) { /* * This is the only difference between runuser(1) and su(1). The command * runuser(1) does not required authentication, because user is root. */ if (restricted) { errx(EXIT_FAILURE, _("may not be used by non-root users")); } return; } retval = pam_authenticate (pamh, 0); if (is_pam_failure(retval)) { goto done; } retval = pam_acct_mgmt (pamh, 0); if (retval == PAM_NEW_AUTHTOK_REQD) { /* Password has expired. Offer option to change it. */ retval = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } done: log_syslog(pw, !is_pam_failure(retval)); if (is_pam_failure(retval)) { const char* msg; log_btmp(pw); msg = pam_strerror(pamh, retval); pam_end(pamh, retval); sleep (getlogindefs_num ("FAIL_DELAY", 1)); errx (EXIT_FAILURE, "%s", msg ? msg : _("incorrect password")); } }
static void loginpam_auth(struct login_context *cxt) { int rc, show_unknown; unsigned int retries, failcount = 0; const char *hostname = cxt->hostname ? cxt->hostname : cxt->tty_name ? cxt->tty_name : "<unknown>"; pam_handle_t *pamh = cxt->pamh; /* if we didn't get a user on the command line, set it to NULL */ loginpam_get_username(pamh, &cxt->username); show_unknown = getlogindefs_bool("LOG_UNKFAIL_ENAB", 0); retries = getlogindefs_num("LOGIN_RETRIES", LOGIN_MAX_TRIES); /* * There may be better ways to deal with some of these conditions, but * at least this way I don't think we'll be giving away information... * * Perhaps someday we can trust that all PAM modules will pay attention * to failure count and get rid of LOGIN_MAX_TRIES? */ rc = pam_authenticate(pamh, 0); while ((++failcount < retries) && ((rc == PAM_AUTH_ERR) || (rc == PAM_USER_UNKNOWN) || (rc == PAM_CRED_INSUFFICIENT) || (rc == PAM_AUTHINFO_UNAVAIL))) { if (rc == PAM_USER_UNKNOWN && !show_unknown) /* * Logging unknown usernames may be a security issue if * a user enters her password instead of her login name. */ cxt->username = NULL; else loginpam_get_username(pamh, &cxt->username); syslog(LOG_NOTICE, _("FAILED LOGIN %u FROM %s FOR %s, %s"), failcount, hostname, cxt->username ? cxt->username : "******", pam_strerror(pamh, rc)); log_btmp(cxt); log_audit(cxt, 0); fprintf(stderr, _("Login incorrect\n\n")); pam_set_item(pamh, PAM_USER, NULL); rc = pam_authenticate(pamh, 0); } if (is_pam_failure(rc)) { if (rc == PAM_USER_UNKNOWN && !show_unknown) cxt->username = NULL; else loginpam_get_username(pamh, &cxt->username); if (rc == PAM_MAXTRIES) syslog(LOG_NOTICE, _("TOO MANY LOGIN TRIES (%u) FROM %s FOR %s, %s"), failcount, hostname, cxt->username ? cxt->username : "******", pam_strerror(pamh, rc)); else syslog(LOG_NOTICE, _("FAILED LOGIN SESSION FROM %s FOR %s, %s"), hostname, cxt->username ? cxt->username : "******", pam_strerror(pamh, rc)); log_btmp(cxt); log_audit(cxt, 0); fprintf(stderr, _("\nLogin incorrect\n")); pam_end(pamh, rc); sleepexit(EXIT_SUCCESS); } }