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