]> eyrie.org Git - kerberos/krb5-strength.git/blob - plugin/classes.c
Begin error messages with a capital letter
[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, 2014
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
29 /*
30  * Analyze a password and fill out a struct with flags indicating which
31  * character classes are present in the password.
32  */
33 static void
34 analyze_password(const char *password, struct password_classes *classes)
35 {
36     const char *p;
37
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;
46         else
47             classes->symbol = true;
48     }
49 }
50
51
52 /*
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.
56  */
57 static krb5_error_code
58 check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
59            struct password_classes *classes)
60 {
61     if (length < rule->min || (rule->max > 0 && length > rule->max))
62         return 0;
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);
71     return 0;
72 }
73
74
75 /*
76  * Check whether a password satisfies the configured character class
77  * restrictions.
78  */
79 krb5_error_code
80 strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
81                        const char *password)
82 {
83     struct password_classes classes;
84     size_t length;
85     struct class_rule *rule;
86     krb5_error_code code;
87
88     if (data->rules == NULL)
89         return 0;
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);
94         if (code != 0)
95             return code;
96     }
97     return 0;
98 }