summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/man/pam_pwquality.826
-rw-r--r--doc/man/pwquality.conf.59
-rw-r--r--python/pwquality.c5
-rw-r--r--src/check.c42
-rw-r--r--src/error.c6
-rw-r--r--src/pwqprivate.h1
-rw-r--r--src/pwquality.h2
-rw-r--r--src/settings.c1
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}