From: Tobias Stoeckmann Date: Fri, 19 Dec 2025 11:36:59 +0000 (+0000) Subject: lib/obscure.c: Introduce obscure_get_range X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa889977190ad89664ef3a50db467d6c3a6878bc;p=thirdparty%2Fshadow.git lib/obscure.c: Introduce obscure_get_range Unify the retrieval of PASS_MIN_LEN and PASS_MAX_LEN for output in passwd and actual checks. Fixes wrong output for minimum password lengths if no such restriction is configured: 5 is printed, 0 is in effect. How to reproduce: 1. Use passwd compiled without PAM support 2. Do not specify PASS_MIN_LEN in login.defs 3. Run passwd as a user and enter your old password, then - you will see that 5 characters are expected - you can just press enter twice Signed-off-by: Tobias Stoeckmann --- diff --git a/lib/obscure.c b/lib/obscure.c index 3c723b2bf..c572b96a3 100644 --- a/lib/obscure.c +++ b/lib/obscure.c @@ -115,17 +115,17 @@ static /*@observer@*//*@null@*/const char *obscure_msg ( /*@notnull@*/const char *old, /*@notnull@*/const char *new) { - size_t maxlen, oldlen, newlen; - int minlen; + int maxlen, minlen; + size_t oldlen, newlen; char *new1, *old1; const char *msg; - const char *result; oldlen = strlen (old); newlen = strlen (new); - minlen = getdef_num ("PASS_MIN_LEN", 0); - if (minlen != -1 && newlen < (size_t) minlen) { + obscure_get_range(&minlen, &maxlen); + + if (newlen < (size_t) minlen) { return _("too short"); } @@ -141,47 +141,26 @@ static /*@observer@*//*@null@*/const char *obscure_msg ( return msg; } - result = getdef_str ("ENCRYPT_METHOD"); - if (NULL == result) { + if (maxlen == -1) { + return NULL; + } + /* The traditional crypt() truncates passwords to 8 chars. It is possible to circumvent the above checks by choosing an easy 8-char password and adding some random characters to it... Example: "password$%^&*123". So check it again, this time truncated to the maximum length. Idea from npasswd. --marekm */ - if (getdef_bool ("MD5_CRYPT_ENAB")) { - return NULL; - } - - } else { - - if ( streq(result, "MD5") -#ifdef USE_SHA_CRYPT - || streq(result, "SHA256") - || streq(result, "SHA512") -#endif -#ifdef USE_BCRYPT - || streq(result, "BCRYPT") -#endif -#ifdef USE_YESCRYPT - || streq(result, "YESCRYPT") -#endif - ) { - return NULL; - } - - } - maxlen = getdef_num ("PASS_MAX_LEN", 8); - if ( (oldlen <= maxlen) - && (newlen <= maxlen)) { + if ( (oldlen <= (size_t) maxlen) + && (newlen <= (size_t) maxlen)) { return NULL; } new1 = xstrdup (new); old1 = xstrdup (old); - if (newlen > maxlen) + if (newlen > (size_t) maxlen) stpcpy(&new1[maxlen], ""); - if (oldlen > maxlen) + if (oldlen > (size_t) maxlen) stpcpy(&old1[maxlen], ""); msg = password_check(old1, new1); @@ -211,3 +190,50 @@ obscure(const char *old, const char *new) } return true; } + +/* + * obscure_get_range - retrieve min and max password lengths + * + * Returns minimum and maximum allowed lengths of a password + * to pass obscure checks. + */ +void +obscure_get_range(int *minlen, int *maxlen) +{ + int val; + const char *method; + + /* Minimum length is 0, even if -1 is configured. */ + val = getdef_num("PASS_MIN_LEN", 0); + *minlen = val == -1 ? 0 : val; + + /* Maximum password length check is optional. */ + *maxlen = -1; + + if (!getdef_bool("OBSCURE_CHECKS_ENAB")) { + return; + } + + method = getdef_str ("ENCRYPT_METHOD"); + if (NULL == method) { + if (getdef_bool ("MD5_CRYPT_ENAB")) { + return; + } + } else { + if ( streq(method, "MD5") +#ifdef USE_SHA_CRYPT + || streq(method, "SHA256") + || streq(method, "SHA512") +#endif +#ifdef USE_BCRYPT + || streq(method, "BCRYPT") +#endif +#ifdef USE_YESCRYPT + || streq(method, "YESCRYPT") +#endif + ) { + return; + } + } + *maxlen = getdef_num ("PASS_MAX_LEN", 8); +} diff --git a/lib/prototypes.h b/lib/prototypes.h index d1fb9b878..c53f95443 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -302,6 +302,7 @@ extern int do_pam_passwd_non_interactive (const char *pam_service, /* obscure.c */ extern bool obscure (const char *, const char *); +extern void obscure_get_range(int *, int *); /* pam_pass.c */ #ifdef USE_PAM diff --git a/src/passwd.c b/src/passwd.c index 17c50787b..0afae4d7b 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -194,8 +194,6 @@ static int new_password (const struct passwd *pw) int i; /* Counter for retries */ int ret; bool warned; - int pass_max_len = -1; - const char *method; /* * Authenticate the user. The user will be prompted for their own @@ -245,41 +243,20 @@ static int new_password (const struct passwd *pw) * be optionally tested for strength. The root user can circumvent * tests. This provides an escape for initial login passwords. */ - method = getdef_str ("ENCRYPT_METHOD"); - if (NULL == method) { - if (!getdef_bool ("MD5_CRYPT_ENAB")) { - pass_max_len = getdef_num ("PASS_MAX_LEN", 8); - } - } else { - if ( streq(method, "MD5") -#ifdef USE_SHA_CRYPT - || streq(method, "SHA256") - || streq(method, "SHA512") -#endif /* USE_SHA_CRYPT */ -#ifdef USE_BCRYPT - || streq(method, "BCRYPT") -#endif /* USE_BCRYPT*/ -#ifdef USE_YESCRYPT - || streq(method, "YESCRYPT") -#endif /* USE_YESCRYPT*/ - - ) { - pass_max_len = -1; - } else { - pass_max_len = getdef_num ("PASS_MAX_LEN", 8); - } - } if (!qflg && !sflg) { + int pass_max_len, pass_min_len; + + obscure_get_range(&pass_min_len, &pass_max_len); if (pass_max_len == -1) { (void) printf (_( "Enter the new password (minimum of %d characters)\n" "Please use a combination of upper and lower case letters and numbers.\n"), - getdef_num ("PASS_MIN_LEN", 5)); + pass_min_len); } else { (void) printf (_( "Enter the new password (minimum of %d, maximum of %d characters)\n" "Please use a combination of upper and lower case letters and numbers.\n"), - getdef_num ("PASS_MIN_LEN", 5), pass_max_len); + pass_min_len, pass_max_len); } }