]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
lib/obscure.c: Introduce obscure_get_range
authorTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 19 Dec 2025 11:36:59 +0000 (11:36 +0000)
committerAlejandro Colomar <foss+github@alejandro-colomar.es>
Sat, 20 Dec 2025 19:22:50 +0000 (20:22 +0100)
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 <tobias@stoeckmann.org>
lib/obscure.c
lib/prototypes.h
src/passwd.c

index 3c723b2bff0e97328280c2c437b3fd70bb1ed59d..c572b96a343e1feb88a40757a6419963b9eb43a5 100644 (file)
@@ -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);
+}
index d1fb9b8789149540ab21c505649b52099ec682ad..c53f954432f5d9836a8400661f57bb56b5b20fff 100644 (file)
@@ -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
index 17c50787ba14f191f42e69b2fb68554c01d43053..0afae4d7beaad1f92bdbd822401e9532e082f849 100644 (file)
@@ -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);
                }
        }