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