File: classes.c

package info (click to toggle)
krb5-strength 3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 2,668 kB
  • ctags: 876
  • sloc: sh: 11,907; ansic: 8,234; perl: 1,208; makefile: 167
file content (102 lines) | stat: -rw-r--r-- 2,830 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * Password strength checks for character classes.
 *
 * Checks whether the password satisfies a set of character class rules.
 *
 * Written by Russ Allbery <eagle@eyrie.org>
 * Copyright 2013
 *     The Board of Trustees of the Leland Stanford Junior University
 *
 * See LICENSE for licensing terms.
 */

#include <config.h>
#include <portable/system.h>

#include <ctype.h>

#include <plugin/internal.h>

/* Stores the characteristics of a particular password as boolean flags. */
struct password_classes {
    bool lower;
    bool upper;
    bool digit;
    bool symbol;
};

/* Abbreviate the most common error reporting syntax. */
#define MUST_HAVE(ctx, err) \
    strength_error_class((ctx), "password must contain " err)


/*
 * Analyze a password and fill out a struct with flags indicating which
 * character classes are present in the password.
 */
static void
analyze_password(const char *password, struct password_classes *classes)
{
    const char *p;

    memset(classes, 0, sizeof(struct password_classes));
    for (p = password; *p != '\0'; p++) {
        if (islower((unsigned char) *p))
            classes->lower = true;
        else if (isupper((unsigned char) *p))
            classes->upper = true;
        else if (isdigit((unsigned char) *p))
            classes->digit = true;
        else
            classes->symbol = true;
    }
}


/*
 * Check whether a password satisfies a required character class rule, given
 * the length of the password and the classes.  Returns 0 if it does and a
 * Kerberos error code if it does not.
 */
static krb5_error_code
check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
           struct password_classes *classes)
{
    if (length < rule->min || (rule->max > 0 && length > rule->max))
        return 0;
    if (rule->lower && !classes->lower)
        return MUST_HAVE(ctx, "a lowercase letter");
    if (rule->upper && !classes->upper)
        return MUST_HAVE(ctx, "an uppercase letter");
    if (rule->digit && !classes->digit)
        return MUST_HAVE(ctx, "a number");
    if (rule->symbol && !classes->symbol)
        return MUST_HAVE(ctx, "a space or punctuation character");
    return 0;
}


/*
 * Check whether a password satisfies the configured character class
 * restrictions.
 */
krb5_error_code
strength_check_classes(krb5_context ctx, krb5_pwqual_moddata data,
                       const char *password)
{
    struct password_classes classes;
    size_t length;
    struct class_rule *rule;
    krb5_error_code code;

    if (data->rules == NULL)
        return 0;
    analyze_password(password, &classes);
    length = strlen(password);
    for (rule = data->rules; rule != NULL; rule = rule->next) {
        code = check_rule(ctx, rule, length, &classes);
        if (code != 0)
            return code;
    }
    return 0;
}