diff options
author | Tomas Mraz <tmraz@redhat.com> | 2011-12-06 21:07:55 +0100 |
---|---|---|
committer | Tomas Mraz <tmraz@redhat.com> | 2011-12-06 21:07:55 +0100 |
commit | f717780594c26f4c6269f41ae8b987fd2745eec4 (patch) | |
tree | 9ca075e17837a9a9e935b6e4ba1f9859f68b4a31 /src | |
parent | cb78be53487398294025da3f7bf1da5cc46b941a (diff) | |
download | libpwquality-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.c | 94 | ||||
-rw-r--r-- | src/error.c | 8 | ||||
-rw-r--r-- | src/pwqprivate.h | 4 | ||||
-rw-r--r-- | src/pwquality.conf | 11 | ||||
-rw-r--r-- | src/pwquality.h | 4 | ||||
-rw-r--r-- | src/settings.c | 17 |
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; } |