X-Git-Url: https://git.eyrie.org/?a=blobdiff_plain;f=plugin%2Fgeneral.c;fp=plugin%2Fgeneral.c;h=c491ea01b9522742e2fd2afc0ff4f5cb587a4ccd;hb=1b0d13931ea9d4f9dd0fda75bdd719dbc5255a34;hp=22690b1a78e17a711ea1cf4a646442a5c290a10a;hpb=fbb6f207f87df537570f410a2eaffde0f5921c4b;p=kerberos%2Fkrb5-strength.git diff --git a/plugin/general.c b/plugin/general.c index 22690b1..c491ea0 100644 --- a/plugin/general.c +++ b/plugin/general.c @@ -9,7 +9,7 @@ * Developed by Derrick Brashear and Ken Hornstein of Sine Nomine Associates, * on behalf of Stanford University * Extensive modifications by Russ Allbery - * Copyright 2006, 2007, 2009, 2012, 2013 + * Copyright 2006, 2007, 2009, 2012, 2013, 2014 * The Board of Trustees of the Leland Stanford Junior University * * See LICENSE for licensing terms. @@ -47,7 +47,8 @@ strength_init(krb5_context ctx, const char *dictionary, return strength_error_system(ctx, "cannot allocate memory"); data->cdb_fd = -1; - /* Get minimum length information from krb5.conf. */ + /* Get minimum length and character information from krb5.conf. */ + strength_config_number(ctx, "minimum_different", &data->minimum_different); strength_config_number(ctx, "minimum_length", &data->minimum_length); /* Get simple character class restrictions from krb5.conf. */ @@ -60,14 +61,17 @@ strength_init(krb5_context ctx, const char *dictionary, goto fail; /* - * Try to initialize CDB and CrackLib dictionaries. Both functions handle - * their own configuration parsing and will do nothing if the - * corresponding dictionary is not configured. + * Try to initialize CDB, CrackLib, and SQLite dictionaries. These + * functions handle their own configuration parsing and will do nothing if + * the corresponding dictionary is not configured. */ code = strength_init_cracklib(ctx, data, dictionary); if (code != 0) goto fail; code = strength_init_cdb(ctx, data); + if (code != 0) + goto fail; + code = strength_init_sqlite(ctx, data); if (code != 0) goto fail; @@ -113,6 +117,39 @@ only_alpha_space(const char *password) } +/* + * Check if a password has a sufficient number of unique characters. Takes + * the password and the required number of characters. + */ +static bool +has_minimum_different(const char *password, long minimum) +{ + size_t unique; + const char *p; + + /* Special cases for passwords of length 0 and a minimum <= 1. */ + if (password == NULL || password[0] == '\0') + return minimum <= 0; + if (minimum <= 1) + return true; + + /* + * Count the number of unique characters by incrementing the count if each + * subsequent character is not found in the previous password characters. + * This algorithm is O(n^2), but passwords are short enough it shouldn't + * matter. + */ + unique = 1; + for (p = password + 1; *p != '\0'; p++) + if (memchr(password, *p, p - password) == NULL) { + unique++; + if (unique >= (size_t) minimum) + return true; + } + return false; +} + + /* * Check a given password. Takes a Kerberos context, our module data, the * password, the principal the password is for, and a buffer and buffer length @@ -144,6 +181,11 @@ strength_check(krb5_context ctx UNUSED, krb5_pwqual_moddata data, if (data->nonletter && only_alpha_space(password)) return strength_error_class(ctx, ERROR_LETTER); + /* If desired, check for enough unique characters. */ + if (data->minimum_different > 0) + if (!has_minimum_different(password, data->minimum_different)) + return strength_error_class(ctx, ERROR_MINDIFF); + /* * If desired, check that the password satisfies character class * restrictions. @@ -157,11 +199,14 @@ strength_check(krb5_context ctx UNUSED, krb5_pwqual_moddata data, if (code != 0) return code; - /* Check the password against CDB and CrackLib if configured. */ + /* Check the password against CDB, CrackLib, and SQLite if configured. */ code = strength_check_cracklib(ctx, data, password); if (code != 0) return code; code = strength_check_cdb(ctx, data, password); + if (code != 0) + return code; + code = strength_check_sqlite(ctx, data, password); if (code != 0) return code; @@ -182,6 +227,7 @@ strength_close(krb5_context ctx UNUSED, krb5_pwqual_moddata data) if (data == NULL) return; strength_close_cdb(ctx, data); + strength_close_sqlite(ctx, data); last = data->rules; while (last != NULL) { tmp = last;