misc/154597: pam_passwdqc incorrectly user their password must be MAX_INT characters long in some cases.

Ted Stodgell ted.stodgell at nasa.gov
Tue Feb 8 19:30:10 UTC 2011


>Number:         154597
>Category:       misc
>Synopsis:       pam_passwdqc incorrectly user their password must be MAX_INT characters long in some cases.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Tue Feb 08 19:30:08 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Ted Stodgell
>Release:        8-STABLE
>Organization:
NASA Marshall Spaceflight Center
>Environment:
FreeBSD groundemu3.fddrlab.msfc.nasa.gov 8.2-RC3 FreeBSD 8.2-RC3 #6: Mon Feb  7 10:28:26 CST 2011     root at groundemu3.fddrlab.msfc.nasa.gov:/usr/obj/usr/src/sys/GROUNDEMU-B  i386

>Description:
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!
>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.
>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:

--- 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;
 


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list