diff options
-rw-r--r-- | modules/pam_unix/pam_unix.8.xml | 13 | ||||
-rw-r--r-- | modules/pam_unix/pam_unix_acct.c | 26 | ||||
-rw-r--r-- | modules/pam_unix/support.c | 47 | ||||
-rw-r--r-- | modules/pam_unix/support.h | 7 |
4 files changed, 67 insertions, 26 deletions
diff --git a/modules/pam_unix/pam_unix.8.xml b/modules/pam_unix/pam_unix.8.xml index 93a01c89..607ec85c 100644 --- a/modules/pam_unix/pam_unix.8.xml +++ b/modules/pam_unix/pam_unix.8.xml @@ -165,6 +165,19 @@ </varlistentry> <varlistentry> <term> + <option>nullresetok</option> + </term> + <listitem> + <para> + Allow users to authenticate with blank password if password reset + is enforced even if <option>nullok</option> is not set. If password + reset is not required and <option>nullok</option> is not set the + authentication with blank password will be denied. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> <option>try_first_pass</option> </term> <listitem> diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c index 36f68eff..0c5dff96 100644 --- a/modules/pam_unix/pam_unix_acct.c +++ b/modules/pam_unix/pam_unix_acct.c @@ -192,8 +192,6 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) const void *void_uname; const char *uname; int retval, daysleft; - struct spwd *spent; - struct passwd *pwent; char buf[256]; D(("called.")); @@ -210,29 +208,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) return PAM_USER_UNKNOWN; } - retval = get_account_info(pamh, uname, &pwent, &spent); - if (retval == PAM_USER_UNKNOWN) { - pam_syslog(pamh, LOG_ERR, - "could not identify user (from getpwnam(%s))", - uname); - return retval; - } - - if (retval == PAM_SUCCESS && spent == NULL) - return PAM_SUCCESS; - - if (retval == PAM_UNIX_RUN_HELPER) { - retval = _unix_run_verify_binary(pamh, ctrl, uname, &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); + retval = _unix_verify_user(pamh, ctrl, uname, &daysleft); if (on(UNIX_NO_PASS_EXPIRY, ctrl)) { const void *pretval = NULL; diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c index 33761840..6a840a26 100644 --- a/modules/pam_unix/support.c +++ b/modules/pam_unix/support.c @@ -595,6 +595,7 @@ _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name { struct passwd *pwd = NULL; char *salt = NULL; + int daysleft; int retval; D(("called")); @@ -605,6 +606,15 @@ _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name * 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 */ @@ -796,6 +806,43 @@ cleanup: 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. diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h index e02c05e0..19754dc1 100644 --- a/modules/pam_unix/support.h +++ b/modules/pam_unix/support.h @@ -100,8 +100,9 @@ typedef struct { #define UNIX_DES 30 /* DES, default */ #define UNIX_GOST_YESCRYPT_PASS 31 /* new password hashes will use gost-yescrypt */ #define UNIX_YESCRYPT_PASS 32 /* new password hashes will use yescrypt */ +#define UNIX_NULLRESETOK 33 /* allow empty password if password reset is enforced */ /* -------------- */ -#define UNIX_CTRLS_ 33 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 34 /* number of ctrl arguments defined */ #define UNIX_DES_CRYPT(ctrl) (off(UNIX_MD5_PASS,ctrl)&&off(UNIX_BIGCRYPT,ctrl)&&off(UNIX_SHA256_PASS,ctrl)&&off(UNIX_SHA512_PASS,ctrl)&&off(UNIX_BLOWFISH_PASS,ctrl)&&off(UNIX_GOST_YESCRYPT_PASS,ctrl)&&off(UNIX_YESCRYPT_PASS,ctrl)) @@ -143,6 +144,7 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = /* UNIX_DES */ {"des", _ALL_ON_^(015660420000ULL), 0, 1}, /* UNIX_GOST_YESCRYPT_PASS */ {"gost_yescrypt", _ALL_ON_^(015660420000ULL), 04000000000, 1}, /* UNIX_YESCRYPT_PASS */ {"yescrypt", _ALL_ON_^(015660420000ULL), 010000000000, 1}, +/* UNIX_NULLRESETOK */ {"nullresetok", _ALL_ON_, 020000000000, 0}, }; #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) @@ -171,6 +173,9 @@ extern int _unix_blankpasswd(pam_handle_t *pamh, unsigned long long ctrl, extern int _unix_verify_password(pam_handle_t * pamh, const char *name, const char *p, unsigned long long ctrl); +extern int _unix_verify_user(pam_handle_t *pamh, unsigned long long ctrl, + const char *name, int *daysleft); + extern int _unix_run_verify_binary(pam_handle_t *pamh, unsigned long long ctrl, const char *user, int *daysleft); |