diff options
author | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:48:14 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:48:14 -0800 |
commit | d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c (patch) | |
tree | ba5654cffacfd2002eefc5bc3764a7971afff1dc /Linux-PAM/modules/pam_unix/pam_unix_passwd.c | |
parent | 4c51da22e068907adb7857d50f5109a467c94d7c (diff) | |
parent | 7cbfa335c57d068d59508c844f3957165cccfb9b (diff) | |
download | pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.tar.gz pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.tar.bz2 pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.zip |
New upstream version 0.99.7.1
Diffstat (limited to 'Linux-PAM/modules/pam_unix/pam_unix_passwd.c')
-rw-r--r-- | Linux-PAM/modules/pam_unix/pam_unix_passwd.c | 635 |
1 files changed, 444 insertions, 191 deletions
diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c index 2ea57cc6..8921d1cc 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c @@ -35,7 +35,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <security/_pam_aconf.h> +#include "config.h" #include <stdio.h> #include <stdlib.h> @@ -57,6 +57,16 @@ #include <rpcsvc/yp_prot.h> #include <rpcsvc/ypclnt.h> +#include <signal.h> +#include <errno.h> +#include <sys/wait.h> +#ifdef WITH_SELINUX +static int selinux_enabled=-1; +#include <selinux/selinux.h> +static security_context_t prev_context=NULL; +#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) +#endif + #ifdef USE_CRACKLIB #include <crack.h> #endif @@ -68,16 +78,13 @@ #define PAM_SM_PASSWORD #include <security/pam_modules.h> - -#ifndef LINUX_PAM -#include <security/pam_appl.h> -#endif /* LINUX_PAM */ - -#include <security/_pam_modutil.h> +#include <security/pam_ext.h> +#include <security/pam_modutil.h> #include "yppasswd.h" #include "md5.h" #include "support.h" +#include "bigcrypt.h" #if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) extern int getrpcport(const char *host, unsigned long prognum, @@ -89,12 +96,10 @@ extern int getrpcport(const char *host, unsigned long prognum, * password changing module. */ -#ifdef NEED_LCKPWDF +#if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF) # include "./lckpwdf.-c" #endif -extern char *bigcrypt(const char *key, const char *salt); - /* How it works: Gets in username (has to be done) from the calling program @@ -117,7 +122,7 @@ extern char *bigcrypt(const char *key, const char *salt); #define PW_TMPFILE "/etc/npasswd" #define SH_TMPFILE "/etc/nshadow" #ifndef CRACKLIB_DICTS -#define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict" +#define CRACKLIB_DICTS NULL #endif #define OPW_TMPFILE "/etc/security/nopasswd" #define OLD_PASSWORDS_FILE "/etc/security/opasswd" @@ -187,29 +192,131 @@ static char *getNISserver(pam_handle_t *pamh) int port, err; if ((err = yp_get_default_domain(&domainname)) != 0) { - _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n", + pam_syslog(pamh, LOG_WARNING, "can't get local yp domain: %s", yperr_string(err)); return NULL; } if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) { - _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n", + pam_syslog(pamh, LOG_WARNING, "can't find the master ypserver: %s", yperr_string(err)); return NULL; } port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); if (port == 0) { - _log_err(LOG_WARNING, pamh, - "yppasswdd not running on NIS master host\n"); + pam_syslog(pamh, LOG_WARNING, + "yppasswdd not running on NIS master host"); return NULL; } if (port >= IPPORT_RESERVED) { - _log_err(LOG_WARNING, pamh, - "yppasswd daemon running on illegal port.\n"); + pam_syslog(pamh, LOG_WARNING, + "yppasswd daemon running on illegal port"); return NULL; } return master; } +#ifdef WITH_SELINUX + +static int _unix_run_shadow_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, const char *fromwhat, const char *towhat) +{ + int retval, child, fds[2]; + void (*sighandler)(int) = NULL; + + 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. + */ + sighandler = signal(SIGCHLD, SIG_DFL); + } + + /* fork */ + child = fork(); + if (child == 0) { + size_t i=0; + struct rlimit rlim; + static char *envp[] = { NULL }; + char *args[] = { NULL, NULL, NULL, NULL }; + + /* XXX - should really tidy up PAM here too */ + + close(0); close(1); + /* reopen stdin as pipe */ + close(fds[1]); + dup2(fds[0], STDIN_FILENO); + + if (getrlimit(RLIMIT_NOFILE,&rlim)==0) { + for (i=2; i < rlim.rlim_max; i++) { + if ((unsigned int)fds[0] != i) + close(i); + } + } + + if (SELINUX_ENABLED && 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...) */ + setuid(0); + } + + /* exec binary helper */ + args[0] = x_strdup(CHKPWD_HELPER); + args[1] = x_strdup(user); + args[2] = x_strdup("shadow"); + + execve(CHKPWD_HELPER, args, envp); + + /* 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 (fromwhat) + pam_modutil_write(fds[1], fromwhat, strlen(fromwhat)+1); + else + pam_modutil_write(fds[1], "", 1); + if (towhat) { + pam_modutil_write(fds[1], towhat, strlen(towhat)+1); + } + else + pam_modutil_write(fds[1], "", 1); + + close(fds[0]); /* close here to avoid possible SIGPIPE above */ + close(fds[1]); + rc=waitpid(child, &retval, 0); /* wait for helper to complete */ + if (rc<0) { + pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc); + retval = PAM_AUTH_ERR; + } else { + retval = WEXITSTATUS(retval); + } + } else { + D(("fork failed")); + close(fds[0]); + close(fds[1]); + retval = PAM_AUTH_ERR; + } + + if (sighandler != SIG_ERR) { + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } + + return retval; +} +#endif + static int check_old_password(const char *forwho, const char *newpass) { static char buf[16384]; @@ -270,37 +377,58 @@ static int save_old_password(pam_handle_t *pamh, } oldmask = umask(077); + +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + security_context_t passwd_context=NULL; + if (getfilecon("/etc/passwd",&passwd_context)<0) { + return PAM_AUTHTOK_ERR; + }; + if (getfscreatecon(&prev_context)<0) { + freecon(passwd_context); + return PAM_AUTHTOK_ERR; + } + if (setfscreatecon(passwd_context)) { + freecon(passwd_context); + freecon(prev_context); + return PAM_AUTHTOK_ERR; + } + freecon(passwd_context); + } +#endif pwfile = fopen(OPW_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } opwfile = fopen(OLD_PASSWORDS_FILE, "r"); if (opwfile == NULL) { fclose(pwfile); - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } - if (fstat (fileno (opwfile), &st) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } + if (fstat(fileno(opwfile), &st) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } - if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } - if (fchmod (fileno (pwfile), st.st_mode) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } + if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } + if (fchmod(fileno(pwfile), st.st_mode) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { @@ -337,13 +465,13 @@ static int save_old_password(pam_handle_t *pamh, fclose(opwfile); if (!found) { - pwd = _pammodutil_getpwnam(pamh, forwho); + pwd = pam_modutil_getpwnam(pamh, forwho); if (pwd == NULL) { err = 1; } else { pass = crypt_md5_wrapper(oldpass); - snprintf(nbuf, sizeof(nbuf), "%s:%d:1:%s\n", - forwho, pwd->pw_uid, pass); + snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n", + forwho, (unsigned long)pwd->pw_uid, pass); _pam_delete(pass); if (fputs(nbuf, pwfile) < 0) { err = 1; @@ -352,19 +480,31 @@ static int save_old_password(pam_handle_t *pamh, } if (fclose(pwfile)) { - D(("error writing entries to old passwords file: %s\n", - strerror(errno))); + D(("error writing entries to old passwords file: %m")); err = 1; } +done: if (!err) { - if (!rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) { - return PAM_SUCCESS; - } + if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) + err = 1; + } +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + if (setfscreatecon(prev_context)) { + err = 1; + } + if (prev_context) + freecon(prev_context); + prev_context=NULL; + } +#endif + if (!err) { + return PAM_SUCCESS; + } else { + unlink(OPW_TMPFILE); + return PAM_AUTHTOK_ERR; } - - unlink(OPW_TMPFILE); - return PAM_AUTHTOK_ERR; } static int _update_passwd(pam_handle_t *pamh, @@ -377,38 +517,59 @@ static int _update_passwd(pam_handle_t *pamh, int oldmask; oldmask = umask(077); +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + security_context_t passwd_context=NULL; + if (getfilecon("/etc/passwd",&passwd_context)<0) { + return PAM_AUTHTOK_ERR; + }; + if (getfscreatecon(&prev_context)<0) { + freecon(passwd_context); + return PAM_AUTHTOK_ERR; + } + if (setfscreatecon(passwd_context)) { + freecon(passwd_context); + freecon(prev_context); + return PAM_AUTHTOK_ERR; + } + freecon(passwd_context); + } +#endif pwfile = fopen(PW_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } opwfile = fopen("/etc/passwd", "r"); if (opwfile == NULL) { fclose(pwfile); - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } - if (fstat (fileno (opwfile), &st) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } + if (fstat(fileno(opwfile), &st) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } - if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } - if (fchmod (fileno (pwfile), st.st_mode) == -1) - { - fclose (opwfile); - fclose (pwfile); - } + if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } + if (fchmod(fileno(pwfile), st.st_mode) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } - tmpent = fgetpwent (opwfile); + tmpent = fgetpwent(opwfile); while (tmpent) { if (!strcmp(tmpent->pw_name, forwho)) { /* To shut gcc up */ @@ -422,7 +583,7 @@ static int _update_passwd(pam_handle_t *pamh, err = 0; } if (putpwent(tmpent, pwfile)) { - D(("error writing entry to password file: %s\n", strerror(errno))); + D(("error writing entry to password file: %m")); err = 1; break; } @@ -431,19 +592,33 @@ static int _update_passwd(pam_handle_t *pamh, fclose(opwfile); if (fclose(pwfile)) { - D(("error writing entries to password file: %s\n", strerror(errno))); + D(("error writing entries to password file: %m")); err = 1; } +done: if (!err) { - if (!rename(PW_TMPFILE, "/etc/passwd")) { - _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); - return PAM_SUCCESS; - } + if (!rename(PW_TMPFILE, "/etc/passwd")) + pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho); + else + err = 1; + } +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + if (setfscreatecon(prev_context)) { + err = 1; + } + if (prev_context) + freecon(prev_context); + prev_context=NULL; + } +#endif + if (!err) { + return PAM_SUCCESS; + } else { + unlink(PW_TMPFILE); + return PAM_AUTHTOK_ERR; } - - unlink(PW_TMPFILE); - return PAM_AUTHTOK_ERR; } static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) @@ -459,37 +634,58 @@ static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) return PAM_USER_UNKNOWN; } oldmask = umask(077); + +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + security_context_t shadow_context=NULL; + if (getfilecon("/etc/shadow",&shadow_context)<0) { + return PAM_AUTHTOK_ERR; + }; + if (getfscreatecon(&prev_context)<0) { + freecon(shadow_context); + return PAM_AUTHTOK_ERR; + } + if (setfscreatecon(shadow_context)) { + freecon(shadow_context); + freecon(prev_context); + return PAM_AUTHTOK_ERR; + } + freecon(shadow_context); + } +#endif pwfile = fopen(SH_TMPFILE, "w"); umask(oldmask); if (pwfile == NULL) { - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } opwfile = fopen("/etc/shadow", "r"); if (opwfile == NULL) { fclose(pwfile); - return PAM_AUTHTOK_ERR; + err = 1; + goto done; } - if (fstat (fileno (opwfile), &st) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } + if (fstat(fileno(opwfile), &st) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } - if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } - if (fchmod (fileno (pwfile), st.st_mode) == -1) - { - fclose (opwfile); - fclose (pwfile); - return PAM_AUTHTOK_ERR; - } + if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } + if (fchmod(fileno(pwfile), st.st_mode) == -1) { + fclose(opwfile); + fclose(pwfile); + err = 1; + goto done; + } stmpent = fgetspent(opwfile); while (stmpent) { @@ -502,7 +698,7 @@ static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) } if (putspent(stmpent, pwfile)) { - D(("error writing entry to shadow file: %s\n", strerror(errno))); + D(("error writing entry to shadow file: %m")); err = 1; break; } @@ -512,26 +708,45 @@ static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) fclose(opwfile); if (fclose(pwfile)) { - D(("error writing entries to shadow file: %s\n", strerror(errno))); + D(("error writing entries to shadow file: %m")); err = 1; } + done: if (!err) { - if (!rename(SH_TMPFILE, "/etc/shadow")) { - _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); - return PAM_SUCCESS; - } + if (!rename(SH_TMPFILE, "/etc/shadow")) + pam_syslog(pamh, LOG_NOTICE, "password changed for %s", forwho); + else + err = 1; + } + +#ifdef WITH_SELINUX + if (SELINUX_ENABLED) { + if (setfscreatecon(prev_context)) { + err = 1; + } + if (prev_context) + freecon(prev_context); + prev_context=NULL; } +#endif - unlink(SH_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!err) { + return PAM_SUCCESS; + } else { + unlink(SH_TMPFILE); + return PAM_AUTHTOK_ERR; + } } -static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, +static int _do_setpass(pam_handle_t* pamh, const char *forwho, + const char *fromwhat, char *towhat, unsigned int ctrl, int remember) { struct passwd *pwd = NULL; int retval = 0; + int unlocked = 0; + char *master = NULL; D(("called")); @@ -542,35 +757,19 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, goto done; } - if (_unix_comesfromsource(pamh, forwho, 1, 0)) { - /* first, save old password */ - if (save_old_password(pamh, forwho, fromwhat, remember)) { - retval = PAM_AUTHTOK_ERR; - goto done; - } - if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { - retval = _update_shadow(pamh, forwho, towhat); - if (retval == PAM_SUCCESS) - if (!_unix_shadowed(pwd)) - retval = _update_passwd(pamh, forwho, "x"); - } else { - retval = _update_passwd(pamh, forwho, towhat); - } - } else if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { + if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { + if ((master=getNISserver(pamh)) != NULL) { struct timeval timeout; struct yppasswd yppwd; CLIENT *clnt; - char *master; int status; - int err = 0; + enum clnt_stat err; /* Unlock passwd file to avoid deadlock */ #ifdef USE_LCKPWDF ulckpwdf(); #endif - /* Make RPC call to NIS server */ - if ((master = getNISserver(pamh)) == NULL) - return PAM_TRY_AGAIN; + unlocked = 1; /* Initialize password information */ yppwd.newpw.pw_passwd = pwd->pw_passwd; @@ -580,7 +779,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, yppwd.newpw.pw_gecos = pwd->pw_gecos; yppwd.newpw.pw_dir = pwd->pw_dir; yppwd.newpw.pw_shell = pwd->pw_shell; - yppwd.oldpass = fromwhat ? fromwhat : ""; + yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup (""); yppwd.newpw.pw_passwd = towhat; D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); @@ -600,29 +799,73 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, (xdrproc_t) xdr_int, (char *) &status, timeout); + free (yppwd.oldpass); + if (err) { - clnt_perrno(err); - retval = PAM_TRY_AGAIN; + _make_remark(pamh, ctrl, PAM_TEXT_INFO, + clnt_sperrno(err)); } else if (status) { D(("Error while changing NIS password.\n")); - retval = PAM_TRY_AGAIN; } D(("The password has%s been changed on %s.", (err || status) ? " not" : "", master)); - _log_err(LOG_NOTICE, pamh, "password%s changed for %s on %s", + pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s", (err || status) ? " not" : "", pwd->pw_name, master); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); - if ((err || status) != 0) { + if (err || status) { + _make_remark(pamh, ctrl, PAM_TEXT_INFO, + _("NIS password could not be changed.")); retval = PAM_TRY_AGAIN; } #ifdef DEBUG sleep(5); #endif - return retval; + } else { + retval = PAM_TRY_AGAIN; + } } + if (_unix_comesfromsource(pamh, forwho, 1, 0)) { +#ifdef USE_LCKPWDF + if(unlocked) { + int i = 0; + /* These values for the number of attempts and the sleep time + are, of course, completely arbitrary. + My reading of the PAM docs is that, once pam_chauthtok() has been + called with PAM_UPDATE_AUTHTOK, we are obliged to take any + reasonable steps to make sure the token is updated; so retrying + for 1/10 sec. isn't overdoing it. */ + while((retval = lckpwdf()) != 0 && i < 100) { + usleep(1000); + i++; + } + if(retval != 0) { + return PAM_AUTHTOK_LOCK_BUSY; + } + } +#endif + /* first, save old password */ + if (save_old_password(pamh, forwho, fromwhat, remember)) { + retval = PAM_AUTHTOK_ERR; + goto done; + } + if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { + retval = _update_shadow(pamh, forwho, towhat); +#ifdef WITH_SELINUX + if (retval != PAM_SUCCESS && SELINUX_ENABLED) + retval = _unix_run_shadow_binary(pamh, ctrl, forwho, fromwhat, towhat); +#endif + if (retval == PAM_SUCCESS) + if (!_unix_shadowed(pwd)) + retval = _update_passwd(pamh, forwho, "x"); + } else { + retval = _update_passwd(pamh, forwho, towhat); + } + } + + done: #ifdef USE_LCKPWDF ulckpwdf(); @@ -631,7 +874,7 @@ done: return retval; } -static int _unix_verify_shadow(const char *user, unsigned int ctrl) +static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl) { struct passwd *pwd = NULL; /* Password and shadow password */ struct spwd *spwdent = NULL; /* file entries for the user */ @@ -650,6 +893,10 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) spwdent = getspnam(user); endspent(); +#ifdef WITH_SELINUX + if (spwdent == NULL && SELINUX_ENABLED ) + spwdent = _unix_run_verify_binary(pamh, ctrl, user); +#endif if (spwdent == NULL) return PAM_AUTHINFO_UNAVAIL; } else { @@ -674,10 +921,22 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) if (off(UNIX__IAMROOT, ctrl)) { /* Get the current number of days since 1970 */ curdays = time(NULL) / (60 * 60 * 24); - if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) - && (spwdent->sp_min != -1)) + if (curdays < spwdent->sp_lstchg) { + pam_syslog(pamh, LOG_DEBUG, + "account %s has password changed in future", + user); + curdays = spwdent->sp_lstchg; + } + if ((curdays - spwdent->sp_lstchg < spwdent->sp_min) + && (spwdent->sp_min != -1)) + /* + * The last password change was too recent. + */ retval = PAM_AUTHTOK_ERR; - else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) + else if ((curdays - spwdent->sp_lstchg > spwdent->sp_max) + && (curdays - spwdent->sp_lstchg > spwdent->sp_inact) + && (curdays - spwdent->sp_lstchg > + spwdent->sp_max + spwdent->sp_inact) && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1) && (spwdent->sp_lstchg != 0)) /* @@ -700,7 +959,7 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh ,const char *pass_old ,const char *pass_new) { - const char *user; + const void *user; const char *remark = NULL; int retval = PAM_SUCCESS; @@ -710,10 +969,10 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) { if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_DEBUG, pamh, "bad authentication token"); + pam_syslog(pamh, LOG_DEBUG, "bad authentication token"); } _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? - "No password supplied" : "Password unchanged"); + _("No password supplied") : _("Password unchanged")); return PAM_AUTHTOK_ERR; } /* @@ -721,27 +980,27 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh * checking this would be the place - AGM */ - retval = pam_get_item(pamh, PAM_USER, (const void **) &user); + retval = pam_get_item(pamh, PAM_USER, &user); if (retval != PAM_SUCCESS) { if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_ERR, pamh, "Can not get username"); + pam_syslog(pamh, LOG_ERR, "Can not get username"); return PAM_AUTHTOK_ERR; } } if (off(UNIX__IAMROOT, ctrl)) { #ifdef USE_CRACKLIB - remark = FascistCheck(pass_new, CRACKLIB_DICTS); + remark = FascistCheck (pass_new, CRACKLIB_DICTS); D(("called cracklib [%s]", remark)); #else if (strlen(pass_new) < 6) - remark = "You must choose a longer password"; + remark = _("You must choose a longer password"); D(("length check [%s]", remark)); #endif if (on(UNIX_REMEMBER_PASSWD, ctrl)) { if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR) - remark = "Password has been already used. Choose another."; + remark = _("Password has been already used. Choose another."); if (retval == PAM_ABORT) { - _log_err(LOG_ERR, pamh, "can't open %s file to check old passwords", + pam_syslog(pamh, LOG_ERR, "can't open %s file to check old passwords", OLD_PASSWORDS_FILE); return retval; } @@ -764,7 +1023,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, /* <DO NOT free() THESE> */ const char *user; - char *pass_old, *pass_new; + const void *pass_old, *pass_new; /* </DO NOT free() THESE> */ D(("called.")); @@ -778,20 +1037,19 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval == PAM_SUCCESS) { /* * Various libraries at various times have had bugs related to - * '+' or '-' as the first character of a user name. Don't take - * any chances here. Require that the username starts with an - * alphanumeric character. + * '+' or '-' as the first character of a user name. Don't + * allow them. */ - if (user == NULL || !isalnum(*user)) { - _log_err(LOG_ERR, pamh, "bad username [%s]", user); + if (user == NULL || user[0] == '-' || user[0] == '+') { + pam_syslog(pamh, LOG_ERR, "bad username [%s]", user); return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) - _log_err(LOG_DEBUG, pamh, "username [%s] obtained", + pam_syslog(pamh, LOG_DEBUG, "username [%s] obtained", user); } else { if (on(UNIX_DEBUG, ctrl)) - _log_err(LOG_DEBUG, pamh, + pam_syslog(pamh, LOG_DEBUG, "password - could not identify user"); return retval; } @@ -805,23 +1063,23 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * getpwnam() doesn't tell you *where* the information it gives you * came from, nor should it. That's our job. */ - if (_unix_comesfromsource(pamh, user, 1, 1) == 0) { - _log_err(LOG_DEBUG, pamh, - "user \"%s\" does not exist in /etc/passwd or NIS", - user); + if (_unix_comesfromsource(pamh, user, 1, on(UNIX_NIS, ctrl)) == 0) { + pam_syslog(pamh, LOG_DEBUG, + "user \"%s\" does not exist in /etc/passwd%s", + user, on(UNIX_NIS, ctrl) ? " or NIS" : ""); return PAM_USER_UNKNOWN; } else { struct passwd *pwd; _unix_getpwnam(pamh, user, 1, 1, &pwd); if (pwd == NULL) { - _log_err(LOG_DEBUG, pamh, + pam_syslog(pamh, LOG_DEBUG, "user \"%s\" has corrupted passwd entry", user); return PAM_USER_UNKNOWN; } if (!_unix_shadowed(pwd) && (strchr(pwd->pw_passwd, '*') != NULL)) { - _log_err(LOG_DEBUG, pamh, + pam_syslog(pamh, LOG_DEBUG, "user \"%s\" does not have modifiable password", user); return PAM_USER_UNKNOWN; @@ -846,32 +1104,27 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (_unix_blankpasswd(pamh, ctrl, user)) { return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { - /* instruct user what is happening */ -#define greeting "Changing password for " - Announce = (char *) malloc(sizeof(greeting) + strlen(user)); - if (Announce == NULL) { - _log_err(LOG_CRIT, pamh, + if (asprintf(&Announce, _("Changing password for %s."), + user) < 0) { + pam_syslog(pamh, LOG_CRIT, "password - out of memory"); return PAM_BUF_ERR; } - (void) strcpy(Announce, greeting); - (void) strcpy(Announce + sizeof(greeting) - 1, user); -#undef greeting lctrl = ctrl; set(UNIX__OLD_PASSWD, lctrl); retval = _unix_read_password(pamh, lctrl ,Announce - ,"(current) UNIX password: " + ,_("(current) UNIX password: ") ,NULL ,_UNIX_OLD_AUTHTOK - ,(const char **) &pass_old); + ,&pass_old); free(Announce); if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh - ,"password - (old) token not obtained"); + pam_syslog(pamh, LOG_NOTICE, + "password - (old) token not obtained"); return retval; } /* verify that this is the password for this user */ @@ -891,14 +1144,14 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { - _log_err(LOG_CRIT, pamh, + pam_syslog(pamh, LOG_CRIT, "failed to set PAM_OLDAUTHTOK"); } - retval = _unix_verify_shadow(user, ctrl); + retval = _unix_verify_shadow(pamh,user, ctrl); if (retval == PAM_AUTHTOK_ERR) { if (off(UNIX__IAMROOT, ctrl)) _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "You must wait longer to change your password"); + _("You must wait longer to change your password")); else retval = PAM_SUCCESS; } @@ -925,10 +1178,10 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (off(UNIX_NOT_SET_PASS, ctrl)) { retval = pam_get_item(pamh, PAM_OLDAUTHTOK - ,(const void **) &pass_old); + ,&pass_old); } else { retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK - ,(const void **) &pass_old); + ,&pass_old); if (retval == PAM_NO_MODULE_DATA) { retval = PAM_SUCCESS; pass_old = NULL; @@ -937,7 +1190,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("pass_old [%s]", pass_old)); if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated"); + pam_syslog(pamh, LOG_NOTICE, "user not authenticated"); return retval; } @@ -958,15 +1211,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = _unix_read_password(pamh, lctrl ,NULL - ,"Enter new UNIX password: " - ,"Retype new UNIX password: " + ,_("Enter new UNIX password: ") + ,_("Retype new UNIX password: ") ,_UNIX_NEW_AUTHTOK - ,(const char **) &pass_new); + ,&pass_new); if (retval != PAM_SUCCESS) { if (on(UNIX_DEBUG, ctrl)) { - _log_err(LOG_ALERT, pamh - ,"password - new password not obtained"); + pam_syslog(pamh, LOG_ALERT, + "password - new password not obtained"); } pass_old = NULL; /* tidy up */ return retval; @@ -979,14 +1232,14 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * password is acceptable. */ - if (pass_new[0] == '\0') { /* "\0" password = NULL */ + if (*(const char *)pass_new == '\0') { /* "\0" password = NULL */ pass_new = NULL; } retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); } if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, + pam_syslog(pamh, LOG_NOTICE, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ return retval; @@ -1011,7 +1264,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (pass_old) { retval = _unix_verify_password(pamh, user, pass_old, ctrl); if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user password changed by another process"); + pam_syslog(pamh, LOG_NOTICE, "user password changed by another process"); #ifdef USE_LCKPWDF ulckpwdf(); #endif @@ -1019,9 +1272,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, } } - retval = _unix_verify_shadow(user, ctrl); + retval = _unix_verify_shadow(pamh, user, ctrl); if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); + pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2"); #ifdef USE_LCKPWDF ulckpwdf(); #endif @@ -1030,7 +1283,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, + pam_syslog(pamh, LOG_NOTICE, "new password not acceptable 2"); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF @@ -1074,7 +1327,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, char *temp = malloc(9); if (temp == NULL) { - _log_err(LOG_CRIT, pamh, + pam_syslog(pamh, LOG_CRIT, "out of memory for password"); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF @@ -1106,7 +1359,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */ - _log_err(LOG_ALERT, pamh, + pam_syslog(pamh, LOG_ALERT, "password received unknown request"); retval = PAM_ABORT; } |