]> eyrie.org Git - kerberos/krb5-strength.git/blob - plugin/api.c
The check of the password against the principal checked against the
[kerberos/krb5-strength.git] / plugin / api.c
1 /*
2  * api.c
3  *
4  * The public APIs of the password strength checking kadmind plugin.
5  *
6  * Provides the public pwcheck_init, pwcheck_check, and pwcheck_close APIs for
7  * the kadmind plugin.
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 /*
16  * Used to store local state.  Currently, all we have is the dictionary path,
17  * which we get from kadmind rather than from krb5.conf since it's already a
18  * kdc.conf setting.
19  */
20 struct context {
21     char *dictionary;
22 };
23
24 /* The public function exported by the cracklib library. */
25 extern char *FascistCheck(const char *password, const char *dict);
26
27 /*
28  * Initialize the module.  Ensure that the dictionary file exists and is
29  * readable and store the path in the module context.  Returns 0 on success,
30  * non-zero on failure.  This function returns failure only if it could not
31  * allocate memory.
32  *
33  * The dictionary file should not include the trailing .pwd extension.
34  * Currently, we don't cope with a NULL dictionary path.
35  */
36 int
37 pwcheck_init(void **context, const char *dictionary)
38 {
39     char *path;
40     size_t length;
41     struct context *ctx;
42
43     if (dictionary == NULL)
44         return 1;
45     length = strlen(dictionary) + strlen(".pwd") + 1;
46     path = malloc(length);
47     if (path == NULL)
48         return 1;
49     snprintf(path, length, "%s.pwd", dictionary);
50     if (access(path, R_OK) != 0)
51         return 1;
52     path[strlen(path) - strlen(".pwd")] = '\0';
53     ctx = malloc(sizeof(struct context));
54     if (ctx == NULL)
55         return 1;
56     ctx->dictionary = path;
57     *context = ctx;
58     return 0;
59 }
60
61
62 /*
63  * Check a given password.  Takes our local context, the password, the
64  * principal the password is for, and a buffer and buffer length into which to
65  * put any failure message.
66  */
67 int
68 pwcheck_check(void *context, const char *password, const char *principal,
69               char *errstr, int errstrlen)
70 {
71     char *user, *p;
72     size_t i, j;
73     char c;
74     const char *result;
75     struct context *ctx = context;
76
77     /*
78      * We get the principal (in krb5_unparse_name format) from kadmind and we
79      * want to be sure that the password doesn't match the username or the
80      * username reversed.  We therefore have to copy the string so that we can
81      * manipulate it a bit.
82      */
83     if (strcasecmp(password, principal) == 0) {
84         snprintf(errstr, errstrlen, "Password based on username");
85         errstr[errstrlen - 1] = '\0';
86         return 1;
87     }
88     user = strdup(principal);
89     if (user == NULL) {
90         snprintf(errstr, errstrlen, "Cannot allocate memory");
91         errstr[errstrlen - 1] = '\0';
92         return 1;
93     }
94     for (p = user; p[0] != '\0'; p++) {
95         if (p[0] == '\\' && p[1] != '\0') {
96             p++;
97             continue;
98         }
99         if (p[0] == '@') {
100             p[0] = '\0';
101             break;
102         }
103     }
104     if (strlen(password) == strlen(user)) {
105         if (strcasecmp(password, user) == 0) {
106             free(user);
107             snprintf(errstr, errstrlen, "Password based on username");
108             errstr[errstrlen - 1] = '\0';
109             return 1;
110         }
111         for (i = 0, j = strlen(user) - 1; i < j; i++, j--) {
112             c = user[i];
113             user[i] = user[j];
114             user[j] = c;
115         }
116         if (strcasecmp(password, user) == 0) {
117             free(user);
118             snprintf(errstr, errstrlen, "Password based on username");
119             errstr[errstrlen - 1] = '\0';
120             return 1;
121         }
122     }
123     free(user);
124     result = FascistCheck(password, ctx->dictionary);
125     if (result != NULL) {
126         strncpy(errstr, result, errstrlen);
127         errstr[errstrlen - 1] = '\0';
128         return 1;
129     }
130     return 0;
131 }
132
133
134 /*
135  * Cleanly shut down the password strength plugin.  The only thing we have to
136  * do is free our context memory.
137  */
138 void
139 pwcheck_close(void *context)
140 {
141     struct context *ctx = context;
142
143     if (ctx != NULL) {
144         if (ctx->dictionary != NULL)
145             free(ctx->dictionary);
146         free(ctx);
147     }
148 }