]> granicus.if.org Git - linux-pam/commitdiff
Relevant BUGIDs:
authorTomas Mraz <tm@t8m.info>
Fri, 19 Sep 2008 13:38:32 +0000 (13:38 +0000)
committerTomas Mraz <tm@t8m.info>
Fri, 19 Sep 2008 13:38:32 +0000 (13:38 +0000)
Purpose of commit: new feature

Commit summary:
---------------
2008-09-19  Tomas Mraz <t8m@centrum.cz>

        * modules/pam_cracklib/pam_cracklib.8.xml: Fix description
        of the palindrome test. Document new options maxrepeat and
        reject_username.
        * modules/pam_cracklib/pam_cracklib.c(_pam_parse): Parse
        the maxrepeat and reject_username options.
        (password_check): Call the new tests usercheck() and
        consecutive().
        (_pam_unix_approve_pass): Pass user name to the password_check().

ChangeLog
NEWS
modules/pam_cracklib/pam_cracklib.8.xml
modules/pam_cracklib/pam_cracklib.c

index 5da1343c4633794612ddf78cd2e47b476116bd53..5a6c2bba6bfcdead0a02ee8a0d7094cfa106cdee 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-09-19  Tomas Mraz <t8m@centrum.cz>
+
+       * modules/pam_cracklib/pam_cracklib.8.xml: Fix description
+       of the palindrome test. Document new options maxrepeat and
+       reject_username.
+       * modules/pam_cracklib/pam_cracklib.c(_pam_parse): Parse
+       the maxrepeat and reject_username options.
+       (password_check): Call the new tests usercheck() and
+       consecutive().
+       (_pam_unix_approve_pass): Pass user name to the password_check().
+
 2008-09-16  Thorsten Kukuk  <kukuk@thkukuk.de>
 
        * modules/pam_cracklib/pam_cracklib.8.xml: Fix typo.
diff --git a/NEWS b/NEWS
index e4e2b743392bdbef8f7c4c22a69b8142bf7c2c8b..5d9927b7b3b2feaf6a15fdd28efd899a98b26b7e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,11 +6,12 @@ Release 1.0.90
 * Supply hostname of the machine to netgroup match call in pam_access
 * Make pam_namespace to work safe on child directories of parent directories
   owned by users
-* Redifine LOCAL keyword of pam_access configuration file
+* Redefine LOCAL keyword of pam_access configuration file
 * Add support fro try_first_pass and use_first_pass to pam_cracklib
 * Print informative messages for rejected login and add silent and
   no_log_info options to pam_tally
-
+* Add support for passing PAM_AUTHTOK to stdin of helpers from pam_exec
+* New password quality tests in pam_cracklib
 
 Release 1.0.1
 
index 19b74d276933481d9b1dcf1d57abfb833c520352..3d061c433b4ecb532fd7a290648d3e1ece1d4203 100644 (file)
@@ -59,7 +59,7 @@
         <term>Palindrome</term>
         <listitem>
           <para>
-            Is the new password a palindrome of the old one?
+            Is the new password a palindrome?
           </para>
         </listitem>
       </varlistentry>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term>Same consecutive characters</term>
+        <listitem>
+          <para>
+            Optional check for same consecutive characters.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>Contains user name</term>
+        <listitem>
+          <para>
+            Optional check whether the password contains the user's name
+            in some form.
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
     <para>
       This module with no arguments will work well for standard unix
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>
+            <option>maxrepeat=<replaceable>N</replaceable></option>
+          </term>
+          <listitem>
+            <para>
+              Reject passwords which contain more than N same consecutive
+              characters. The default is 0 which means that this check
+              is disabled.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>
+            <option>reject_username</option>
+          </term>
+          <listitem>
+            <para>
+              Check whether the name of the user in straight or reversed
+              form is contained in the new password. If it is found the
+              new password is rejected.
+            </para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term>
             <option>use_authtok</option>
index 12cbcf3c29994afcf058571e68d2e29b68d270ff..3dcc4729abfadc6cfcbbef8bb84c6f42e14f1b16 100644 (file)
@@ -99,6 +99,8 @@ struct cracklib_options {
         int min_class;
        int use_authtok;
        int try_first_pass;
+       int max_repeat;
+       int reject_user;
        char prompt_type[BUFSIZ];
         const char *cracklib_dictpath;
 };
