From ee8bbeb05d4f2ee929bddf1f268160e767598400 Mon Sep 17 00:00:00 2001 From: Gabe Date: Thu, 23 Aug 2018 10:31:35 -0600 Subject: Move retry, enforce_for_root, local_users_only options to pwquality.conf - retry, enforce_for_root, local_users_only options can now be configured in pwquality.conf - Fixes RHBZ#1537240 --- doc/man/pwquality.conf.5.pod | 20 ++++++++++++++++++++ src/pam_pwquality.c | 33 ++++++++++++++++----------------- src/pwqprivate.h | 6 ++++++ src/pwquality.conf | 12 ++++++++++++ src/pwquality.h | 3 +++ src/settings.c | 23 ++++++++++++++++++++++- 6 files changed, 79 insertions(+), 18 deletions(-) diff --git a/doc/man/pwquality.conf.5.pod b/doc/man/pwquality.conf.5.pod index 4d90285..47d6fd0 100644 --- a/doc/man/pwquality.conf.5.pod +++ b/doc/man/pwquality.conf.5.pod @@ -129,6 +129,26 @@ not created yet. Path to the cracklib dictionaries. Default is to use the cracklib default. +=item BI + +Prompt user at most I times before returning with error. The default is +I<1>. + +=item B + +The module will return error on failed check even if the user changing the +password is root. This option is off by default which means that just +the message about the failed check is printed but root can change +the password anyway. Note that root is not asked for an old password +so the checks that compare the old and new password are not performed. + +=item B + +The module will not test the password quality for users that are not present +in the F file. The module still asks for the password so +the following modules in the stack can use the B option. +This option is off by default. + =back =head1 SEE ALSO diff --git a/src/pam_pwquality.c b/src/pam_pwquality.c index 9c9849d..9d210e8 100644 --- a/src/pam_pwquality.c +++ b/src/pam_pwquality.c @@ -38,9 +38,6 @@ #define PAM_DEBUG_ARG 0x0001 struct module_options { - int retry_times; - int enforce_for_root; - int local_users_only; pwquality_settings_t *pwq; }; @@ -76,15 +73,7 @@ _pam_parse (pam_handle_t *pamh, struct module_options *opt, ctrl |= PAM_DEBUG_ARG; else if (!strncmp(*argv, "type=", 5)) pam_set_item (pamh, PAM_AUTHTOK_TYPE, *argv+5); - else if (!strncmp(*argv, "retry=", 6)) { - opt->retry_times = strtol(*argv+6, &ep, 10); - if (!ep || (opt->retry_times < 1)) - opt->retry_times = CO_RETRY_TIMES; - } else if (!strncmp(*argv, "enforce_for_root", 16)) { - opt->enforce_for_root = 1; - } else if (!strncmp(*argv, "local_users_only", 16)) { - opt->local_users_only = 1; - } else if (!strncmp(*argv, "difignore=", 10)) { + else if (!strncmp(*argv, "difignore=", 10)) { /* ignored for compatibility with pam_cracklib */ } else if (!strncmp(*argv, "reject_username", 15)) { /* ignored for compatibility with pam_cracklib */ @@ -157,14 +146,19 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, { int ctrl; struct module_options options; + int retry_times = CO_RETRY_TIMES; memset(&options, 0, sizeof(options)); - options.retry_times = CO_RETRY_TIMES; ctrl = _pam_parse(pamh, &options, argc, argv); if (ctrl < 0) return PAM_BUF_ERR; + pwquality_get_int_value(options.pwq, PWQ_SETTING_RETRY_TIMES, &retry_times); + if (retry_times < 1) + retry_times = CO_RETRY_TIMES; + + if (flags & PAM_PRELIM_CHECK) { /* Check for passwd dictionary * We cannot do that, since the original path is compiled @@ -194,9 +188,10 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, } tries = 0; - while (tries < options.retry_times) { + while (tries < retry_times) { void *auxerror; const char *newtoken = NULL; + int local_users_only = 0; tries++; @@ -218,8 +213,9 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, pwquality_free_settings(options.pwq); return PAM_AUTHTOK_ERR; } + pwquality_get_int_value(options.pwq, PWQ_SETTING_LOCAL_USERS, &local_users_only); - if (options.local_users_only && check_local_user (pamh, user) == 0) { + if (local_users_only && check_local_user (pamh, user) == 0) { /* skip the check if a non-local user */ retval = 0; } else { @@ -231,13 +227,16 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, const char *msg; char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; int enforcing = 1; + int enforce_for_root = 0; + msg = pwquality_strerror(buf, sizeof(buf), retval, auxerror); if (ctrl & PAM_DEBUG_ARG) pam_syslog(pamh, LOG_DEBUG, "bad password: %s", msg); pam_error(pamh, _("BAD PASSWORD: %s"), msg); pwquality_get_int_value(options.pwq, PWQ_SETTING_ENFORCING, &enforcing); + pwquality_get_int_value(options.pwq, PWQ_SETTING_ENFORCE_ROOT, &enforce_for_root); - if (enforcing && (getuid() || options.enforce_for_root || + if (enforcing && (getuid() || enforce_for_root || (flags & PAM_CHANGE_EXPIRED_AUTHTOK))) { pam_set_item(pamh, PAM_AUTHTOK, NULL); retval = PAM_AUTHTOK_ERR; @@ -271,7 +270,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* if we have only one try, we can use the real reason, * else say that there were too many tries. */ - if (options.retry_times > 1) + if (retry_times > 1) return PAM_MAXTRIES; else return PAM_AUTHTOK_ERR; diff --git a/src/pwqprivate.h b/src/pwqprivate.h index 4ac96a7..38fc93f 100644 --- a/src/pwqprivate.h +++ b/src/pwqprivate.h @@ -27,6 +27,9 @@ struct pwquality_settings { int dict_check; int user_check; int enforcing; + int retry_times; + int enforce_for_root; + int local_users_only; char *bad_words; char *dict_path; }; @@ -46,6 +49,9 @@ struct setting_mapping { #define PWQ_DEFAULT_DICT_CHECK 1 #define PWQ_DEFAULT_USER_CHECK 1 #define PWQ_DEFAULT_ENFORCING 1 +#define PWQ_DEFAULT_RETRY_TIMES 1 +#define PWQ_DEFAULT_ENFORCE_ROOT 0 +#define PWQ_DEFAULT_LOCAL_USERS 0 #define PWQ_TYPE_INT 1 #define PWQ_TYPE_STR 2 diff --git a/src/pwquality.conf b/src/pwquality.conf index 550036d..1b05cb4 100644 --- a/src/pwquality.conf +++ b/src/pwquality.conf @@ -61,3 +61,15 @@ # # Path to the cracklib dictionaries. Default is to use the cracklib default. # dictpath = +# +# Prompt user at most N times before returning with error. The default is 1. +# retry = 3 +# +# Enforces pwquality checks on the root user password. +# Enabled if the option is present. +# enforce_for_root +# +# Skip testing the password quality for users that are not present in the +# /etc/passwd file. +# Enabled if the option is present. +# local_users_only diff --git a/src/pwquality.h b/src/pwquality.h index 0666735..3d61fd6 100644 --- a/src/pwquality.h +++ b/src/pwquality.h @@ -30,6 +30,9 @@ extern "C" { #define PWQ_SETTING_DICT_CHECK 15 #define PWQ_SETTING_USER_CHECK 16 #define PWQ_SETTING_ENFORCING 17 +#define PWQ_SETTING_RETRY_TIMES 18 +#define PWQ_SETTING_ENFORCE_ROOT 19 +#define PWQ_SETTING_LOCAL_USERS 20 #define PWQ_MAX_ENTROPY_BITS 256 #define PWQ_MIN_ENTROPY_BITS 56 diff --git a/src/settings.c b/src/settings.c index 4b026b1..4f11537 100644 --- a/src/settings.c +++ b/src/settings.c @@ -36,6 +36,9 @@ pwquality_default_settings(void) pwq->dict_check = PWQ_DEFAULT_DICT_CHECK; pwq->user_check = PWQ_DEFAULT_USER_CHECK; pwq->enforcing = PWQ_DEFAULT_ENFORCING; + pwq->retry_times = PWQ_DEFAULT_RETRY_TIMES; + pwq->enforce_for_root = PWQ_DEFAULT_ENFORCE_ROOT; + pwq->local_users_only = PWQ_DEFAULT_LOCAL_USERS; return pwq; } @@ -68,7 +71,10 @@ static const struct setting_mapping s_map[] = { { "usercheck", PWQ_SETTING_USER_CHECK, PWQ_TYPE_INT}, { "enforcing", PWQ_SETTING_ENFORCING, PWQ_TYPE_INT}, { "badwords", PWQ_SETTING_BAD_WORDS, PWQ_TYPE_STR}, - { "dictpath", PWQ_SETTING_DICT_PATH, PWQ_TYPE_STR} + { "dictpath", PWQ_SETTING_DICT_PATH, PWQ_TYPE_STR}, + { "retry", PWQ_SETTING_RETRY_TIMES, PWQ_TYPE_INT}, + { "enforce_for_root", PWQ_SETTING_ENFORCE_ROOT, PWQ_TYPE_SET}, + { "local_users_only", PWQ_SETTING_LOCAL_USERS, PWQ_TYPE_SET} }; /* set setting name with value */ @@ -344,6 +350,12 @@ pwquality_set_int_value(pwquality_settings_t *pwq, int setting, int value) case PWQ_SETTING_ENFORCING: pwq->enforcing = value; break; + case PWQ_SETTING_RETRY_TIMES: + pwq->retry_times = value; + case PWQ_SETTING_ENFORCE_ROOT: + pwq->enforce_for_root = value; + case PWQ_SETTING_LOCAL_USERS: + pwq->local_users_only = value; default: return PWQ_ERROR_NON_INT_SETTING; } @@ -430,6 +442,15 @@ pwquality_get_int_value(pwquality_settings_t *pwq, int setting, int *value) case PWQ_SETTING_ENFORCING: *value = pwq->enforcing; break; + case PWQ_SETTING_RETRY_TIMES: + *value = pwq->retry_times; + break; + case PWQ_SETTING_ENFORCE_ROOT: + *value = pwq->enforce_for_root; + break; + case PWQ_SETTING_LOCAL_USERS: + *value = pwq->local_users_only; + break; default: return PWQ_ERROR_NON_INT_SETTING; } -- cgit v1.2.1