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