diff options
-rw-r--r-- | doc/man/pam_pwquality.8 | 26 | ||||
-rw-r--r-- | doc/man/pwquality.conf.5 | 9 | ||||
-rw-r--r-- | python/pwquality.c | 5 | ||||
-rw-r--r-- | src/check.c | 42 | ||||
-rw-r--r-- | src/error.c | 6 | ||||
-rw-r--r-- | src/pwqprivate.h | 1 | ||||
-rw-r--r-- | src/pwquality.h | 2 | ||||
-rw-r--r-- | src/settings.c | 1 |
8 files changed, 87 insertions, 5 deletions
diff --git a/doc/man/pam_pwquality.8 b/doc/man/pam_pwquality.8 index b8269de..863480f 100644 --- a/doc/man/pam_pwquality.8 +++ b/doc/man/pam_pwquality.8 @@ -27,7 +27,7 @@ new authentication token\&. The strength checks works in the following manner: at first the \fBCracklib\fR routine is called to check if the password is part of a dictionary; if this -is not the case an additional set of strength checks are done\&. These checks +is not the case an additional set of strength checks is done\&. These checks are: .PP Palindrome @@ -45,14 +45,16 @@ Similar Is the new password too much like the old one? This is primarily controlled by one argument, \fBdifok\fR -which is a number of changes between the old and new are enough to accept -the new password\&. +which is a number of character changes (inserts, removals, or replacements) +between the old and new password that are enough to accept the new +password\&. This defaults to 5 changes\&. .RE .PP Simple .RS 4 -Is the new password too small? This is controlled by 5 arguments +Is the new password too small? This is controlled by 6 arguments \fBminlen\fR, +\fBmaxclassrepeat\fR, \fBdcredit\fR, \fBucredit\fR, \fBlcredit\fR, and @@ -70,9 +72,14 @@ Same consecutive characters Optional check for same consecutive characters\&. .RE .PP +Too long monotonic character sequence +.RS 4 +Optional check for too long monotonic character sequence\&. +.RE +.PP Contains user name .RS 4 -Optional check whether the password contains the user name in some form\&. +Optional check whether the password contains the user\*(Aqs name in some form\&. .RE .PP These checks are configurable either by use of the module arguments @@ -217,6 +224,15 @@ Reject passwords which contain more than N same consecutive characters\&. The default is 0 which means that this check is disabled\&. .RE .PP +\fBmaxsequence=\fR\fB\fIN\fR\fR +.RS 4 +Reject passwords which contain monotonic character sequences longer than N\&. +The default is 0 which means that this check is disabled\&. +Examples of such sequence are \*(Aq12345\*(Aq or \*(Aqfedcb\*(Aq\&. Note that +most such passwords will not pass the simplicity check unless the sequence +is only a minor part of the password\&. +.RE +.PP \fBmaxclassrepeat=\fR\fB\fIN\fR\fR .RS 4 Reject passwords which contain more than N consecutive characters of the diff --git a/doc/man/pwquality.conf.5 b/doc/man/pwquality.conf.5 index 050d4eb..5302e50 100644 --- a/doc/man/pwquality.conf.5 +++ b/doc/man/pwquality.conf.5 @@ -73,6 +73,15 @@ The maximum number of allowed same consecutive characters in the new password. The check is disabled if the value is 0. (default 0) .RE .PP +\fBmaxsequence\fR +.RS 4 +The maximum length of monotonic character sequences in the new password. +Examples of such sequence are \*(Aq12345\*(Aq or \*(Aqfedcb\*(Aq\&. Note +that most such passwords will not pass the simplicity check unless +the sequence is only a minor part of the password. +The check is disabled if the value is 0. (default 0) +.RE +.PP \fBmaxclassrepeat\fR .RS 4 The maximum number of allowed consecutive characters of the same class in the diff --git a/python/pwquality.c b/python/pwquality.c index 68e55b6..18fd608 100644 --- a/python/pwquality.c +++ b/python/pwquality.c @@ -107,6 +107,11 @@ static PyGetSetDef pwqsettings_getseters[] = { "Maximum consecutive characters of the same class", (void *)PWQ_SETTING_MAX_CLASS_REPEAT }, + { "maxsequence", + (getter)pwqsettings_getint, (setter)pwqsettings_setint, + "Maximum length of a monotonic character sequence", + (void *)PWQ_SETTING_MAX_SEQUENCE + }, { "gecoscheck", (getter)pwqsettings_getint, (setter)pwqsettings_setint, "Match words from the passwd GECOS field if available", diff --git a/src/check.c b/src/check.c index 5303b51..f72c351 100644 --- a/src/check.c +++ b/src/check.c @@ -329,6 +329,45 @@ consecutive(pwquality_settings_t *pwq, const char *new, void **auxerror) return 0; } +static int sequence(pwquality_settings_t *pwq, const char *new, void **auxerror) +{ + char c; + int i; + int sequp = 1; + int seqdown = 1; + + if (pwq->max_sequence == 0) + return 0; + + if (new[0] == '\0') + return 0; + + for (i = 1; new[i]; i++) { + c = new[i-1]; + if (new[i] == c+1) { + ++sequp; + if (sequp > pwq->max_sequence) { + if (auxerror) + *auxerror = (void *)(long)pwq->max_sequence; + return 1; + } + seqdown = 1; + } else if (new[i] == c-1) { + ++seqdown; + if (seqdown > pwq->max_sequence) { + if (auxerror) + *auxerror = (void *)(long)pwq->max_sequence; + return 1; + } + sequp = 1; + } else { + sequp = 1; + seqdown = 1; + } + } + return 0; +} + static int usercheck(pwquality_settings_t *pwq, const char *new, char *user) @@ -511,6 +550,9 @@ password_check(pwquality_settings_t *pwq, if (!rv && consecutive(pwq, new, auxerror)) rv = PWQ_ERROR_MAX_CONSECUTIVE; + if (!rv && sequence(pwq, new, auxerror)) + rv = PWQ_ERROR_MAX_SEQUENCE; + if (!rv && usermono && usercheck(pwq, newmono, usermono)) rv = PWQ_ERROR_USER_CHECK; diff --git a/src/error.c b/src/error.c index 25e834b..4928097 100644 --- a/src/error.c +++ b/src/error.c @@ -97,6 +97,12 @@ pwquality_strerror(char *buf, size_t len, int rv, void *auxerror) return buf; } return _("The password contains too many characters of the same class consecutively"); + case PWQ_ERROR_MAX_SEQUENCE: + if (auxerror) { + snprintf(buf, len, _("The password contains monotonic sequence longer than %ld characters"), (long)auxerror); + return buf; + } + return _("The password contains too long of a monotonic character sequence"); case PWQ_ERROR_EMPTY_PASSWORD: return _("No password supplied"); case PWQ_ERROR_RNG: diff --git a/src/pwqprivate.h b/src/pwqprivate.h index 092a6f3..0e3df81 100644 --- a/src/pwqprivate.h +++ b/src/pwqprivate.h @@ -22,6 +22,7 @@ struct pwquality_settings { int min_class; int max_repeat; int max_class_repeat; + int max_sequence; int gecos_check; char *bad_words; char *dict_path; diff --git a/src/pwquality.h b/src/pwquality.h index e22b084..1657ca1 100644 --- a/src/pwquality.h +++ b/src/pwquality.h @@ -22,6 +22,7 @@ #define PWQ_SETTING_MAX_CLASS_REPEAT 11 #define PWQ_SETTING_GECOS_CHECK 12 #define PWQ_SETTING_BAD_WORDS 13 +#define PWQ_SETTING_MAX_SEQUENCE 14 #define PWQ_MAX_ENTROPY_BITS 256 #define PWQ_MIN_ENTROPY_BITS 56 @@ -57,6 +58,7 @@ #define PWQ_ERROR_GECOS_CHECK -26 #define PWQ_ERROR_MAX_CLASS_REPEAT -27 #define PWQ_ERROR_BAD_WORDS -28 +#define PWQ_ERROR_MAX_SEQUENCE -29 typedef struct pwquality_settings pwquality_settings_t; diff --git a/src/settings.c b/src/settings.c index f57db85..9ba3e62 100644 --- a/src/settings.c +++ b/src/settings.c @@ -57,6 +57,7 @@ static const struct setting_mapping s_map[] = { { "minclass", PWQ_SETTING_MIN_CLASS, PWQ_TYPE_INT}, { "maxrepeat", PWQ_SETTING_MAX_REPEAT, PWQ_TYPE_INT}, { "maxclassrepeat", PWQ_SETTING_MAX_CLASS_REPEAT, PWQ_TYPE_INT}, + { "maxsequence", PWQ_SETTING_MAX_SEQUENCE, PWQ_TYPE_INT}, { "gecoscheck", PWQ_SETTING_GECOS_CHECK, PWQ_TYPE_INT}, { "badwords", PWQ_SETTING_BAD_WORDS, PWQ_TYPE_STR}, { "dictpath", PWQ_SETTING_DICT_PATH, PWQ_TYPE_STR} |