From 8bb171506fc2579669fd86bd29885f256e26ccb0 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Wed, 17 Feb 2016 14:21:41 +0100 Subject: pam_unix: Add no_pass_expiry option to ignore password expiration. * modules/pam_unix/pam_unix.8.xml: Document the no_pass_expiry option. * modules/pam_unix/pam_unix_acct.c (pam_sm_acct_mgmt): If no_pass_expiry is on and return value data is not set to PAM_SUCCESS then ignore PAM_NEW_AUTHTOK_REQD and PAM_AUTHTOK_EXPIRED returns. * modules/pam_unix/pam_unix_auth.c (pam_sm_authenticate): Always set the return value data. (pam_sm_setcred): Test for likeauth option and use the return value data only if set. * modules/pam_unix/support.h: Add the no_pass_expiry option. --- modules/pam_unix/pam_unix.8.xml | 19 +++++++++++++++++++ modules/pam_unix/pam_unix_acct.c | 13 +++++++++++++ modules/pam_unix/pam_unix_auth.c | 20 +++++++++++--------- modules/pam_unix/support.h | 6 ++++-- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/modules/pam_unix/pam_unix.8.xml b/modules/pam_unix/pam_unix.8.xml index a8b64bb5..6d8e4ba0 100644 --- a/modules/pam_unix/pam_unix.8.xml +++ b/modules/pam_unix/pam_unix.8.xml @@ -364,6 +364,25 @@ + + + + + + + When set ignore password expiration as defined by the + shadow entry of the user. The option has an + effect only in case pam_unix was not used + for the authentication or it returned authentication failure + meaning that other authentication source or method succeeded. + The example can be public key authentication in + sshd. The module will return + PAM_SUCCESS instead of eventual + PAM_NEW_AUTHTOK_REQD or + PAM_AUTHTOK_EXPIRED. + + + Invalid arguments are logged with diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c index 27998451..f8b39c91 100644 --- a/modules/pam_unix/pam_unix_acct.c +++ b/modules/pam_unix/pam_unix_acct.c @@ -235,6 +235,19 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) } else retval = check_shadow_expiry(pamh, spent, &daysleft); + if (on(UNIX_NO_PASS_EXPIRY, ctrl)) { + const void *pretval = NULL; + int authrv = PAM_AUTHINFO_UNAVAIL; /* authentication not called */ + + if (pam_get_data(pamh, "unix_setcred_return", &pretval) == PAM_SUCCESS + && pretval) + authrv = *(const int *)pretval; + + if (authrv != PAM_SUCCESS + && (retval == PAM_NEW_AUTHTOK_REQD || retval == PAM_AUTHTOK_EXPIRED)) + retval = PAM_SUCCESS; + } + switch (retval) { case PAM_ACCT_EXPIRED: pam_syslog(pamh, LOG_NOTICE, diff --git a/modules/pam_unix/pam_unix_auth.c b/modules/pam_unix/pam_unix_auth.c index 44573e6c..9a547b3a 100644 --- a/modules/pam_unix/pam_unix_auth.c +++ b/modules/pam_unix/pam_unix_auth.c @@ -82,14 +82,13 @@ #define AUTH_RETURN \ do { \ - if (on(UNIX_LIKE_AUTH, ctrl) && ret_data) { \ + if (ret_data) { \ D(("recording return code for next time [%d]", \ retval)); \ *ret_data = retval; \ pam_set_data(pamh, "unix_setcred_return", \ (void *) ret_data, setcred_free); \ - } else if (ret_data) \ - free (ret_data); \ + } \ D(("done. [%s]", pam_strerror(pamh, retval))); \ return retval; \ } while (0) @@ -115,9 +114,8 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv); /* Get a few bytes so we can pass our return value to - pam_sm_setcred(). */ - if (on(UNIX_LIKE_AUTH, ctrl)) - ret_data = malloc(sizeof(int)); + pam_sm_setcred() and pam_sm_acct_mgmt(). */ + ret_data = malloc(sizeof(int)); /* get the user'name' */ @@ -194,20 +192,24 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) */ int -pam_sm_setcred (pam_handle_t *pamh, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) +pam_sm_setcred (pam_handle_t *pamh, int flags, + int argc, const char **argv) { int retval; const void *pretval = NULL; + unsigned int ctrl; D(("called.")); + ctrl = _set_ctrl(pamh, flags, NULL, NULL, NULL, argc, argv); + retval = PAM_SUCCESS; D(("recovering return code from auth call")); /* We will only find something here if UNIX_LIKE_AUTH is set -- don't worry about an explicit check of argv. */ - if (pam_get_data(pamh, "unix_setcred_return", &pretval) == PAM_SUCCESS + if (on(UNIX_LIKE_AUTH, ctrl) + && pam_get_data(pamh, "unix_setcred_return", &pretval) == PAM_SUCCESS && pretval) { retval = *(const int *)pretval; pam_set_data(pamh, "unix_setcred_return", NULL, NULL); diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h index 3729ce0c..b767c265 100644 --- a/modules/pam_unix/support.h +++ b/modules/pam_unix/support.h @@ -98,9 +98,10 @@ typedef struct { #define UNIX_BLOWFISH_PASS 26 /* new password hashes will use blowfish */ #define UNIX_MIN_PASS_LEN 27 /* min length for password */ #define UNIX_QUIET 28 /* Don't print informational messages */ -#define UNIX_DES 29 /* DES, default */ +#define UNIX_NO_PASS_EXPIRY 29 /* Don't check for password expiration if not used for authentication */ +#define UNIX_DES 30 /* DES, default */ /* -------------- */ -#define UNIX_CTRLS_ 30 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 31 /* 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)) @@ -138,6 +139,7 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = /* UNIX_BLOWFISH_PASS */ {"blowfish", _ALL_ON_^(0260420000), 0200000000, 1}, /* UNIX_MIN_PASS_LEN */ {"minlen=", _ALL_ON_, 0400000000, 0}, /* UNIX_QUIET */ {"quiet", _ALL_ON_, 01000000000, 0}, +/* UNIX_NO_PASS_EXPIRY */ {"no_pass_expiry", _ALL_ON_, 02000000000, 0}, /* UNIX_DES */ {"des", _ALL_ON_^(0260420000), 0, 1}, }; -- cgit v1.2.3