From owner-freebsd-bugs@FreeBSD.ORG Tue Feb 8 19:30:10 2011 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 774451065695 for ; Tue, 8 Feb 2011 19:30:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 8DF478FC1B for ; Tue, 8 Feb 2011 19:30:08 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p18JU8oB044499 for ; Tue, 8 Feb 2011 19:30:08 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p18JU8id044496; Tue, 8 Feb 2011 19:30:08 GMT (envelope-from gnats) Resent-Date: Tue, 8 Feb 2011 19:30:08 GMT Resent-Message-Id: <201102081930.p18JU8id044496@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Ted Stodgell Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A89B7106566B for ; Tue, 8 Feb 2011 19:26:53 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id 8A81B8FC0A for ; Tue, 8 Feb 2011 19:26:53 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p18JQrQ9015929 for ; Tue, 8 Feb 2011 19:26:53 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id p18JQrYQ015928; Tue, 8 Feb 2011 19:26:53 GMT (envelope-from nobody) Message-Id: <201102081926.p18JQrYQ015928@red.freebsd.org> Date: Tue, 8 Feb 2011 19:26:53 GMT From: Ted Stodgell To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: misc/154597: pam_passwdqc incorrectly user their password must be MAX_INT characters long in some cases. X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 08 Feb 2011 19:30:10 -0000 >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@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: