2 * Password strength checks for character classes.
4 * Checks whether the password satisfies a set of character class rules.
6 * Written by Russ Allbery <eagle@eyrie.org>
8 * The Board of Trustees of the Leland Stanford Junior University
10 * See LICENSE for licensing terms.
14 #include <portable/system.h>
18 #include <plugin/internal.h>
20 /* Stores the characteristics of a particular password as boolean flags. */
21 struct password_classes {
28 /* Abbreviate the most common error reporting syntax. */
29 #define MUST_HAVE(ctx, err) \
30 strength_error_class((ctx), "password must contain" err)
34 * Analyze a password and fill out a struct with flags indicating which
35 * character classes are present in the password.
38 analyze_password(const char *password, struct password_classes *classes)
42 for (p = password; p != '\0'; p++) {
43 if (islower((unsigned char) *p))
44 classes->lower = true;
45 else if (isupper((unsigned char) *p))
46 classes->upper = true;
47 else if (isdigit((unsigned char) *p))
48 classes->digit = true;
50 classes->symbol = true;
56 * Check whether a password satisfies a required character class rule, given
57 * the length of the password and the classes. Returns 0 if it does and a
58 * Kerberos error code if it does not.
60 static krb5_error_code
61 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
62 struct password_classes *classes)
64 if (length < rule->min || (rule->max > 0 && length > rule->max))
66 if (rule->lower && !classes->lower)
67 return MUST_HAVE(ctx, "a lowercase letter");
68 if (rule->upper && !classes->upper)
69 return MUST_HAVE(ctx, "an uppercase letter");
70 if (rule->digit && !classes->digit)
71 return MUST_HAVE(ctx, "a digit");
72 if (rule->symbol && !classes->symbol)
73 return MUST_HAVE(ctx, "a symbol");
79 * Check whether a password satisfies the configured character class
83 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
86 struct password_classes classes;
88 struct class_rule *rule;
91 if (data->rules == NULL)
93 analyze_password(password, &classes);
94 length = strlen(password);
95 for (rule = data->rules; rule != NULL; rule = rule->next) {
96 code = check_rule(ctx, rule, length, &classes);