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 {
30 * Analyze a password and fill out a struct with flags indicating which
31 * character classes are present in the password.
34 analyze_password(const char *password, struct password_classes *classes)
38 memset(classes, 0, sizeof(struct password_classes));
39 for (p = password; *p != '\0'; p++) {
40 if (islower((unsigned char) *p))
41 classes->lower = true;
42 else if (isupper((unsigned char) *p))
43 classes->upper = true;
44 else if (isdigit((unsigned char) *p))
45 classes->digit = true;
47 classes->symbol = true;
53 * Check whether a password satisfies a required character class rule, given
54 * the length of the password and the classes. Returns 0 if it does and a
55 * Kerberos error code if it does not.
57 static krb5_error_code
58 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
59 struct password_classes *classes)
61 if (length < rule->min || (rule->max > 0 && length > rule->max))
63 if (rule->lower && !classes->lower)
64 return strength_error_class((ctx), ERROR_CLASS_LOWER);
65 if (rule->upper && !classes->upper)
66 return strength_error_class((ctx), ERROR_CLASS_UPPER);
67 if (rule->digit && !classes->digit)
68 return strength_error_class((ctx), ERROR_CLASS_DIGIT);
69 if (rule->symbol && !classes->symbol)
70 return strength_error_class((ctx), ERROR_CLASS_SYMBOL);
76 * Check whether a password satisfies the configured character class
80 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
83 struct password_classes classes;
85 struct class_rule *rule;
88 if (data->rules == NULL)
90 analyze_password(password, &classes);
91 length = strlen(password);
92 for (rule = data->rules; rule != NULL; rule = rule->next) {
93 code = check_rule(ctx, rule, length, &classes);