]> eyrie.org Git - kerberos/krb5-strength.git/blob - plugin/cracklib.c
Declare fast forward from 3.1-2
[kerberos/krb5-strength.git] / plugin / cracklib.c
1 /*
2  * Test a password for weaknesses using CrackLib.
3  *
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.
7  *
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
14  *
15  * SPDX-License-Identifier: MIT
16  */
17
18 #include <config.h>
19 #include <portable/kadmin.h>
20 #include <portable/system.h>
21
22 #include <plugin/internal.h>
23 #include <util/macros.h>
24
25 /* When using the embedded CrackLib, we need to provide our own prototype. */
26 #ifdef HAVE_CRACKLIB
27 #    ifdef HAVE_CRACK_H
28 #        include <crack.h>
29 #    else
30 extern const char *FascistCheck(const char *password, const char *dict);
31 #    endif
32 #endif
33
34
35 /*
36  * Stub for strength_init_cracklib if not built with CrackLib support.
37  */
38 #ifndef HAVE_CRACKLIB
39 krb5_error_code
40 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data UNUSED,
41                        const char *dictionary UNUSED)
42 {
43     char *path = NULL;
44
45     /* Get CDB dictionary path from krb5.conf. */
46     strength_config_string(ctx, "password_dictionary", &path);
47
48     /* If it was set, report an error, since we don't have CrackLib support. */
49     if (path == NULL)
50         return 0;
51     free(path);
52     krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS,
53                            "CrackLib dictionary requested but not built with"
54                            " CrackLib support");
55     return KADM5_BAD_SERVER_PARAMS;
56 }
57 #endif
58
59
60 /* Skip the rest of this file if CrackLib is not available. */
61 #ifdef HAVE_CRACKLIB
62
63 /*
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.
67  *
68  * The dictionary file should not include the trailing .pwd extension.
69  * Currently, we don't cope with a NULL dictionary path.
70  */
71 krb5_error_code
72 strength_init_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
73                        const char *dictionary)
74 {
75     char *file;
76     krb5_error_code code;
77
78     /*
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
84      * krb5-strength.
85      */
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");
91     }
92
93     /* All done if we don't have a dictionary. */
94     if (data->dictionary == NULL)
95         return 0;
96
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);
102         free(file);
103         return code;
104     }
105     free(file);
106     return 0;
107 }
108
109
110 /*
111  * Check a password against CrackLib.  Returns 0 on success, non-zero on
112  * failure or if the password is rejected.
113  */
114 krb5_error_code
115 strength_check_cracklib(krb5_context ctx, krb5_pwqual_moddata data,
116                         const char *password)
117 {
118     const char *result;
119
120     /* Nothing to do if we don't have a dictionary. */
121     if (data->dictionary == NULL)
122         return 0;
123
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)
127             return 0;
128
129     /* Check the password against CrackLib and return the results. */
130     result = FascistCheck(password, data->dictionary);
131     if (result != NULL)
132         return strength_error_generic(ctx, "%s", result);
133     else
134         return 0;
135 }
136
137 #endif /* HAVE_CRACKLIB */