summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Mraz <tmraz@redhat.com>2011-12-06 21:07:55 +0100
committerTomas Mraz <tmraz@redhat.com>2011-12-06 21:07:55 +0100
commitf717780594c26f4c6269f41ae8b987fd2745eec4 (patch)
tree9ca075e17837a9a9e935b6e4ba1f9859f68b4a31 /src
parentcb78be53487398294025da3f7bf1da5cc46b941a (diff)
downloadlibpwquality-f717780594c26f4c6269f41ae8b987fd2745eec4.tar.gz
Add checks for words from passwd GECOS field and for maximum consecutive characters of same class.
Diffstat (limited to 'src')
-rw-r--r--src/check.c94
-rw-r--r--src/error.c8
-rw-r--r--src/pwqprivate.h4
-rw-r--r--src/pwquality.conf11
-rw-r--r--src/pwquality.h4
-rw-r--r--src/settings.c17
6 files changed, 130 insertions, 8 deletions
diff --git a/src/check.c b/src/check.c
index 2a42931..ca815b0 100644
--- a/src/check.c
+++ b/src/check.c
@@ -10,6 +10,9 @@
#include <string.h>
#include <ctype.h>
#include <crack.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
#include "pwquality.h"
#include "pwqprivate.h"
@@ -199,16 +202,47 @@ simple(pwquality_settings_t *pwq, const char *new, void **auxerror)
int others = 0;
int size;
int i;
+ enum { NONE, DIGIT, UCASE, LCASE, OTHER } prevclass = NONE;
+ int sameclass = 0;
for (i = 0; new[i]; i++) {
- if (isdigit(new[i]))
+ if (isdigit(new[i])) {
digits++;
- else if (isupper(new[i]))
+ if (prevclass != DIGIT) {
+ prevclass = DIGIT;
+ sameclass = 1;
+ } else
+ sameclass++;
+ }
+ else if (isupper(new[i])) {
uppers++;
- else if (islower(new[i]))
+ if (prevclass != UCASE) {
+ prevclass = UCASE;
+ sameclass = 1;
+ } else
+ sameclass++;
+ }
+ else if (islower(new[i])) {
lowers++;
- else
+ if (prevclass != LCASE) {
+ prevclass = LCASE;
+ sameclass = 1;
+ } else
+ sameclass++;
+ }
+ else {
others++;
+ if (prevclass != OTHER) {
+ prevclass = OTHER;
+ sameclass = 1;
+ } else
+ sameclass++;
+ }
+ if (pwq->max_class_repeat > 1 && sameclass > pwq->max_class_repeat) {
+ if (auxerror)
+ *auxerror = (void *)(long)pwq->max_class_repeat;
+ return PWQ_ERROR_MAX_CLASS_REPEAT;
+ }
}
if ((pwq->dig_credit >= 0) && (digits > pwq->dig_credit))
@@ -296,8 +330,9 @@ consecutive(pwquality_settings_t *pwq, const char *new, void **auxerror)
return 0;
}
-static int usercheck(pwquality_settings_t *pwq, const char *new,
- char *user)
+static int
+usercheck(pwquality_settings_t *pwq, const char *new,
+ char *user)
{
char *f, *b;
int dist;
@@ -346,6 +381,50 @@ str_lower(char *string)
return string;
}
+static int
+gecoscheck(pwquality_settings_t *pwq, const char *new,
+ const char *user)
+{
+ struct passwd pwd;
+ struct passwd *result;
+ char *buf;
+ size_t bufsize;
+ char *p;
+ char *next;
+
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize == -1 || bufsize > PWQ_MAX_PASSWD_BUF_LEN)
+ bufsize = PWQ_MAX_PASSWD_BUF_LEN;
+ buf = malloc(bufsize);
+ if (buf == NULL)
+ return PWQ_ERROR_MEM_ALLOC;
+
+ if (getpwnam_r(user, &pwd, buf, bufsize, &result) != 0 ||
+ result == NULL) {
+ free(buf);
+ return 0;
+ }
+
+ for (p = result->pw_gecos;;p = next + 1) {
+ next = strchr(p, ' ');
+ if (next)
+ *next = '\0';
+
+ if (strlen(p) >= PWQ_MIN_WORD_LENGTH) {
+ str_lower(p);
+ if (usercheck(pwq, new, p)) {
+ free(buf);
+ return PWQ_ERROR_GECOS_CHECK;
+ }
+ }
+
+ if (!next)
+ break;
+ }
+
+ return 0;
+}
+
static char *
x_strdup(const char *string)
{
@@ -413,6 +492,9 @@ password_check(pwquality_settings_t *pwq,
if (!rv && usermono && usercheck(pwq, newmono, usermono))
rv = PWQ_ERROR_USER_CHECK;
+ if (!rv && user && pwq->gecos_check)
+ rv = gecoscheck(pwq, newmono, user);
+
if (newmono) {
memset(newmono, 0, strlen(newmono));
free(newmono);
diff --git a/src/error.c b/src/error.c
index 9a69741..cb4c89f 100644
--- a/src/error.c
+++ b/src/error.c
@@ -43,6 +43,8 @@ pwquality_strerror(char *buf, size_t len, int rv, void *auxerror)
return _("The password is too similar to the old one");
case PWQ_ERROR_USER_CHECK:
return _("The password contains the user name in some form");
+ case PWQ_ERROR_GECOS_CHECK:
+ return _("The password contains words from the real name of the user in some form");
case PWQ_ERROR_MIN_DIGITS:
if (auxerror) {
snprintf(buf, len, _("The password contains less than %ld digits"), (long)auxerror);
@@ -87,6 +89,12 @@ pwquality_strerror(char *buf, size_t len, int rv, void *auxerror)
return buf;
}
return _("The password contains too many same characters consecutively");
+ case PWQ_ERROR_MAX_CLASS_REPEAT:
+ if (auxerror) {
+ snprintf(buf, len, _("The password contains more than %ld characters of the same class consecutively"), (long)auxerror);
+ return buf;
+ }
+ return _("The password contains too many characters of the same class consecutively");
case PWQ_ERROR_EMPTY_PASSWORD:
return _("No password supplied");
case PWQ_ERROR_RNG:
diff --git a/src/pwqprivate.h b/src/pwqprivate.h
index 51e79e6..08b2d37 100644
--- a/src/pwqprivate.h
+++ b/src/pwqprivate.h
@@ -21,6 +21,8 @@ struct pwquality_settings {
int oth_credit;
int min_class;
int max_repeat;
+ int max_class_repeat;
+ int gecos_check;
char *dict_path;
};
@@ -44,6 +46,8 @@ struct setting_mapping {
#define PWQ_BASE_MIN_LENGTH 6 /* used when lower than this value of min len is set */
#define PWQ_NUM_CLASSES 4
#define PWQ_NUM_GENERATION_TRIES 3 /* how many times to try to generate the random password if it fails the check */
+#define PWQ_MIN_WORD_LENGTH 4
+#define PWQ_MAX_PASSWD_BUF_LEN 16300
#ifndef PWQUALITY_DEFAULT_CFGFILE
#define PWQUALITY_DEFAULT_CFGFILE "/etc/security/pwquality.conf"
diff --git a/src/pwquality.conf b/src/pwquality.conf
index c6b1729..cec450f 100644
--- a/src/pwquality.conf
+++ b/src/pwquality.conf
@@ -33,9 +33,18 @@
# password (digits, uppercase, lowercase, others).
# minclass = 0
#
-# The maximum number of allowed consecutive characters in the new password.
+# The maximum number of allowed consecutive same characters in the new password.
# The check is disabled if the value is 0.
# maxrepeat = 0
#
+# The maximum number of allowed consecutive characters of the same class in the
+# new password.
+# The check is disabled if the value is 0.
+# maxclassrepeat = 0
+#
+# Whether to check for the words from the passwd entry GECOS string of the user.
+# The check is enabled if the value is not 0.
+# gecoscheck = 0
+#
# Path to the cracklib dictionaries. Default is to use the cracklib default.
# dictpath =
diff --git a/src/pwquality.h b/src/pwquality.h
index fcb379f..2ea40b1 100644
--- a/src/pwquality.h
+++ b/src/pwquality.h
@@ -19,6 +19,8 @@
#define PWQ_SETTING_MIN_CLASS 8
#define PWQ_SETTING_MAX_REPEAT 9
#define PWQ_SETTING_DICT_PATH 10
+#define PWQ_SETTING_MAX_CLASS_REPEAT 11
+#define PWQ_SETTING_GECOS_CHECK 12
#define PWQ_MAX_ENTROPY_BITS 256
#define PWQ_MIN_ENTROPY_BITS 56
@@ -51,6 +53,8 @@
#define PWQ_ERROR_RNG -23
#define PWQ_ERROR_GENERATION_FAILED -24
#define PWQ_ERROR_USER_CHECK -25
+#define PWQ_ERROR_GECOS_CHECK -26
+#define PWQ_ERROR_MAX_CLASS_REPEAT -27
typedef struct pwquality_settings pwquality_settings_t;
diff --git a/src/settings.c b/src/settings.c
index 6c42c19..3e45f1c 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -57,6 +57,8 @@ static const struct setting_mapping s_map[] = {
{ "ocredit", PWQ_SETTING_OTH_CREDIT, PWQ_TYPE_INT},
{ "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},
+ { "gecoscheck", PWQ_SETTING_GECOS_CHECK, PWQ_TYPE_INT},
{ "dictpath", PWQ_SETTING_DICT_PATH, PWQ_TYPE_STR}
};
@@ -72,6 +74,7 @@ set_name_value(pwquality_settings_t *pwq, const char *name, const char *value)
if (strcasecmp(s_map[i].name, name) == 0) {
switch(s_map[i].type) {
case PWQ_TYPE_INT:
+fprintf(stderr, "Value: '%s'", value);
errno = 0;
val = strtol(value, &endptr, 10);
if (errno != 0 || *value == '\0' ||
@@ -195,7 +198,7 @@ pwquality_set_option(pwquality_settings_t *pwq, const char *option)
strncpy(name, option, len);
name[sizeof(name) - 1] = '\0';
-
+
return set_name_value(pwq, name, value);
}
@@ -232,6 +235,12 @@ pwquality_set_int_value(pwquality_settings_t *pwq, int setting, int value)
case PWQ_SETTING_MAX_REPEAT:
pwq->max_repeat = value;
break;
+ case PWQ_SETTING_MAX_CLASS_REPEAT:
+ pwq->max_class_repeat = value;
+ break;
+ case PWQ_SETTING_GECOS_CHECK:
+ pwq->gecos_check = value;
+ break;
default:
return PWQ_ERROR_NON_INT_SETTING;
}
@@ -294,6 +303,12 @@ pwquality_get_int_value(pwquality_settings_t *pwq, int setting, int *value)
case PWQ_SETTING_MAX_REPEAT:
*value = pwq->max_repeat;
break;
+ case PWQ_SETTING_MAX_CLASS_REPEAT:
+ *value = pwq->max_class_repeat;
+ break;
+ case PWQ_SETTING_GECOS_CHECK:
+ *value = pwq->gecos_check;
+ break;
default:
return PWQ_ERROR_NON_INT_SETTING;
}