]> eyrie.org Git - kerberos/krb5-strength.git/blob - plugin/classes.c
683b5de255e00da4d194fe8fa1d4d799dd3639f1
[kerberos/krb5-strength.git] / plugin / classes.c
1 /*
2  * Password strength checks for character classes.
3  *
4  * Checks whether the password satisfies a set of character class rules.
5  *
6  * Written by Russ Allbery <eagle@eyrie.org>
7  * Copyright 2013
8  *     The Board of Trustees of the Leland Stanford Junior University
9  *
10  * See LICENSE for licensing terms.
11  */
12
13 #include <config.h>
14 #include <portable/system.h>
15
16 #include <ctype.h>
17
18 #include <plugin/internal.h>
19
20 /* Stores the characteristics of a particular password as boolean flags. */
21 struct password_classes {
22     bool lower;
23     bool upper;
24     bool digit;
25     bool symbol;
26 };
27
28 /* Abbreviate the most common error reporting syntax. */
29 #define MUST_HAVE(ctx, err) \
30     strength_error_class((ctx), "password must contain" err)
31
32
33 /*
34  * Analyze a password and fill out a struct with flags indicating which
35  * character classes are present in the password.
36  */
37 static void
38 analyze_password(const char *password, struct password_classes *classes)
39 {
40     const char *p;
41
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;
49         else
50             classes->symbol = true;
51     }
52 }
53
54
55 /*
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.
59  */
60 static krb5_error_code
61 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
62            struct password_classes *classes)
63 {
64     if (length < rule->min || (rule->max > 0 && length > rule->max))
65         return 0;
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");
74     return 0;
75 }
76
77
78 /*
79  * Check whether a password satisfies the configured character class
80  * restrictions.
81  */
82 krb5_error_code
83 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
84                        const char *password)
85 {
86     struct password_classes classes;
87     size_t length;
88     struct class_rule *rule;
89     krb5_error_code code;
90
91     if (data->rules == NULL)
92         return 0;
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);
97         if (code != 0)
98             return code;
99     }
100     return 0;
101 }