1b528cefcSMark Murray /*
2ae771770SStanislav Sedov * Copyright (c) 1997-2000, 2003-2005 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34b528cefcSMark Murray #include "kadm5_locl.h"
35c19800e8SDoug Rabson #include "kadm5-pwcheck.h"
36b528cefcSMark Murray
37c19800e8SDoug Rabson #ifdef HAVE_SYS_WAIT_H
38c19800e8SDoug Rabson #include <sys/wait.h>
39c19800e8SDoug Rabson #endif
40b528cefcSMark Murray #ifdef HAVE_DLFCN_H
41b528cefcSMark Murray #include <dlfcn.h>
42b528cefcSMark Murray #endif
43b528cefcSMark Murray
44c19800e8SDoug Rabson static int
min_length_passwd_quality(krb5_context context,krb5_principal principal,krb5_data * pwd,const char * opaque,char * message,size_t length)45c19800e8SDoug Rabson min_length_passwd_quality (krb5_context context,
46c19800e8SDoug Rabson krb5_principal principal,
47c19800e8SDoug Rabson krb5_data *pwd,
48c19800e8SDoug Rabson const char *opaque,
49c19800e8SDoug Rabson char *message,
50c19800e8SDoug Rabson size_t length)
51c19800e8SDoug Rabson {
52c19800e8SDoug Rabson uint32_t min_length = krb5_config_get_int_default(context, NULL, 6,
53c19800e8SDoug Rabson "password_quality",
54c19800e8SDoug Rabson "min_length",
55c19800e8SDoug Rabson NULL);
56c19800e8SDoug Rabson
57c19800e8SDoug Rabson if (pwd->length < min_length) {
58c19800e8SDoug Rabson strlcpy(message, "Password too short", length);
59c19800e8SDoug Rabson return 1;
60c19800e8SDoug Rabson } else
61c19800e8SDoug Rabson return 0;
62c19800e8SDoug Rabson }
63c19800e8SDoug Rabson
64b528cefcSMark Murray static const char *
min_length_passwd_quality_v0(krb5_context context,krb5_principal principal,krb5_data * pwd)65c19800e8SDoug Rabson min_length_passwd_quality_v0 (krb5_context context,
66b528cefcSMark Murray krb5_principal principal,
67b528cefcSMark Murray krb5_data *pwd)
68b528cefcSMark Murray {
69c19800e8SDoug Rabson static char message[1024];
70c19800e8SDoug Rabson int ret;
71c19800e8SDoug Rabson
72c19800e8SDoug Rabson message[0] = '\0';
73c19800e8SDoug Rabson
74c19800e8SDoug Rabson ret = min_length_passwd_quality(context, principal, pwd, NULL,
75c19800e8SDoug Rabson message, sizeof(message));
76c19800e8SDoug Rabson if (ret)
77c19800e8SDoug Rabson return message;
78b528cefcSMark Murray return NULL;
79b528cefcSMark Murray }
80b528cefcSMark Murray
81b528cefcSMark Murray
82c19800e8SDoug Rabson static int
char_class_passwd_quality(krb5_context context,krb5_principal principal,krb5_data * pwd,const char * opaque,char * message,size_t length)83c19800e8SDoug Rabson char_class_passwd_quality (krb5_context context,
84c19800e8SDoug Rabson krb5_principal principal,
85c19800e8SDoug Rabson krb5_data *pwd,
86c19800e8SDoug Rabson const char *opaque,
87c19800e8SDoug Rabson char *message,
88c19800e8SDoug Rabson size_t length)
89c19800e8SDoug Rabson {
90c19800e8SDoug Rabson const char *classes[] = {
91c19800e8SDoug Rabson "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
92c19800e8SDoug Rabson "abcdefghijklmnopqrstuvwxyz",
93c19800e8SDoug Rabson "1234567890",
94c19800e8SDoug Rabson "!@#$%^&*()/?<>,.{[]}\\|'~`\" "
95c19800e8SDoug Rabson };
96ae771770SStanislav Sedov int counter = 0, req_classes;
97ae771770SStanislav Sedov size_t i, len;
98c19800e8SDoug Rabson char *pw;
99b528cefcSMark Murray
100c19800e8SDoug Rabson req_classes = krb5_config_get_int_default(context, NULL, 3,
101c19800e8SDoug Rabson "password_quality",
102c19800e8SDoug Rabson "min_classes",
103c19800e8SDoug Rabson NULL);
104b528cefcSMark Murray
105c19800e8SDoug Rabson len = pwd->length + 1;
106c19800e8SDoug Rabson pw = malloc(len);
107c19800e8SDoug Rabson if (pw == NULL) {
108c19800e8SDoug Rabson strlcpy(message, "out of memory", length);
109c19800e8SDoug Rabson return 1;
110c19800e8SDoug Rabson }
111c19800e8SDoug Rabson strlcpy(pw, pwd->data, len);
112c19800e8SDoug Rabson len = strlen(pw);
113b528cefcSMark Murray
114c19800e8SDoug Rabson for (i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) {
115c19800e8SDoug Rabson if (strcspn(pw, classes[i]) < len)
116c19800e8SDoug Rabson counter++;
117c19800e8SDoug Rabson }
118c19800e8SDoug Rabson memset(pw, 0, pwd->length + 1);
119c19800e8SDoug Rabson free(pw);
120c19800e8SDoug Rabson if (counter < req_classes) {
121c19800e8SDoug Rabson snprintf(message, length,
122c19800e8SDoug Rabson "Password doesn't meet complexity requirement.\n"
123c19800e8SDoug Rabson "Add more characters from the following classes:\n"
124c19800e8SDoug Rabson "1. English uppercase characters (A through Z)\n"
125c19800e8SDoug Rabson "2. English lowercase characters (a through z)\n"
126c19800e8SDoug Rabson "3. Base 10 digits (0 through 9)\n"
127c19800e8SDoug Rabson "4. Nonalphanumeric characters (e.g., !, $, #, %%)");
128c19800e8SDoug Rabson return 1;
129c19800e8SDoug Rabson }
130c19800e8SDoug Rabson return 0;
131c19800e8SDoug Rabson }
132c19800e8SDoug Rabson
133c19800e8SDoug Rabson static int
external_passwd_quality(krb5_context context,krb5_principal principal,krb5_data * pwd,const char * opaque,char * message,size_t length)134c19800e8SDoug Rabson external_passwd_quality (krb5_context context,
135c19800e8SDoug Rabson krb5_principal principal,
136c19800e8SDoug Rabson krb5_data *pwd,
137c19800e8SDoug Rabson const char *opaque,
138c19800e8SDoug Rabson char *message,
139c19800e8SDoug Rabson size_t length)
140c19800e8SDoug Rabson {
141c19800e8SDoug Rabson krb5_error_code ret;
142c19800e8SDoug Rabson const char *program;
143c19800e8SDoug Rabson char *p;
144c19800e8SDoug Rabson pid_t child;
145c19800e8SDoug Rabson int status;
146c19800e8SDoug Rabson char reply[1024];
147c19800e8SDoug Rabson FILE *in = NULL, *out = NULL, *error = NULL;
148c19800e8SDoug Rabson
149ae771770SStanislav Sedov if (memchr(pwd->data, '\n', pwd->length) != NULL) {
150c19800e8SDoug Rabson snprintf(message, length, "password contains newline, "
151c19800e8SDoug Rabson "not valid for external test");
152c19800e8SDoug Rabson return 1;
153c19800e8SDoug Rabson }
154c19800e8SDoug Rabson
155c19800e8SDoug Rabson program = krb5_config_get_string(context, NULL,
156c19800e8SDoug Rabson "password_quality",
157c19800e8SDoug Rabson "external_program",
158c19800e8SDoug Rabson NULL);
159c19800e8SDoug Rabson if (program == NULL) {
160c19800e8SDoug Rabson snprintf(message, length, "external password quality "
161c19800e8SDoug Rabson "program not configured");
162c19800e8SDoug Rabson return 1;
163c19800e8SDoug Rabson }
164c19800e8SDoug Rabson
165c19800e8SDoug Rabson ret = krb5_unparse_name(context, principal, &p);
166c19800e8SDoug Rabson if (ret) {
167c19800e8SDoug Rabson strlcpy(message, "out of memory", length);
168c19800e8SDoug Rabson return 1;
169c19800e8SDoug Rabson }
170c19800e8SDoug Rabson
171ae771770SStanislav Sedov child = pipe_execv(&in, &out, &error, program, program, p, NULL);
172c19800e8SDoug Rabson if (child < 0) {
173c19800e8SDoug Rabson snprintf(message, length, "external password quality "
174c19800e8SDoug Rabson "program failed to execute for principal %s", p);
175c19800e8SDoug Rabson free(p);
176c19800e8SDoug Rabson return 1;
177c19800e8SDoug Rabson }
178c19800e8SDoug Rabson
179c19800e8SDoug Rabson fprintf(in, "principal: %s\n"
180c19800e8SDoug Rabson "new-password: %.*s\n"
181c19800e8SDoug Rabson "end\n",
182c19800e8SDoug Rabson p, (int)pwd->length, (char *)pwd->data);
183c19800e8SDoug Rabson
184c19800e8SDoug Rabson fclose(in);
185c19800e8SDoug Rabson
186c19800e8SDoug Rabson if (fgets(reply, sizeof(reply), out) == NULL) {
187c19800e8SDoug Rabson
188c19800e8SDoug Rabson if (fgets(reply, sizeof(reply), error) == NULL) {
189c19800e8SDoug Rabson snprintf(message, length, "external password quality "
190c19800e8SDoug Rabson "program failed without error");
191c19800e8SDoug Rabson
192c19800e8SDoug Rabson } else {
193c19800e8SDoug Rabson reply[strcspn(reply, "\n")] = '\0';
194c19800e8SDoug Rabson snprintf(message, length, "External password quality "
195c19800e8SDoug Rabson "program failed: %s", reply);
196c19800e8SDoug Rabson }
197c19800e8SDoug Rabson
198c19800e8SDoug Rabson fclose(out);
199c19800e8SDoug Rabson fclose(error);
200ae771770SStanislav Sedov wait_for_process(child);
201c19800e8SDoug Rabson return 1;
202c19800e8SDoug Rabson }
203c19800e8SDoug Rabson reply[strcspn(reply, "\n")] = '\0';
204c19800e8SDoug Rabson
205c19800e8SDoug Rabson fclose(out);
206c19800e8SDoug Rabson fclose(error);
207c19800e8SDoug Rabson
208ae771770SStanislav Sedov status = wait_for_process(child);
209ae771770SStanislav Sedov
210ae771770SStanislav Sedov if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0) {
211c19800e8SDoug Rabson snprintf(message, length, "external program failed: %s", reply);
212c19800e8SDoug Rabson free(p);
213c19800e8SDoug Rabson return 1;
214c19800e8SDoug Rabson }
215c19800e8SDoug Rabson
216c19800e8SDoug Rabson if (strcmp(reply, "APPROVED") != 0) {
217c19800e8SDoug Rabson snprintf(message, length, "%s", reply);
218c19800e8SDoug Rabson free(p);
219c19800e8SDoug Rabson return 1;
220c19800e8SDoug Rabson }
221c19800e8SDoug Rabson
222c19800e8SDoug Rabson free(p);
223c19800e8SDoug Rabson
224c19800e8SDoug Rabson return 0;
225c19800e8SDoug Rabson }
226c19800e8SDoug Rabson
227c19800e8SDoug Rabson
228c19800e8SDoug Rabson static kadm5_passwd_quality_check_func_v0 passwd_quality_check =
229c19800e8SDoug Rabson min_length_passwd_quality_v0;
230c19800e8SDoug Rabson
231c19800e8SDoug Rabson struct kadm5_pw_policy_check_func builtin_funcs[] = {
232c19800e8SDoug Rabson { "minimum-length", min_length_passwd_quality },
233c19800e8SDoug Rabson { "character-class", char_class_passwd_quality },
234c19800e8SDoug Rabson { "external-check", external_passwd_quality },
235ae771770SStanislav Sedov { NULL, NULL }
236c19800e8SDoug Rabson };
237c19800e8SDoug Rabson struct kadm5_pw_policy_verifier builtin_verifier = {
238c19800e8SDoug Rabson "builtin",
239c19800e8SDoug Rabson KADM5_PASSWD_VERSION_V1,
240c19800e8SDoug Rabson "Heimdal builtin",
241c19800e8SDoug Rabson builtin_funcs
242c19800e8SDoug Rabson };
243c19800e8SDoug Rabson
244c19800e8SDoug Rabson static struct kadm5_pw_policy_verifier **verifiers;
245c19800e8SDoug Rabson static int num_verifiers;
246b528cefcSMark Murray
247b528cefcSMark Murray /*
248b528cefcSMark Murray * setup the password quality hook
249b528cefcSMark Murray */
250b528cefcSMark Murray
251c19800e8SDoug Rabson #ifndef RTLD_NOW
252c19800e8SDoug Rabson #define RTLD_NOW 0
253c19800e8SDoug Rabson #endif
254c19800e8SDoug Rabson
255b528cefcSMark Murray void
kadm5_setup_passwd_quality_check(krb5_context context,const char * check_library,const char * check_function)256b528cefcSMark Murray kadm5_setup_passwd_quality_check(krb5_context context,
257b528cefcSMark Murray const char *check_library,
258b528cefcSMark Murray const char *check_function)
259b528cefcSMark Murray {
260b528cefcSMark Murray #ifdef HAVE_DLOPEN
261b528cefcSMark Murray void *handle;
262b528cefcSMark Murray void *sym;
263b528cefcSMark Murray int *version;
264b528cefcSMark Murray const char *tmp;
265b528cefcSMark Murray
266b528cefcSMark Murray if(check_library == NULL) {
267b528cefcSMark Murray tmp = krb5_config_get_string(context, NULL,
268b528cefcSMark Murray "password_quality",
269b528cefcSMark Murray "check_library",
270b528cefcSMark Murray NULL);
271b528cefcSMark Murray if(tmp != NULL)
272b528cefcSMark Murray check_library = tmp;
273b528cefcSMark Murray }
274b528cefcSMark Murray if(check_function == NULL) {
275b528cefcSMark Murray tmp = krb5_config_get_string(context, NULL,
276b528cefcSMark Murray "password_quality",
277b528cefcSMark Murray "check_function",
278b528cefcSMark Murray NULL);
279b528cefcSMark Murray if(tmp != NULL)
280b528cefcSMark Murray check_function = tmp;
281b528cefcSMark Murray }
282b528cefcSMark Murray if(check_library != NULL && check_function == NULL)
283b528cefcSMark Murray check_function = "passwd_check";
284b528cefcSMark Murray
285b528cefcSMark Murray if(check_library == NULL)
286b528cefcSMark Murray return;
287c19800e8SDoug Rabson handle = dlopen(check_library, RTLD_NOW);
288b528cefcSMark Murray if(handle == NULL) {
289b528cefcSMark Murray krb5_warnx(context, "failed to open `%s'", check_library);
290b528cefcSMark Murray return;
291b528cefcSMark Murray }
292ae771770SStanislav Sedov version = (int *) dlsym(handle, "version");
293b528cefcSMark Murray if(version == NULL) {
294b528cefcSMark Murray krb5_warnx(context,
295b528cefcSMark Murray "didn't find `version' symbol in `%s'", check_library);
296b528cefcSMark Murray dlclose(handle);
297b528cefcSMark Murray return;
298b528cefcSMark Murray }
299c19800e8SDoug Rabson if(*version != KADM5_PASSWD_VERSION_V0) {
300b528cefcSMark Murray krb5_warnx(context,
301b528cefcSMark Murray "version of loaded library is %d (expected %d)",
302c19800e8SDoug Rabson *version, KADM5_PASSWD_VERSION_V0);
303b528cefcSMark Murray dlclose(handle);
304b528cefcSMark Murray return;
305b528cefcSMark Murray }
306b528cefcSMark Murray sym = dlsym(handle, check_function);
307b528cefcSMark Murray if(sym == NULL) {
308b528cefcSMark Murray krb5_warnx(context,
309b528cefcSMark Murray "didn't find `%s' symbol in `%s'",
310b528cefcSMark Murray check_function, check_library);
311b528cefcSMark Murray dlclose(handle);
312b528cefcSMark Murray return;
313b528cefcSMark Murray }
314c19800e8SDoug Rabson passwd_quality_check = (kadm5_passwd_quality_check_func_v0) sym;
315b528cefcSMark Murray #endif /* HAVE_DLOPEN */
316b528cefcSMark Murray }
317b528cefcSMark Murray
318c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
319c19800e8SDoug Rabson
320c19800e8SDoug Rabson static krb5_error_code
add_verifier(krb5_context context,const char * check_library)321c19800e8SDoug Rabson add_verifier(krb5_context context, const char *check_library)
322c19800e8SDoug Rabson {
323c19800e8SDoug Rabson struct kadm5_pw_policy_verifier *v, **tmp;
324c19800e8SDoug Rabson void *handle;
325c19800e8SDoug Rabson int i;
326c19800e8SDoug Rabson
327c19800e8SDoug Rabson handle = dlopen(check_library, RTLD_NOW);
328c19800e8SDoug Rabson if(handle == NULL) {
329c19800e8SDoug Rabson krb5_warnx(context, "failed to open `%s'", check_library);
330c19800e8SDoug Rabson return ENOENT;
331c19800e8SDoug Rabson }
332ae771770SStanislav Sedov v = (struct kadm5_pw_policy_verifier *) dlsym(handle, "kadm5_password_verifier");
333c19800e8SDoug Rabson if(v == NULL) {
334c19800e8SDoug Rabson krb5_warnx(context,
335c19800e8SDoug Rabson "didn't find `kadm5_password_verifier' symbol "
336c19800e8SDoug Rabson "in `%s'", check_library);
337c19800e8SDoug Rabson dlclose(handle);
338c19800e8SDoug Rabson return ENOENT;
339c19800e8SDoug Rabson }
340c19800e8SDoug Rabson if(v->version != KADM5_PASSWD_VERSION_V1) {
341c19800e8SDoug Rabson krb5_warnx(context,
342c19800e8SDoug Rabson "version of loaded library is %d (expected %d)",
343c19800e8SDoug Rabson v->version, KADM5_PASSWD_VERSION_V1);
344c19800e8SDoug Rabson dlclose(handle);
345c19800e8SDoug Rabson return EINVAL;
346c19800e8SDoug Rabson }
347c19800e8SDoug Rabson for (i = 0; i < num_verifiers; i++) {
348c19800e8SDoug Rabson if (strcmp(v->name, verifiers[i]->name) == 0)
349c19800e8SDoug Rabson break;
350c19800e8SDoug Rabson }
351c19800e8SDoug Rabson if (i < num_verifiers) {
352c19800e8SDoug Rabson krb5_warnx(context, "password verifier library `%s' is already loaded",
353c19800e8SDoug Rabson v->name);
354c19800e8SDoug Rabson dlclose(handle);
355c19800e8SDoug Rabson return 0;
356c19800e8SDoug Rabson }
357c19800e8SDoug Rabson
358c19800e8SDoug Rabson tmp = realloc(verifiers, (num_verifiers + 1) * sizeof(*verifiers));
359c19800e8SDoug Rabson if (tmp == NULL) {
360c19800e8SDoug Rabson krb5_warnx(context, "out of memory");
361c19800e8SDoug Rabson dlclose(handle);
362c19800e8SDoug Rabson return 0;
363c19800e8SDoug Rabson }
364c19800e8SDoug Rabson verifiers = tmp;
365c19800e8SDoug Rabson verifiers[num_verifiers] = v;
366c19800e8SDoug Rabson num_verifiers++;
367c19800e8SDoug Rabson
368c19800e8SDoug Rabson return 0;
369c19800e8SDoug Rabson }
370c19800e8SDoug Rabson
371c19800e8SDoug Rabson #endif
372c19800e8SDoug Rabson
373c19800e8SDoug Rabson krb5_error_code
kadm5_add_passwd_quality_verifier(krb5_context context,const char * check_library)374c19800e8SDoug Rabson kadm5_add_passwd_quality_verifier(krb5_context context,
375c19800e8SDoug Rabson const char *check_library)
376c19800e8SDoug Rabson {
377c19800e8SDoug Rabson #ifdef HAVE_DLOPEN
378c19800e8SDoug Rabson
379c19800e8SDoug Rabson if(check_library == NULL) {
380c19800e8SDoug Rabson krb5_error_code ret;
381c19800e8SDoug Rabson char **tmp;
382c19800e8SDoug Rabson
383c19800e8SDoug Rabson tmp = krb5_config_get_strings(context, NULL,
384c19800e8SDoug Rabson "password_quality",
385c19800e8SDoug Rabson "policy_libraries",
386c19800e8SDoug Rabson NULL);
387ae771770SStanislav Sedov if(tmp == NULL || *tmp == NULL)
388c19800e8SDoug Rabson return 0;
389c19800e8SDoug Rabson
390ae771770SStanislav Sedov while (*tmp) {
391c19800e8SDoug Rabson ret = add_verifier(context, *tmp);
392c19800e8SDoug Rabson if (ret)
393c19800e8SDoug Rabson return ret;
394c19800e8SDoug Rabson tmp++;
395c19800e8SDoug Rabson }
396ae771770SStanislav Sedov return 0;
397ae771770SStanislav Sedov } else {
398c19800e8SDoug Rabson return add_verifier(context, check_library);
399ae771770SStanislav Sedov }
400c19800e8SDoug Rabson #else
401c19800e8SDoug Rabson return 0;
402c19800e8SDoug Rabson #endif /* HAVE_DLOPEN */
403c19800e8SDoug Rabson }
404c19800e8SDoug Rabson
405c19800e8SDoug Rabson /*
406c19800e8SDoug Rabson *
407c19800e8SDoug Rabson */
408c19800e8SDoug Rabson
409c19800e8SDoug Rabson static const struct kadm5_pw_policy_check_func *
find_func(krb5_context context,const char * name)410c19800e8SDoug Rabson find_func(krb5_context context, const char *name)
411c19800e8SDoug Rabson {
412c19800e8SDoug Rabson const struct kadm5_pw_policy_check_func *f;
413c19800e8SDoug Rabson char *module = NULL;
414c19800e8SDoug Rabson const char *p, *func;
415c19800e8SDoug Rabson int i;
416c19800e8SDoug Rabson
417c19800e8SDoug Rabson p = strchr(name, ':');
418c19800e8SDoug Rabson if (p) {
419ae771770SStanislav Sedov size_t len = p - name + 1;
420c19800e8SDoug Rabson func = p + 1;
421ae771770SStanislav Sedov module = malloc(len);
422c19800e8SDoug Rabson if (module == NULL)
423c19800e8SDoug Rabson return NULL;
424ae771770SStanislav Sedov strlcpy(module, name, len);
425c19800e8SDoug Rabson } else
426c19800e8SDoug Rabson func = name;
427c19800e8SDoug Rabson
428c19800e8SDoug Rabson /* Find module in loaded modules first */
429c19800e8SDoug Rabson for (i = 0; i < num_verifiers; i++) {
430c19800e8SDoug Rabson if (module && strcmp(module, verifiers[i]->name) != 0)
431c19800e8SDoug Rabson continue;
432c19800e8SDoug Rabson for (f = verifiers[i]->funcs; f->name ; f++)
433ae771770SStanislav Sedov if (strcmp(func, f->name) == 0) {
434c19800e8SDoug Rabson if (module)
435c19800e8SDoug Rabson free(module);
436c19800e8SDoug Rabson return f;
437c19800e8SDoug Rabson }
438c19800e8SDoug Rabson }
439c19800e8SDoug Rabson /* Lets try try the builtin modules */
440c19800e8SDoug Rabson if (module == NULL || strcmp(module, "builtin") == 0) {
441c19800e8SDoug Rabson for (f = builtin_verifier.funcs; f->name ; f++)
442c19800e8SDoug Rabson if (strcmp(func, f->name) == 0) {
443c19800e8SDoug Rabson if (module)
444c19800e8SDoug Rabson free(module);
445c19800e8SDoug Rabson return f;
446c19800e8SDoug Rabson }
447c19800e8SDoug Rabson }
448c19800e8SDoug Rabson if (module)
449c19800e8SDoug Rabson free(module);
450c19800e8SDoug Rabson return NULL;
451c19800e8SDoug Rabson }
452c19800e8SDoug Rabson
453b528cefcSMark Murray const char *
kadm5_check_password_quality(krb5_context context,krb5_principal principal,krb5_data * pwd_data)454b528cefcSMark Murray kadm5_check_password_quality (krb5_context context,
455b528cefcSMark Murray krb5_principal principal,
456b528cefcSMark Murray krb5_data *pwd_data)
457b528cefcSMark Murray {
458c19800e8SDoug Rabson const struct kadm5_pw_policy_check_func *proc;
459c19800e8SDoug Rabson static char error_msg[1024];
460c19800e8SDoug Rabson const char *msg;
461c19800e8SDoug Rabson char **v, **vp;
462c19800e8SDoug Rabson int ret;
463c19800e8SDoug Rabson
464c19800e8SDoug Rabson /*
465c19800e8SDoug Rabson * Check if we should use the old version of policy function.
466c19800e8SDoug Rabson */
467c19800e8SDoug Rabson
468c19800e8SDoug Rabson v = krb5_config_get_strings(context, NULL,
469c19800e8SDoug Rabson "password_quality",
470c19800e8SDoug Rabson "policies",
471c19800e8SDoug Rabson NULL);
472c19800e8SDoug Rabson if (v == NULL) {
473c19800e8SDoug Rabson msg = (*passwd_quality_check) (context, principal, pwd_data);
474*cf771f22SStanislav Sedov if (msg)
475ae771770SStanislav Sedov krb5_set_error_message(context, 0, "password policy failed: %s", msg);
476c19800e8SDoug Rabson return msg;
477c19800e8SDoug Rabson }
478c19800e8SDoug Rabson
479c19800e8SDoug Rabson error_msg[0] = '\0';
480c19800e8SDoug Rabson
481c19800e8SDoug Rabson msg = NULL;
482c19800e8SDoug Rabson for(vp = v; *vp; vp++) {
483c19800e8SDoug Rabson proc = find_func(context, *vp);
484c19800e8SDoug Rabson if (proc == NULL) {
485c19800e8SDoug Rabson msg = "failed to find password verifier function";
486ae771770SStanislav Sedov krb5_set_error_message(context, 0, "Failed to find password policy "
487c19800e8SDoug Rabson "function: %s", *vp);
488c19800e8SDoug Rabson break;
489c19800e8SDoug Rabson }
490c19800e8SDoug Rabson ret = (proc->func)(context, principal, pwd_data, NULL,
491c19800e8SDoug Rabson error_msg, sizeof(error_msg));
492c19800e8SDoug Rabson if (ret) {
493ae771770SStanislav Sedov krb5_set_error_message(context, 0, "Password policy "
494c19800e8SDoug Rabson "%s failed with %s",
495c19800e8SDoug Rabson proc->name, error_msg);
496c19800e8SDoug Rabson msg = error_msg;
497c19800e8SDoug Rabson break;
498c19800e8SDoug Rabson }
499c19800e8SDoug Rabson }
500c19800e8SDoug Rabson krb5_config_free_strings(v);
501c19800e8SDoug Rabson
502c19800e8SDoug Rabson /* If the default quality check isn't used, lets check that the
503c19800e8SDoug Rabson * old quality function the user have set too */
504c19800e8SDoug Rabson if (msg == NULL && passwd_quality_check != min_length_passwd_quality_v0) {
505c19800e8SDoug Rabson msg = (*passwd_quality_check) (context, principal, pwd_data);
506c19800e8SDoug Rabson if (msg)
507ae771770SStanislav Sedov krb5_set_error_message(context, 0, "(old) password policy "
508c19800e8SDoug Rabson "failed with %s", msg);
509c19800e8SDoug Rabson
510c19800e8SDoug Rabson }
511c19800e8SDoug Rabson return msg;
512b528cefcSMark Murray }
513