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>
7 * Copyright 2016 Russ Allbery <eagle@eyrie.org>
9 * The Board of Trustees of the Leland Stanford Junior University
11 * SPDX-License-Identifier: MIT
15 #include <portable/system.h>
19 #include <plugin/internal.h>
21 /* Stores the characteristics of a particular password as boolean flags. */
22 struct password_classes {
27 unsigned long num_classes;
32 * Analyze a password and fill out a struct with flags indicating which
33 * character classes are present in the password.
36 analyze_password(const char *password, struct password_classes *classes)
40 memset(classes, 0, sizeof(struct password_classes));
41 for (p = password; *p != '\0'; p++) {
42 if (islower((unsigned char) *p))
43 classes->lower = true;
44 else if (isupper((unsigned char) *p))
45 classes->upper = true;
46 else if (isdigit((unsigned char) *p))
47 classes->digit = true;
49 classes->symbol = true;
52 classes->num_classes++;
54 classes->num_classes++;
56 classes->num_classes++;
58 classes->num_classes++;
63 * Check whether a password satisfies a required character class rule, given
64 * the length of the password and the classes. Returns 0 if it does and a
65 * Kerberos error code if it does not.
67 static krb5_error_code
68 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
69 struct password_classes *classes)
71 if (length < rule->min || (rule->max > 0 && length > rule->max))
73 if (classes->num_classes < rule->num_classes)
74 return strength_error_class(ctx, ERROR_CLASS_MIN, rule->num_classes);
75 if (rule->lower && !classes->lower)
76 return strength_error_class(ctx, ERROR_CLASS_LOWER);
77 if (rule->upper && !classes->upper)
78 return strength_error_class(ctx, ERROR_CLASS_UPPER);
79 if (rule->digit && !classes->digit)
80 return strength_error_class(ctx, ERROR_CLASS_DIGIT);
81 if (rule->symbol && !classes->symbol)
82 return strength_error_class(ctx, ERROR_CLASS_SYMBOL);
88 * Check whether a password satisfies the configured character class
92 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
95 struct password_classes classes;
97 struct class_rule *rule;
100 if (data->rules == NULL)
102 analyze_password(password, &classes);
103 length = strlen(password);
104 for (rule = data->rules; rule != NULL; rule = rule->next) {
105 code = check_rule(ctx, rule, length, &classes);