2 * Test a password for weaknesses using CrackLib.
4 * Contained here is the interface from the krb5-strength plugin to the
5 * CrackLib library, including initialization and checking of a password
6 * against a CrackLib dictionary.
8 * Developed by Derrick Brashear and Ken Hornstein of Sine Nomine Associates,
9 * on behalf of Stanford University
10 * Extensive modifications by Russ Allbery <eagle@eyrie.org>
11 * Copyright 2017 Russ Allbery <eagle@eyrie.org>
12 * Copyright 2006-2007, 2009, 2012-2013
13 * The Board of Trustees of the Leland Stanford Junior University
15 * SPDX-License-Identifier: MIT
19 #include <portable/kadmin.h>
20 #include <portable/system.h>
22 #include <plugin/internal.h>
23 #include <util/macros.h>
25 /* When using the embedded CrackLib, we need to provide our own prototype. */
30 extern const char *FascistCheck(const char *password, const char *dict);
36 * Stub for strength_init_cracklib if not built with CrackLib support.
40 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data UNUSED,
41 const char *dictionary UNUSED)
45 /* Get CDB dictionary path from krb5.conf. */
46 strength_config_string(ctx, "password_dictionary", &path);
48 /* If it was set, report an error, since we don't have CrackLib support. */
52 krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS,
53 "CrackLib dictionary requested but not built with"
55 return KADM5_BAD_SERVER_PARAMS;
60 /* Skip the rest of this file if CrackLib is not available. */
64 * Initialize the CrackLib dictionary. Ensure that the dictionary file exists
65 * and is readable and store the path in the module context. Returns 0 on
66 * success, non-zero on failure.
68 * The dictionary file should not include the trailing .pwd extension.
69 * Currently, we don't cope with a NULL dictionary path.
72 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
73 const char *dictionary)
79 * Get the dictionary from krb5.conf, and only use the dictionary provided
80 * if krb5.conf configuration is not present. The dictionary passed to
81 * the initialization function is normally set by dict_path in the MIT
82 * Kerberos configuration, and this allows that setting to be used for
83 * other password strength modules while using a different dictionary for
86 strength_config_string(ctx, "password_dictionary", &data->dictionary);
87 if (data->dictionary == NULL && dictionary != NULL) {
88 data->dictionary = strdup(dictionary);
89 if (data->dictionary == NULL)
90 return strength_error_system(ctx, "cannot allocate memory");
93 /* All done if we don't have a dictionary. */
94 if (data->dictionary == NULL)
97 /* Sanity-check the dictionary path. */
98 if (asprintf(&file, "%s.pwd", data->dictionary) < 0)
99 return strength_error_system(ctx, "cannot allocate memory");
100 if (access(file, R_OK) != 0) {
101 code = strength_error_system(ctx, "cannot read dictionary %s", file);
111 * Check a password against CrackLib. Returns 0 on success, non-zero on
112 * failure or if the password is rejected.
115 strength_check_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
116 const char *password)
120 /* Nothing to do if we don't have a dictionary. */
121 if (data->dictionary == NULL)
124 /* Nothing to do if the password is longer than the maximum length. */
125 if (data->cracklib_maxlen > 0)
126 if (strlen(password) > (size_t) data->cracklib_maxlen)
129 /* Check the password against CrackLib and return the results. */
130 result = FascistCheck(password, data->dictionary);
132 return strength_error_generic(ctx, "%s", result);
137 #endif /* HAVE_CRACKLIB */