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 Daria Phoebe Brashear and Ken Hornstein of Sine Nomine
9 * Associates, on behalf of Stanford University Extensive modifications by Russ
10 * Allbery <eagle@eyrie.org> Copyright 2017 Russ Allbery <eagle@eyrie.org>
11 * Copyright 2006-2007, 2009, 2012-2013
12 * The Board of Trustees of the Leland Stanford Junior University
14 * SPDX-License-Identifier: MIT
18 #include <portable/kadmin.h>
19 #include <portable/system.h>
21 #include <plugin/internal.h>
22 #include <util/macros.h>
24 /* When using the embedded CrackLib, we need to provide our own prototype. */
29 extern const char *FascistCheck(const char *password, const char *dict);
35 * Stub for strength_init_cracklib if not built with CrackLib support.
39 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data UNUSED,
40 const char *dictionary UNUSED)
44 /* Get CDB dictionary path from krb5.conf. */
45 strength_config_string(ctx, "password_dictionary", &path);
47 /* If it was set, report an error, since we don't have CrackLib support. */
51 krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS,
52 "CrackLib dictionary requested but not built with"
54 return KADM5_BAD_SERVER_PARAMS;
59 /* Skip the rest of this file if CrackLib is not available. */
63 * Initialize the CrackLib dictionary. Ensure that the dictionary file exists
64 * and is readable and store the path in the module context. Returns 0 on
65 * success, non-zero on failure.
67 * The dictionary file should not include the trailing .pwd extension.
68 * Currently, we don't cope with a NULL dictionary path.
71 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
72 const char *dictionary)
78 * Get the dictionary from krb5.conf, and only use the dictionary provided
79 * if krb5.conf configuration is not present. The dictionary passed to
80 * the initialization function is normally set by dict_path in the MIT
81 * Kerberos configuration, and this allows that setting to be used for
82 * other password strength modules while using a different dictionary for
85 strength_config_string(ctx, "password_dictionary", &data->dictionary);
86 if (data->dictionary == NULL && dictionary != NULL) {
87 data->dictionary = strdup(dictionary);
88 if (data->dictionary == NULL)
89 return strength_error_system(ctx, "cannot allocate memory");
92 /* All done if we don't have a dictionary. */
93 if (data->dictionary == NULL)
96 /* Sanity-check the dictionary path. */
97 if (asprintf(&file, "%s.pwd", data->dictionary) < 0)
98 return strength_error_system(ctx, "cannot allocate memory");
99 if (access(file, R_OK) != 0) {
100 code = strength_error_system(ctx, "cannot read dictionary %s", file);
110 * Check a password against CrackLib. Returns 0 on success, non-zero on
111 * failure or if the password is rejected.
114 strength_check_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
115 const char *password)
119 /* Nothing to do if we don't have a dictionary. */
120 if (data->dictionary == NULL)
123 /* Nothing to do if the password is longer than the maximum length. */
124 if (data->cracklib_maxlen > 0)
125 if (strlen(password) > (size_t) data->cracklib_maxlen)
128 /* Check the password against CrackLib and return the results. */
129 result = FascistCheck(password, data->dictionary);
131 return strength_error_generic(ctx, "%s", result);
136 #endif /* HAVE_CRACKLIB */