diff -up Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.8.xml.pwquality Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.8.xml
--- Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.8.xml.pwquality 2007-11-06 15:58:54.000000000 +0100
+++ Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.8.xml 2008-09-23 15:06:40.000000000 +0200
@@ -59,7 +59,7 @@
Palindrome
- Is the new password a palindrome of the old one?
+ Is the new password a palindrome?
@@ -120,6 +120,23 @@
+
+ Same consecutive characters
+
+
+ Optional check for same consecutive characters.
+
+
+
+
+ Contains user name
+
+
+ Optional check whether the password contains the user's name
+ in some form.
+
+
+
This module with no arguments will work well for standard unix
@@ -281,7 +298,7 @@
than 10.
- (N > 0) This is the minimum number of upper
+ (N < 0) This is the minimum number of upper
case letters that must be met for a new password.
@@ -349,6 +366,50 @@
+
+
+
+
+ The minimum number of required classes of characters for
+ the new password. The default number is zero. The four
+ classes are digits, upper and lower letters and other
+ characters.
+ The difference to the check is
+ that a specific class if of characters is not required.
+ Instead N out of four of the
+ classes are required.
+
+
+
+
+
+
+
+
+
+
+ Reject passwords which contain more than N same consecutive
+ characters. The default is 0 which means that this check
+ is disabled.
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
@@ -495,7 +556,7 @@ password required pam_unix.so use_autht
pam.conf5
,
- pam.d8
+ pam.d5,
pam8
diff -up Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.c.pwquality Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.c
--- Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.c.pwquality 2008-09-23 15:06:40.000000000 +0200
+++ Linux-PAM-1.0.2/modules/pam_cracklib/pam_cracklib.c 2008-09-23 15:10:14.000000000 +0200
@@ -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 c
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_option
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
}
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
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_ha
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);
}