123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- /*
- * Copyright information at end of file.
- */
- #include "config.h"
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
- #include <pwd.h>
- #include <shadow.h>
- #include <limits.h>
- #include <utmp.h>
- #include <errno.h>
- #include <signal.h>
- #include <ctype.h>
- #include <syslog.h>
- #include <sys/resource.h>
- #ifdef HAVE_RPCSVC_YPCLNT_H
- #include <rpcsvc/ypclnt.h>
- #endif
- #include <security/_pam_macros.h>
- #include <security/pam_modules.h>
- #include <security/pam_ext.h>
- #include <security/pam_modutil.h>
- #include "pam_cc_compat.h"
- #include "pam_inline.h"
- #include "support.h"
- #include "passverify.h"
- /* this is a front-end for module-application conversations */
- int _make_remark(pam_handle_t * pamh, unsigned long long ctrl,
- int type, const char *text)
- {
- int retval = PAM_SUCCESS;
- if (off(UNIX__QUIET, ctrl)) {
- retval = pam_prompt(pamh, type, NULL, "%s", text);
- }
- return retval;
- }
- /*
- * set the control flags for the UNIX module.
- */
- unsigned long long _set_ctrl(pam_handle_t *pamh, int flags, int *remember,
- int *rounds, int *pass_min_len, int argc,
- const char **argv)
- {
- unsigned long long ctrl;
- char *val;
- int j;
- D(("called."));
- ctrl = UNIX_DEFAULTS; /* the default selection of options */
- /* set some flags manually */
- if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
- D(("IAMROOT"));
- set(UNIX__IAMROOT, ctrl);
- }
- if (flags & PAM_UPDATE_AUTHTOK) {
- D(("UPDATE_AUTHTOK"));
- set(UNIX__UPDATE, ctrl);
- }
- if (flags & PAM_PRELIM_CHECK) {
- D(("PRELIM_CHECK"));
- set(UNIX__PRELIM, ctrl);
- }
- if (flags & PAM_SILENT) {
- D(("SILENT"));
- set(UNIX__QUIET, ctrl);
- }
- /* preset encryption method with value from /etc/login.defs */
- val = pam_modutil_search_key(pamh, LOGIN_DEFS, "ENCRYPT_METHOD");
- if (val) {
- for (j = 0; j < UNIX_CTRLS_; ++j) {
- if (unix_args[j].token && unix_args[j].is_hash_algo
- && !strncasecmp(val, unix_args[j].token, strlen(unix_args[j].token))) {
- break;
- }
- }
- if (j >= UNIX_CTRLS_) {
- pam_syslog(pamh, LOG_WARNING, "unrecognized ENCRYPT_METHOD value [%s]", val);
- } else {
- ctrl &= unix_args[j].mask; /* for turning things off */
- ctrl |= unix_args[j].flag; /* for turning things on */
- }
- free (val);
- /* read number of rounds for crypt algo */
- if (rounds && (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl))) {
- val = pam_modutil_search_key(pamh, LOGIN_DEFS, "SHA_CRYPT_MAX_ROUNDS");
- if (val) {
- *rounds = strtol(val, NULL, 10);
- set(UNIX_ALGO_ROUNDS, ctrl);
- free (val);
- }
- }
- }
- /* now parse the arguments to this module */
- for (; argc-- > 0; ++argv) {
- const char *str = NULL;
- D(("pam_unix arg: %s", *argv));
- for (j = 0; j < UNIX_CTRLS_; ++j) {
- if (unix_args[j].token
- && (str = pam_str_skip_prefix_len(*argv,
- unix_args[j].token,
- strlen(unix_args[j].token))) != NULL) {
- break;
- }
- }
- if (str == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "unrecognized option [%s]", *argv);
- } else {
- /* special cases */
- if (j == UNIX_REMEMBER_PASSWD) {
- if (remember == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "option remember not allowed for this module type");
- continue;
- }
- *remember = strtol(str, NULL, 10);
- if ((*remember == INT_MIN) || (*remember == INT_MAX))
- *remember = -1;
- if (*remember > 400)
- *remember = 400;
- } else if (j == UNIX_MIN_PASS_LEN) {
- if (pass_min_len == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "option minlen not allowed for this module type");
- continue;
- }
- *pass_min_len = atoi(str);
- } else if (j == UNIX_ALGO_ROUNDS) {
- if (rounds == NULL) {
- pam_syslog(pamh, LOG_ERR,
- "option rounds not allowed for this module type");
- continue;
- }
- *rounds = strtol(str, NULL, 10);
- }
- ctrl &= unix_args[j].mask; /* for turning things off */
- ctrl |= unix_args[j].flag; /* for turning things on */
- }
- }
- if (UNIX_DES_CRYPT(ctrl)
- && pass_min_len && *pass_min_len > 8)
- {
- pam_syslog (pamh, LOG_NOTICE, "Password minlen reset to 8 characters");
- *pass_min_len = 8;
- }
- if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
- D(("DISALLOW_NULL_AUTHTOK"));
- set(UNIX__NONULL, ctrl);
- }
- /* Set default rounds for blowfish, gost-yescrypt and yescrypt */
- if (off(UNIX_ALGO_ROUNDS, ctrl) && rounds != NULL) {
- if (on(UNIX_BLOWFISH_PASS, ctrl) ||
- on(UNIX_GOST_YESCRYPT_PASS, ctrl) ||
- on(UNIX_YESCRYPT_PASS, ctrl)) {
- *rounds = 5;
- set(UNIX_ALGO_ROUNDS, ctrl);
- }
- }
- /* Enforce sane "rounds" values */
- if (on(UNIX_ALGO_ROUNDS, ctrl)) {
- if (on(UNIX_GOST_YESCRYPT_PASS, ctrl) ||
- on(UNIX_YESCRYPT_PASS, ctrl)) {
- if (*rounds < 3 || *rounds > 11)
- *rounds = 5;
- } else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
- if (*rounds < 4 || *rounds > 31)
- *rounds = 5;
- } else if (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl)) {
- if ((*rounds < 1000) || (*rounds == INT_MAX)) {
- /* don't care about bogus values */
- *rounds = 0;
- unset(UNIX_ALGO_ROUNDS, ctrl);
- } else if (*rounds >= 10000000) {
- *rounds = 9999999;
- }
- }
- }
- /* auditing is a more sensitive version of debug */
- if (on(UNIX_AUDIT, ctrl)) {
- set(UNIX_DEBUG, ctrl);
- }
- /* return the set of flags */
- D(("done."));
- return ctrl;
- }
- /* ************************************************************** *
- * Useful non-trivial functions *
- * ************************************************************** */
- /*
- * the following is used to keep track of the number of times a user fails
- * to authenticate themself.
- */
- #define FAIL_PREFIX "-UN*X-FAIL-"
- #define UNIX_MAX_RETRIES 3
- struct _pam_failed_auth {
- char *user; /* user that's failed to be authenticated */
- char *name; /* attempt from user with name */
- int uid; /* uid of calling user */
- int euid; /* euid of calling process */
- int count; /* number of failures so far */
- };
- #ifndef PAM_DATA_REPLACE
- #error "Need to get an updated libpam 0.52 or better"
- #endif
- static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
- {
- int quiet;
- const void *service = NULL;
- const void *ruser = NULL;
- const void *rhost = NULL;
- const void *tty = NULL;
- struct _pam_failed_auth *failure;
- D(("called"));
- quiet = err & PAM_DATA_SILENT; /* should we log something? */
- err &= PAM_DATA_REPLACE; /* are we just replacing data? */
- failure = (struct _pam_failed_auth *) fl;
- if (failure != NULL) {
- if (!quiet && !err) { /* under advisement from Sun,may go away */
- /* log the number of authentication failures */
- if (failure->count > 1) {
- (void) pam_get_item(pamh, PAM_SERVICE,
- &service);
- (void) pam_get_item(pamh, PAM_RUSER,
- &ruser);
- (void) pam_get_item(pamh, PAM_RHOST,
- &rhost);
- (void) pam_get_item(pamh, PAM_TTY,
- &tty);
- pam_syslog(pamh, LOG_NOTICE,
- "%d more authentication failure%s; "
- "logname=%s uid=%d euid=%d "
- "tty=%s ruser=%s rhost=%s "
- "%s%s",
- failure->count - 1, failure->count == 2 ? "" : "s",
- failure->name, failure->uid, failure->euid,
- tty ? (const char *)tty : "", ruser ? (const char *)ruser : "",
- rhost ? (const char *)rhost : "",
- (failure->user && failure->user[0] != '\0')
- ? " user=" : "", failure->user
- );
- if (failure->count > UNIX_MAX_RETRIES) {
- pam_syslog(pamh, LOG_NOTICE,
- "service(%s) ignoring max retries; %d > %d",
- service == NULL ? "**unknown**" : (const char *)service,
- failure->count,
- UNIX_MAX_RETRIES);
- }
- }
- }
- _pam_delete(failure->user); /* tidy up */
- _pam_delete(failure->name); /* tidy up */
- free(failure);
- }
- }
- /*
- * _unix_getpwnam() searches only /etc/passwd and NIS to find user information
- */
- static void _unix_cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
- {
- free(data);
- }
- int _unix_getpwnam(pam_handle_t *pamh, const char *name,
- int files, int nis, struct passwd **ret)
- {
- FILE *passwd;
- char buf[16384];
- int matched = 0, buflen;
- char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
- memset(buf, 0, sizeof(buf));
- if (!matched && files) {
- int userlen = strlen(name);
- passwd = fopen("/etc/passwd", "r");
- if (passwd != NULL) {
- while (fgets(buf, sizeof(buf), passwd) != NULL) {
- if ((buf[userlen] == ':') &&
- (strncmp(name, buf, userlen) == 0)) {
- p = buf + strlen(buf) - 1;
- while (isspace(*p) && (p >= buf)) {
- *p-- = '\0';
- }
- matched = 1;
- break;
- }
- }
- fclose(passwd);
- }
- }
- #if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined (HAVE_YP_BIND) && defined (HAVE_YP_MATCH) && defined (HAVE_YP_UNBIND)
- if (!matched && nis) {
- char *userinfo = NULL, *domain = NULL;
- int len = 0, i;
- len = yp_get_default_domain(&domain);
- if (len == YPERR_SUCCESS) {
- len = yp_bind(domain);
- }
- if (len == YPERR_SUCCESS) {
- i = yp_match(domain, "passwd.byname", name,
- strlen(name), &userinfo, &len);
- yp_unbind(domain);
- if ((i == YPERR_SUCCESS) && ((size_t)len < sizeof(buf))) {
- strncpy(buf, userinfo, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- matched = 1;
- }
- }
- }
- #else
- /* we don't have NIS support, make compiler happy. */
- (void) nis;
- #endif
- if (matched && (ret != NULL)) {
- *ret = NULL;
- slogin = buf;
- spasswd = strchr(slogin, ':');
- if (spasswd == NULL) {
- return matched;
- }
- *spasswd++ = '\0';
- suid = strchr(spasswd, ':');
- if (suid == NULL) {
- return matched;
- }
- *suid++ = '\0';
- sgid = strchr(suid, ':');
- if (sgid == NULL) {
- return matched;
- }
- *sgid++ = '\0';
- sgecos = strchr(sgid, ':');
- if (sgecos == NULL) {
- return matched;
- }
- *sgecos++ = '\0';
- shome = strchr(sgecos, ':');
- if (shome == NULL) {
- return matched;
- }
- *shome++ = '\0';
- sshell = strchr(shome, ':');
- if (sshell == NULL) {
- return matched;
- }
- *sshell++ = '\0';
- buflen = sizeof(struct passwd) +
- strlen(slogin) + 1 +
- strlen(spasswd) + 1 +
- strlen(sgecos) + 1 +
- strlen(shome) + 1 +
- strlen(sshell) + 1;
- *ret = malloc(buflen);
- if (*ret == NULL) {
- return matched;
- }
- memset(*ret, '\0', buflen);
- (*ret)->pw_uid = strtol(suid, &p, 10);
- if ((strlen(suid) == 0) || (*p != '\0')) {
- free(*ret);
- *ret = NULL;
- return matched;
- }
- (*ret)->pw_gid = strtol(sgid, &p, 10);
- if ((strlen(sgid) == 0) || (*p != '\0')) {
- free(*ret);
- *ret = NULL;
- return matched;
- }
- p = ((char*)(*ret)) + sizeof(struct passwd);
- (*ret)->pw_name = strcpy(p, slogin);
- p += strlen(p) + 1;
- (*ret)->pw_passwd = strcpy(p, spasswd);
- p += strlen(p) + 1;
- (*ret)->pw_gecos = strcpy(p, sgecos);
- p += strlen(p) + 1;
- (*ret)->pw_dir = strcpy(p, shome);
- p += strlen(p) + 1;
- (*ret)->pw_shell = strcpy(p, sshell);
- snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
- if (pam_set_data(pamh, buf,
- *ret, _unix_cleanup) != PAM_SUCCESS) {
- free(*ret);
- *ret = NULL;
- }
- }
- return matched;
- }
- /*
- * _unix_comsefromsource() is a quick check to see if information about a given
- * user comes from a particular source (just files and nis for now)
- *
- */
- int _unix_comesfromsource(pam_handle_t *pamh,
- const char *name, int files, int nis)
- {
- return _unix_getpwnam(pamh, name, files, nis, NULL);
- }
- /*
- * verify the password of a user
- */
- #include <sys/types.h>
- #include <sys/wait.h>
- static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
- unsigned long long ctrl, const char *user)
- {
- int retval, child, fds[2];
- struct sigaction newsa, oldsa;
- D(("called."));
- /* create a pipe for the password */
- if (pipe(fds) != 0) {
- D(("could not make pipe"));
- return PAM_AUTH_ERR;
- }
- if (off(UNIX_NOREAP, ctrl)) {
- /*
- * This code arranges that the demise of the child does not cause
- * the application to receive a signal it is not expecting - which
- * may kill the application or worse.
- *
- * The "noreap" module argument is provided so that the admin can
- * override this behavior.
- */
- memset(&newsa, '\0', sizeof(newsa));
- newsa.sa_handler = SIG_DFL;
- sigaction(SIGCHLD, &newsa, &oldsa);
- }
- /* fork */
- child = fork();
- if (child == 0) {
- static char *envp[] = { NULL };
- const char *args[] = { NULL, NULL, NULL, NULL };
- /* XXX - should really tidy up PAM here too */
- /* reopen stdin as pipe */
- if (dup2(fds[0], STDIN_FILENO) != STDIN_FILENO) {
- pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin");
- _exit(PAM_AUTHINFO_UNAVAIL);
- }
- if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD,
- PAM_MODUTIL_PIPE_FD,
- PAM_MODUTIL_PIPE_FD) < 0) {
- _exit(PAM_AUTHINFO_UNAVAIL);
- }
- if (geteuid() == 0) {
- /* must set the real uid to 0 so the helper will not error
- out if pam is called from setuid binary (su, sudo...) */
- if (setuid(0) == -1) {
- D(("setuid failed"));
- _exit(PAM_AUTHINFO_UNAVAIL);
- }
- }
- /* exec binary helper */
- args[0] = CHKPWD_HELPER;
- args[1] = user;
- if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
- args[2]="nullok";
- } else {
- args[2]="nonull";
- }
- DIAG_PUSH_IGNORE_CAST_QUAL;
- execve(CHKPWD_HELPER, (char *const *) args, envp);
- DIAG_POP_IGNORE_CAST_QUAL;
- /* should not get here: exit with error */
- D(("helper binary is not available"));
- _exit(PAM_AUTHINFO_UNAVAIL);
- } else if (child > 0) {
- /* wait for child */
- /* if the stored password is NULL */
- int rc=0;
- if (passwd != NULL) { /* send the password to the child */
- int len = strlen(passwd);
- if (len > PAM_MAX_RESP_SIZE)
- len = PAM_MAX_RESP_SIZE;
- if (write(fds[1], passwd, len) == -1 ||
- write(fds[1], "", 1) == -1) {
- pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
- retval = PAM_AUTH_ERR;
- }
- passwd = NULL;
- } else { /* blank password */
- if (write(fds[1], "", 1) == -1) {
- pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
- retval = PAM_AUTH_ERR;
- }
- }
- close(fds[0]); /* close here to avoid possible SIGPIPE above */
- close(fds[1]);
- /* wait for helper to complete: */
- while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
- if (rc<0) {
- pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
- retval = PAM_AUTH_ERR;
- } else if (!WIFEXITED(retval)) {
- pam_syslog(pamh, LOG_ERR, "unix_chkpwd abnormal exit: %d", retval);
- retval = PAM_AUTH_ERR;
- } else {
- retval = WEXITSTATUS(retval);
- }
- } else {
- D(("fork failed"));
- close(fds[0]);
- close(fds[1]);
- retval = PAM_AUTH_ERR;
- }
- if (off(UNIX_NOREAP, ctrl)) {
- sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */
- }
- D(("returning %d", retval));
- return retval;
- }
- /*
- * _unix_blankpasswd() is a quick check for a blank password
- *
- * returns TRUE if user does not have a password
- * - to avoid prompting for one in such cases (CG)
- */
- int
- _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name)
- {
- struct passwd *pwd = NULL;
- char *salt = NULL;
- int daysleft;
- int retval;
- int blank = 0;
- int execloop;
- int nonexistent_check = 1;
- D(("called"));
- /*
- * This function does not have to be too smart if something goes
- * wrong, return FALSE and let this case to be treated somewhere
- * else (CG)
- */
- if (on(UNIX_NULLRESETOK, ctrl)) {
- retval = _unix_verify_user(pamh, ctrl, name, &daysleft);
- if (retval == PAM_NEW_AUTHTOK_REQD) {
- /* password reset is enforced, allow authentication with empty password */
- pam_syslog(pamh, LOG_DEBUG, "user [%s] has expired blank password, enabling nullok", name);
- set(UNIX__NULLOK, ctrl);
- }
- }
- if (on(UNIX__NONULL, ctrl))
- return 0; /* will fail but don't let on yet */
- /* UNIX passwords area */
- /*
- * Execute this loop twice: one checking the password hash of an existing
- * user and another one for a non-existing user. This way the runtimes
- * are equal, making it more difficult to differentiate existing from
- * non-existing users.
- */
- for (execloop = 0; execloop < 2; ++execloop) {
- retval = get_pwd_hash(pamh, name, &pwd, &salt);
- if (retval == PAM_UNIX_RUN_HELPER) {
- if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS)
- blank = nonexistent_check;
- } else if (retval == PAM_USER_UNKNOWN) {
- name = "root";
- nonexistent_check = 0;
- continue;
- } else if (salt != NULL) {
- if (strlen(salt) == 0)
- blank = nonexistent_check;
- }
- name = "pam_unix_non_existent:";
- /* non-existent user check will not affect the blank value */
- }
- /* tidy up */
- if (salt)
- _pam_delete(salt);
- return blank;
- }
- int _unix_verify_password(pam_handle_t * pamh, const char *name
- ,const char *p, unsigned long long ctrl)
- {
- struct passwd *pwd = NULL;
- char *salt = NULL;
- char *data_name;
- char pw[PAM_MAX_RESP_SIZE + 1];
- int retval;
- D(("called"));
- #ifdef HAVE_PAM_FAIL_DELAY
- if (off(UNIX_NODELAY, ctrl)) {
- D(("setting delay"));
- (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */
- }
- #endif
- /* locate the entry for this user */
- D(("locating user's record"));
- retval = get_pwd_hash(pamh, name, &pwd, &salt);
- data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name));
- if (data_name == NULL) {
- pam_syslog(pamh, LOG_CRIT, "no memory for data-name");
- } else {
- strcpy(data_name, FAIL_PREFIX);
- strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
- }
- if (p != NULL && strlen(p) > PAM_MAX_RESP_SIZE) {
- memset(pw, 0, sizeof(pw));
- p = strncpy(pw, p, sizeof(pw) - 1);
- }
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_UNIX_RUN_HELPER) {
- D(("running helper binary"));
- retval = _unix_run_helper_binary(pamh, p, ctrl, name);
- } else {
- D(("user's record unavailable"));
- p = NULL;
- if (on(UNIX_AUDIT, ctrl)) {
- /* this might be a typo and the user has given a password
- instead of a username. Careful with this. */
- pam_syslog(pamh, LOG_NOTICE,
- "check pass; user (%s) unknown", name);
- } else {
- name = NULL;
- if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
- pam_syslog(pamh, LOG_NOTICE,
- "check pass; user unknown");
- } else {
- /* don't log failure as another pam module can succeed */
- goto cleanup;
- }
- }
- }
- } else {
- retval = verify_pwd_hash(pamh, p, salt, off(UNIX__NONULL, ctrl));
- }
- if (retval == PAM_SUCCESS) {
- if (data_name) /* reset failures */
- pam_set_data(pamh, data_name, NULL, _cleanup_failures);
- } else {
- if (data_name != NULL) {
- struct _pam_failed_auth *new = NULL;
- const struct _pam_failed_auth *old = NULL;
- /* get a failure recorder */
- new = (struct _pam_failed_auth *)
- malloc(sizeof(struct _pam_failed_auth));
- if (new != NULL) {
- const char *login_name;
- const void *void_old;
- login_name = pam_modutil_getlogin(pamh);
- if (login_name == NULL) {
- login_name = "";
- }
- new->user = strdup(name ? name : "");
- new->uid = getuid();
- new->euid = geteuid();
- new->name = strdup(login_name);
- /* any previous failures for this user ? */
- if (pam_get_data(pamh, data_name, &void_old)
- == PAM_SUCCESS)
- old = void_old;
- else
- old = NULL;
- if (old != NULL) {
- new->count = old->count + 1;
- if (new->count >= UNIX_MAX_RETRIES) {
- retval = PAM_MAXTRIES;
- }
- } else {
- const void *service=NULL;
- const void *ruser=NULL;
- const void *rhost=NULL;
- const void *tty=NULL;
- (void) pam_get_item(pamh, PAM_SERVICE,
- &service);
- (void) pam_get_item(pamh, PAM_RUSER,
- &ruser);
- (void) pam_get_item(pamh, PAM_RHOST,
- &rhost);
- (void) pam_get_item(pamh, PAM_TTY,
- &tty);
- pam_syslog(pamh, LOG_NOTICE,
- "authentication failure; "
- "logname=%s uid=%d euid=%d "
- "tty=%s ruser=%s rhost=%s "
- "%s%s",
- new->name, new->uid, new->euid,
- tty ? (const char *)tty : "",
- ruser ? (const char *)ruser : "",
- rhost ? (const char *)rhost : "",
- (new->user && new->user[0] != '\0')
- ? " user=" : "",
- new->user
- );
- new->count = 1;
- }
- pam_set_data(pamh, data_name, new, _cleanup_failures);
- } else {
- pam_syslog(pamh, LOG_CRIT,
- "no memory for failure recorder");
- }
- }
- }
- cleanup:
- memset(pw, 0, sizeof(pw)); /* clear memory of the password */
- if (data_name)
- _pam_delete(data_name);
- if (salt)
- _pam_delete(salt);
- D(("done [%d].", retval));
- return retval;
- }
- int
- _unix_verify_user(pam_handle_t *pamh,
- unsigned long long ctrl,
- const char *name,
- int *daysleft)
- {
- int retval;
- struct spwd *spent;
- struct passwd *pwent;
- retval = get_account_info(pamh, name, &pwent, &spent);
- if (retval == PAM_USER_UNKNOWN) {
- pam_syslog(pamh, LOG_ERR,
- "could not identify user (from getpwnam(%s))",
- name);
- return retval;
- }
- if (retval == PAM_SUCCESS && spent == NULL)
- return PAM_SUCCESS;
- if (retval == PAM_UNIX_RUN_HELPER) {
- retval = _unix_run_verify_binary(pamh, ctrl, name, daysleft);
- if (retval == PAM_AUTHINFO_UNAVAIL &&
- on(UNIX_BROKEN_SHADOW, ctrl))
- return PAM_SUCCESS;
- } else if (retval != PAM_SUCCESS) {
- if (on(UNIX_BROKEN_SHADOW,ctrl))
- return PAM_SUCCESS;
- else
- return retval;
- } else
- retval = check_shadow_expiry(pamh, spent, daysleft);
- return retval;
- }
- /* ****************************************************************** *
- * Copyright (c) Jan Rękorajski 1999.
- * Copyright (c) Andrew G. Morgan 1996-8.
- * Copyright (c) Alex O. Yuriev, 1996.
- * Copyright (c) Cristian Gafton 1996.
- * Copyright (c) Red Hat, Inc. 2007.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, and the entire permission notice in its entirety,
- * including the disclaimer of warranties.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
- * required INSTEAD OF the above restrictions. (This clause is
- * necessary due to a potential bad interaction between the GPL and
- * the restrictions contained in a BSD-style copyright.)
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
|