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 memset(classes, 0, sizeof(struct password_classes));
43 for (p = password; *p != '\0'; p++) {
44 if (islower((unsigned char) *p))
45 classes->lower = true;
46 else if (isupper((unsigned char) *p))
47 classes->upper = true;
48 else if (isdigit((unsigned char) *p))
49 classes->digit = true;
51 classes->symbol = true;
57 * Check whether a password satisfies a required character class rule, given
58 * the length of the password and the classes. Returns 0 if it does and a
59 * Kerberos error code if it does not.
61 static krb5_error_code
62 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
63 struct password_classes *classes)
65 if (length < rule->min || (rule->max > 0 && length > rule->max))
67 if (rule->lower && !classes->lower)
68 return MUST_HAVE(ctx, "a lowercase letter");
69 if (rule->upper && !classes->upper)
70 return MUST_HAVE(ctx, "an uppercase letter");
71 if (rule->digit && !classes->digit)
72 return MUST_HAVE(ctx, "a number");
73 if (rule->symbol && !classes->symbol)
74 return MUST_HAVE(ctx, "a space or punctuation character");
80 * Check whether a password satisfies the configured character class
84 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
87 struct password_classes classes;
89 struct class_rule *rule;
92 if (data->rules == NULL)
94 analyze_password(password, &classes);
95 length = strlen(password);
96 for (rule = data->rules; rule != NULL; rule = rule->next) {
97 code = check_rule(ctx, rule, length, &classes);