@@ -166,8 +168,14 @@ _pam_parse (pam_handle_t *pamh, struct cracklib_options *opt,
              opt->min_class = strtol(*argv+9,&ep,10);
              if (!ep)
                  opt->min_class = 0;
-                 if (opt->min_class > 4)
-                     opt->min_class = 4 ;
+             if (opt->min_class > 4)
+                 opt->min_class = 4;
+         } else if (!strncmp(*argv,"maxrepeat=",10)) {
+             opt->max_repeat = strtol(*argv+10,&ep,10);
+             if (!ep)
+                 opt->max_repeat = 0;
+        } else if (!strncmp(*argv,"reject_username",15)) {
+                opt->reject_user = 1;
         } else if (!strncmp(*argv,"use_authtok",11)) {
                 opt->use_authtok = 1;
         } else if (!strncmp(*argv,"use_first_pass",14)) {
@@ -418,6 +426,58 @@ static int simple(struct cracklib_options *opt, const char *new)
     return 1;
 }
 
+static int consecutive(struct cracklib_options *opt, const char *new)
+{
+    char c;
+    int i;
+    int same;
+
+    if (opt->max_repeat == 0)
+       return 0;
+
+    for (i = 0; new[i]; i++) {
+       if (i > 0 && new[i] == c) {
+           ++same;
+           if (same > opt->max_repeat)
+               return 1;
+       } else {
+           c = new[i];
+           same = 1;
+       }
+    }
+    return 0;
+}
+
+static int usercheck(struct cracklib_options *opt, const char *new,
+                    char *user)
+{
+    char *f, *b;
+
+    if (!opt->reject_user)
+       return 0;
+
+    if (strstr(new, user) != NULL)
+       return 1;
+
+    /* now reverse the username, we can do that in place
+       as it is strdup-ed */
+    f = user;
+    b = user+strlen(user)-1;    
+    while (f < b) {
+       char c;
+
+       c = *f;
+       *f = *b;
+       *b = c;
+       --b;
+       ++f;
+    }
+
+    if (strstr(new, user) != NULL)
+       return 1;
+    return 0;
+}
+
 static char * str_lower(char *string)
 {
        char *cp;
@@ -428,10 +488,12 @@ static char * str_lower(char *string)
 }
 
 static const char *password_check(struct cracklib_options *opt,
-                                 const char *old, const char *new)
+                                 const char *old, const char *new,
+                                 const char *user)
 {
        const char *msg = NULL;
        char *oldmono = NULL, *newmono, *wrapped = NULL;
+       char *usermono = NULL;
 
        if (old && strcmp(new, old) == 0) {
            msg = _("is the same as the old one");
@@ -439,6 +501,7 @@ static const char *password_check(struct cracklib_options *opt,
        }
 
        newmono = str_lower(x_strdup(new));
+       usermono = str_lower(x_strdup(user));
        if (old) {
          oldmono = str_lower(x_strdup(old));
          wrapped = malloc(strlen(oldmono) * 2 + 1);
@@ -464,8 +527,15 @@ static const char *password_check(struct cracklib_options *opt,
        if (!msg && minclass (opt, new))
                msg = _("not enough character classes");
 
+       if (!msg && consecutive(opt, new))
+               msg = _("contains too many same characters consecutively");
+
+       if (!msg && usercheck(opt, newmono, usermono))
+               msg = _("contains the user name in some form");
+
        memset(newmono, 0, strlen(newmono));
        free(newmono);
+       free(usermono);
        if (old) {
          memset(oldmono, 0, strlen(oldmono));
          memset(wrapped, 0, strlen(wrapped));
@@ -532,18 +602,18 @@ static int _pam_unix_approve_pass(pam_handle_t *pamh,
         return PAM_AUTHTOK_ERR;
     }
 
+    retval = pam_get_item(pamh, PAM_USER, &user);
+    if (retval != PAM_SUCCESS || user == NULL) {
+       if (ctrl & PAM_DEBUG_ARG)
+               pam_syslog(pamh,LOG_ERR,"Can not get username");
+       return PAM_AUTHTOK_ERR;
+    }
     /*
      * if one wanted to hardwire authentication token strength
      * checking this would be the place
      */
-    msg = password_check(opt, pass_old, pass_new);
+    msg = password_check(opt, pass_old, pass_new, user);
     if (!msg) {
-       retval = pam_get_item(pamh, PAM_USER, &user);
-       if (retval != PAM_SUCCESS || user == NULL) {
-           if (ctrl & PAM_DEBUG_ARG)
-               pam_syslog(pamh,LOG_ERR,"Can not get username");
-           return PAM_AUTHTOK_ERR;
-       }
        msg = check_old_password(user, pass_new);
     }