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