2 * Check a CDB database for a password or some simple permutations.
4 * This file implements a much simpler variation on CrackLib checks intended
5 * for use with longer passwords where some of the CrackLib permutations don't
6 * make as much sense. A CDB database with passwords as keys is checked for
7 * the password and for variations with one character removed from the start
8 * or end, two characters removed from the start, two from the end, or one
9 * character from both start and end.
11 * Written by Russ Allbery <rra@stanford.edu>
13 * The Board of Trustees of the Leland Stanford Junior University
15 * See LICENSE for licensing terms.
19 #include <portable/kadmin.h>
20 #include <portable/krb5.h>
21 #include <portable/system.h>
30 #include <plugin/internal.h>
31 #include <util/macros.h>
35 * Stub for strength_init_cdb if not built with CDB support.
38 static krb5_error_code
39 strength_init_cdb(krb5_context ctx, krb5_pwqual_moddata data UNUSED,
40 const char *database UNUSED)
42 krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS, "CDB dictionary"
43 " requested but not built with CDB support");
44 return KADM5_BAD_SERVER_PARAMS;
49 /* Skip the rest of this file if CDB is not available. */
53 * Macro used to make password checks more readable. Assumes that the found
54 * and fail labels are available for the abort cases of finding a password or
55 * failing to look it up.
57 # define CHECK_PASSWORD(ctx, data, password) \
59 code = in_cdb_dictionary(ctx, data, password, &found); \
68 * Look up a password in CDB and set the found parameter to true if it is
69 * found, false otherwise. Returns a Kerberos status code, which will be 0 on
70 * success and something else on failure.
72 static krb5_error_code
73 in_cdb_dictionary(krb5_context ctx, krb5_pwqual_moddata data,
74 const char *password, bool *found)
78 status = cdb_find(&data->cdb, password, strlen(password));
80 return strength_error_system(ctx, "cannot query CDB database");
82 *found = (status == 1);
89 * Initialize the CDB dictionary. Opens the dictionary and sets up the
90 * TinyCDB state. Returns 0 on success, non-zero on failure (and sets the
91 * error in the Kerberos context). If not built with CDB support, always
95 strength_init_cdb(krb5_context ctx, krb5_pwqual_moddata data,
100 data->cdb_fd = open(path, O_RDONLY);
101 if (data->cdb_fd < 0)
102 return strength_error_system(ctx, "cannot open dictionary %s", path);
103 if (cdb_init(&data->cdb, data->cdb_fd) < 0) {
104 code = strength_error_system(ctx, "cannot init dictionary %s", path);
109 data->have_cdb = true;
115 * Given a password, try the various transformations that we want to apply and
116 * check for each of them in the dictionary. Returns a Kerberos status code,
117 * which will be KADM5_PASS_Q_DICT if the password was found in the
121 strength_check_cdb(krb5_context ctx, krb5_pwqual_moddata data,
122 const char *password)
124 krb5_error_code code;
126 char *variant = NULL;
128 /* Check the basic password. */
129 CHECK_PASSWORD(ctx, data, password);
131 /* Check with one or two characters removed from the start. */
132 if (password[0] != '\0') {
133 CHECK_PASSWORD(ctx, data, password + 1);
134 if (password[1] != '\0')
135 CHECK_PASSWORD(ctx, data, password + 2);
139 * Strip a character from the end and then check both that password and
140 * the one with a character taken from the start as well.
142 if (strlen(password) > 0) {
143 variant = strdup(password);
145 return strength_error_system(ctx, "cannot allocate memory");
146 variant[strlen(variant) - 1] = '\0';
147 CHECK_PASSWORD(ctx, data, variant);
148 if (variant[0] != '\0')
149 CHECK_PASSWORD(ctx, data, variant + 1);
151 /* Check the password with two characters removed. */
152 if (strlen(password) > 1) {
153 variant[strlen(variant) - 1] = '\0';
154 CHECK_PASSWORD(ctx, data, variant);
158 /* Password not found. */
163 /* We found the password or a variant in the dictionary. */
165 return strength_error_dict(ctx, ERROR_DICT);
168 /* Some sort of failure during CDB lookup. */
175 * Free internal TinyCDB state and close the CDB dictionary.
178 strength_close_cdb(krb5_context ctx UNUSED, krb5_pwqual_moddata data)
181 cdb_free(&data->cdb);
182 if (data->cdb_fd != -1)
186 #endif /* HAVE_CDB */