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;
}
|