Bug 154597 - [pam] pam_passwdqc incorrectly tells the user their password must be MAX_INT characters long in some cases
Summary: [pam] pam_passwdqc incorrectly tells the user their password must be MAX_INT ...
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Dag-Erling Smørgrav
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-08 19:30 UTC by Ted Stodgell
Modified: 2024-12-02 12:53 UTC (History)
2 users (show)

See Also:


Attachments
file.diff (3.22 KB, patch)
2011-02-08 19:30 UTC, Ted Stodgell
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ted Stodgell 2011-02-08 19:30:08 UTC
pam_passwdqc incorrectly user their password must be MAX_INT characters long in some cases. If you want to force users to use all 4 classes of character (i.e. uppercase, lowercase, numbers and symbols) the configuration is

min=disabled,disabled,disabled,disabled,[a number]

Unfortunately, pam_passwdc doesn't handle this situation corectly. It would say:

"A valid password should be a mix of upper and lower case letters,
digits and other characters.  You can use a 2147483647 character long
password with characters from at least 3 of these 4 classes, or
a 12 character long password containing characters from all the
classes.  Characters that form a common pattern are discarded by
the check."

We don't want to allow ANY passwords with only 3 classes of character. It's kind of dumb to suggest to a user that they could get away with a password that's 2147483647 characters long!

Fix: --- pam_passwdqc.c  2002-04-16 17:25:21.000000000 -0500
+++ pam_passwdqc.c.new  2011-02-08 10:33:05.000000000 -0600
@@ -100,15 +100,20 @@
    "a%s %d character long password containing characters from all the\n" \
    "classes.  Characters that form a common pattern are discarded by\n" \
    "the check.\n"
+#define MESSAGE_EXPLAIN_PASSWORD_3 \
+   "A valid password should be a mix of upper and lower case letters,\n" \
+   "digits and other characters.  You must use a%s %d character long\n" \
+   "password containing characters from all 4 classes. Characters that\n" \
+   "form a common pattern are discarded by the check.\n"
 #define MESSAGE_EXPLAIN_PASSPHRASE \
    "A passphrase should be of at least %d words, %d to %d characters\n" \
    "long and contain enough different characters.\n"
 #define MESSAGE_RANDOM \
-   "Alternatively, if noone else can see your terminal now, you can\n" \
+   "Alternatively, if no one else can see your terminal now, you can\n" \
    "pick this as your password: \"%s\".\n"
 #define MESSAGE_RANDOMONLY \
    "This system is configured to permit randomly generated passwords\n" \
-   "only.  If noone else can see your terminal now, you can pick this\n" \
+   "only.  If no one else can see your terminal now, you can pick this\n" \
    "as your password: \"%s\".  Otherwise, come back later.\n"
 #define MESSAGE_RANDOMFAILED \
    "This system is configured to use randomly generated passwords\n" \
@@ -201,6 +206,7 @@
            p = *argv + 4;
            for (i = 0; i < 5; i++) {
                if (!strncmp(p, "disabled", 8)) {
+                   /* disabled fields are set to INT_MAX */
                    v = INT_MAX;
                    p += 8;
                } else {
@@ -434,16 +440,44 @@
        return status;

    if (!randomonly && params.qc.min[3] <= params.qc.min[4])
+   /* Password needs at least 3 different classes of character.
+    * N4 is either larger than N3, or set to "disabled".
+    */
        status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_1,
            params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "",
            params.qc.min[3]);
    else
-   if (!randomonly)
+   if (!randomonly && INT_MAX != params.qc.min[3])
+   /* Password needs at least 3 different classes of character.
+    * N3 and N4 were both assigned numeric values.
+    */
        status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_2,
            params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "",
            params.qc.min[3],
            params.qc.min[4] == 8 || params.qc.min[4] == 11 ? "n" : "",
            params.qc.min[4]);
+   else
+   if (!randomonly)
+   /* Password must use all 4 different classes of character.
+     * Only N4 has a value.
+    *
+    * Previously, MESSAGE_EXPLAIN_PASSWORD_2 was used in cases
+    * where N3 was disabled and only N4 was defined with a value,
+    * e.g. min=disabled,disabled,disabled,disabled,12.
+    *
+    * When this happens,
+     * params.qc.min[3] gets set to MAX_INT, and
+    * MESSAGE_EXPLAN_PASSWORD_2 tells you that your password must
+    * be MAX_INT characters long if you want to use only 3 different
+    * classes of character!
+    *
+    * We don't want to allow only 3 classes of character... at all.
+    * Thus, MESSAGE_EXPLAIN_PASSWORD_3.
+    */
+       status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_3,
+           params.qc.min[4] == 8 || params.qc.min[4] == 11 ? "n" : "",
+           params.qc.min[4]);
+
    if (status != PAM_SUCCESS)
        return status;

Patch attached with submission follows:
How-To-Repeat: 1) Enable pam_passwdqc. Below is an example /etc/pam.d/passwd you can use:

#
# $FreeBSD: src/etc/pam.d/passwd,v 1.3.34.1.6.1 2010/12/21 17:09:25 kensmith Exp $
#
# PAM configuration for the "passwd" service
#

# passwd(1) does not use the auth, account or session services.

# password
password	requisite	pam_passwdqc.so		enforce=users min=disabled,disabled,disabled,disabled,12 max=40
password	required	pam_unix.so		no_warn try_first_pass nullok

2) Try changing your password with "passwd". You will get this message:

"A valid password should be a mix of upper and lower case letters,
digits and other characters.  You can use a [HUGE_NUMBER]* character long
password with characters from at least 3 of these 4 classes, or
a 12 character long password containing characters from all the
classes.  Characters that form a common pattern are discarded by
the check."

* this is MAX_INT on your architecture.

3) Unrelated problem: pam_passwdqc has 2 grammatical errors. Messages use the non-word "noone" instead of "no one". This is also fixed in the submitted patch.
Comment 1 Ted Stodgell 2011-02-08 19:40:32 UTC
Typo in PR synopisis, sorry! It should read,

=B3pam_passwdqc incorrectly *TELLS THE* user their password must be MAX_INT
characters long in some cases.=B2
-=20
Ted Stodgell
NASA Marshall Spaceflight Center
EV43, ISHM & Sensors
Office: 1 256 544 8365, Mobile: 1 832 620 6892
Comment 2 Graham Perrin freebsd_committer freebsd_triage 2022-10-17 12:36:35 UTC
Keyword: 

    patch
or  patch-ready

– in lieu of summary line prefix: 

    [patch]

* bulk change for the keyword
* summary lines may be edited manually (not in bulk). 

Keyword descriptions and search interface: 

    <https://bugs.freebsd.org/bugzilla/describekeywords.cgi>