1b528cefcSMark Murray /* 2c19800e8SDoug Rabson * 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 RCSID("$Id: password_quality.c 17595 2006-05-30 21:51:55Z lha $"); 38b528cefcSMark Murray 39c19800e8SDoug Rabson #ifdef HAVE_SYS_WAIT_H 40c19800e8SDoug Rabson #include <sys/wait.h> 41c19800e8SDoug Rabson #endif 42b528cefcSMark Murray #ifdef HAVE_DLFCN_H 43b528cefcSMark Murray #include <dlfcn.h> 44b528cefcSMark Murray #endif 45b528cefcSMark Murray 46c19800e8SDoug Rabson static int 47c19800e8SDoug Rabson min_length_passwd_quality (krb5_context context, 48c19800e8SDoug Rabson krb5_principal principal, 49c19800e8SDoug Rabson krb5_data *pwd, 50c19800e8SDoug Rabson const char *opaque, 51c19800e8SDoug Rabson char *message, 52c19800e8SDoug Rabson size_t length) 53c19800e8SDoug Rabson { 54c19800e8SDoug Rabson uint32_t min_length = krb5_config_get_int_default(context, NULL, 6, 55c19800e8SDoug Rabson "password_quality", 56c19800e8SDoug Rabson "min_length", 57c19800e8SDoug Rabson NULL); 58c19800e8SDoug Rabson 59c19800e8SDoug Rabson if (pwd->length < min_length) { 60c19800e8SDoug Rabson strlcpy(message, "Password too short", length); 61c19800e8SDoug Rabson return 1; 62c19800e8SDoug Rabson } else 63c19800e8SDoug Rabson return 0; 64c19800e8SDoug Rabson } 65c19800e8SDoug Rabson 66b528cefcSMark Murray static const char * 67c19800e8SDoug Rabson min_length_passwd_quality_v0 (krb5_context context, 68b528cefcSMark Murray krb5_principal principal, 69b528cefcSMark Murray krb5_data *pwd) 70b528cefcSMark Murray { 71c19800e8SDoug Rabson static char message[1024]; 72c19800e8SDoug Rabson int ret; 73c19800e8SDoug Rabson 74c19800e8SDoug Rabson message[0] = '\0'; 75c19800e8SDoug Rabson 76c19800e8SDoug Rabson ret = min_length_passwd_quality(context, principal, pwd, NULL, 77c19800e8SDoug Rabson message, sizeof(message)); 78c19800e8SDoug Rabson if (ret) 79c19800e8SDoug Rabson return message; 80b528cefcSMark Murray return NULL; 81b528cefcSMark Murray } 82b528cefcSMark Murray 83b528cefcSMark Murray 84c19800e8SDoug Rabson static int 85c19800e8SDoug Rabson char_class_passwd_quality (krb5_context context, 86c19800e8SDoug Rabson krb5_principal principal, 87c19800e8SDoug Rabson krb5_data *pwd, 88c19800e8SDoug Rabson const char *opaque, 89c19800e8SDoug Rabson char *message, 90c19800e8SDoug Rabson size_t length) 91c19800e8SDoug Rabson { 92c19800e8SDoug Rabson const char *classes[] = { 93c19800e8SDoug Rabson "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 94c19800e8SDoug Rabson "abcdefghijklmnopqrstuvwxyz", 95c19800e8SDoug Rabson "1234567890", 96c19800e8SDoug Rabson "!@#$%^&*()/?<>,.{[]}\\|'~`\" " 97c19800e8SDoug Rabson }; 98c19800e8SDoug Rabson int i, counter = 0, req_classes; 99c19800e8SDoug Rabson size_t len; 100c19800e8SDoug Rabson char *pw; 101b528cefcSMark Murray 102c19800e8SDoug Rabson req_classes = krb5_config_get_int_default(context, NULL, 3, 103c19800e8SDoug Rabson "password_quality", 104c19800e8SDoug Rabson "min_classes", 105c19800e8SDoug Rabson NULL); 106b528cefcSMark Murray 107c19800e8SDoug Rabson len = pwd->length + 1; 108c19800e8SDoug Rabson pw = malloc(len); 109c19800e8SDoug Rabson if (pw == NULL) { 110c19800e8SDoug Rabson strlcpy(message, "out of memory", length); 111c19800e8SDoug Rabson return 1; 112c19800e8SDoug Rabson } 113c19800e8SDoug Rabson strlcpy(pw, pwd->data, len); 114c19800e8SDoug Rabson len = strlen(pw); 115b528cefcSMark Murray 116c19800e8SDoug Rabson for (i = 0; i < sizeof(classes)/sizeof(classes[0]); i++) { 117c19800e8SDoug Rabson if (strcspn(pw, classes[i]) < len) 118c19800e8SDoug Rabson counter++; 119c19800e8SDoug Rabson } 120c19800e8SDoug Rabson memset(pw, 0, pwd->length + 1); 121c19800e8SDoug Rabson free(pw); 122c19800e8SDoug Rabson if (counter < req_classes) { 123c19800e8SDoug Rabson snprintf(message, length, 124c19800e8SDoug Rabson "Password doesn't meet complexity requirement.\n" 125c19800e8SDoug Rabson "Add more characters from the following classes:\n" 126c19800e8SDoug Rabson "1. English uppercase characters (A through Z)\n" 127c19800e8SDoug Rabson "2. English lowercase characters (a through z)\n" 128c19800e8SDoug Rabson "3. Base 10 digits (0 through 9)\n" 129c19800e8SDoug Rabson "4. Nonalphanumeric characters (e.g., !, $, #, %%)"); 130c19800e8SDoug Rabson return 1; 131c19800e8SDoug Rabson } 132c19800e8SDoug Rabson return 0; 133c19800e8SDoug Rabson } 134c19800e8SDoug Rabson 135c19800e8SDoug Rabson static int 136c19800e8SDoug Rabson external_passwd_quality (krb5_context context, 137c19800e8SDoug Rabson krb5_principal principal, 138c19800e8SDoug Rabson krb5_data *pwd, 139c19800e8SDoug Rabson const char *opaque, 140c19800e8SDoug Rabson char *message, 141c19800e8SDoug Rabson size_t length) 142c19800e8SDoug Rabson { 143c19800e8SDoug Rabson krb5_error_code ret; 144c19800e8SDoug Rabson const char *program; 145c19800e8SDoug Rabson char *p; 146c19800e8SDoug Rabson pid_t child; 147c19800e8SDoug Rabson int status; 148c19800e8SDoug Rabson char reply[1024]; 149c19800e8SDoug Rabson FILE *in = NULL, *out = NULL, *error = NULL; 150c19800e8SDoug Rabson 151c19800e8SDoug Rabson if (memchr(pwd->data, pwd->length, '\n') != NULL) { 152c19800e8SDoug Rabson snprintf(message, length, "password contains newline, " 153c19800e8SDoug Rabson "not valid for external test"); 154c19800e8SDoug Rabson return 1; 155c19800e8SDoug Rabson } 156c19800e8SDoug Rabson 157c19800e8SDoug Rabson program = krb5_config_get_string(context, NULL, 158c19800e8SDoug Rabson "password_quality", 159c19800e8SDoug Rabson "external_program", 160c19800e8SDoug Rabson NULL); 161c19800e8SDoug Rabson if (program == NULL) { 162c19800e8SDoug Rabson snprintf(message, length, "external password quality " 163c19800e8SDoug Rabson "program not configured"); 164c19800e8SDoug Rabson return 1; 165c19800e8SDoug Rabson } 166c19800e8SDoug Rabson 167c19800e8SDoug Rabson ret = krb5_unparse_name(context, principal, &p); 168c19800e8SDoug Rabson if (ret) { 169c19800e8SDoug Rabson strlcpy(message, "out of memory", length); 170c19800e8SDoug Rabson return 1; 171c19800e8SDoug Rabson } 172c19800e8SDoug Rabson 173c19800e8SDoug Rabson child = pipe_execv(&in, &out, &error, program, p, NULL); 174c19800e8SDoug Rabson if (child < 0) { 175c19800e8SDoug Rabson snprintf(message, length, "external password quality " 176c19800e8SDoug Rabson "program failed to execute for principal %s", p); 177c19800e8SDoug Rabson free(p); 178c19800e8SDoug Rabson return 1; 179c19800e8SDoug Rabson } 180c19800e8SDoug Rabson 181c19800e8SDoug Rabson fprintf(in, "principal: %s\n" 182c19800e8SDoug Rabson "new-password: %.*s\n" 183c19800e8SDoug Rabson "end\n", 184c19800e8SDoug Rabson p, (int)pwd->length, (char *)pwd->data); 185c19800e8SDoug Rabson 186c19800e8SDoug Rabson fclose(in); 187c19800e8SDoug Rabson 188c19800e8SDoug Rabson if (fgets(reply, sizeof(reply), out) == NULL) { 189c19800e8SDoug Rabson 190c19800e8SDoug Rabson if (fgets(reply, sizeof(reply), error) == NULL) { 191c19800e8SDoug Rabson snprintf(message, length, "external password quality " 192c19800e8SDoug Rabson "program failed without error"); 193c19800e8SDoug Rabson 194c19800e8SDoug Rabson } else { 195c19800e8SDoug Rabson reply[strcspn(reply, "\n")] = '\0'; 196c19800e8SDoug Rabson snprintf(message, length, "External password quality " 197c19800e8SDoug Rabson "program failed: %s", reply); 198c19800e8SDoug Rabson } 199c19800e8SDoug Rabson 200c19800e8SDoug Rabson fclose(out); 201c19800e8SDoug Rabson fclose(error); 202c19800e8SDoug Rabson waitpid(child, &status, 0); 203c19800e8SDoug Rabson return 1; 204c19800e8SDoug Rabson } 205c19800e8SDoug Rabson reply[strcspn(reply, "\n")] = '\0'; 206c19800e8SDoug Rabson 207c19800e8SDoug Rabson fclose(out); 208c19800e8SDoug Rabson fclose(error); 209c19800e8SDoug Rabson 210c19800e8SDoug Rabson if (waitpid(child, &status, 0) < 0) { 211c19800e8SDoug Rabson snprintf(message, length, "external program failed: %s", reply); 212c19800e8SDoug Rabson free(p); 213c19800e8SDoug Rabson return 1; 214c19800e8SDoug Rabson } 215c19800e8SDoug Rabson if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 216c19800e8SDoug Rabson snprintf(message, length, "external program failed: %s", reply); 217c19800e8SDoug Rabson free(p); 218c19800e8SDoug Rabson return 1; 219c19800e8SDoug Rabson } 220c19800e8SDoug Rabson 221c19800e8SDoug Rabson if (strcmp(reply, "APPROVED") != 0) { 222c19800e8SDoug Rabson snprintf(message, length, "%s", reply); 223c19800e8SDoug Rabson free(p); 224c19800e8SDoug Rabson return 1; 225c19800e8SDoug Rabson } 226c19800e8SDoug Rabson 227c19800e8SDoug Rabson free(p); 228c19800e8SDoug Rabson 229c19800e8SDoug Rabson return 0; 230c19800e8SDoug Rabson } 231c19800e8SDoug Rabson 232c19800e8SDoug Rabson 233c19800e8SDoug Rabson static kadm5_passwd_quality_check_func_v0 passwd_quality_check = 234c19800e8SDoug Rabson min_length_passwd_quality_v0; 235c19800e8SDoug Rabson 236c19800e8SDoug Rabson struct kadm5_pw_policy_check_func builtin_funcs[] = { 237c19800e8SDoug Rabson { "minimum-length", min_length_passwd_quality }, 238c19800e8SDoug Rabson { "character-class", char_class_passwd_quality }, 239c19800e8SDoug Rabson { "external-check", external_passwd_quality }, 240c19800e8SDoug Rabson { NULL } 241c19800e8SDoug Rabson }; 242c19800e8SDoug Rabson struct kadm5_pw_policy_verifier builtin_verifier = { 243c19800e8SDoug Rabson "builtin", 244c19800e8SDoug Rabson KADM5_PASSWD_VERSION_V1, 245c19800e8SDoug Rabson "Heimdal builtin", 246c19800e8SDoug Rabson builtin_funcs 247c19800e8SDoug Rabson }; 248c19800e8SDoug Rabson 249c19800e8SDoug Rabson static struct kadm5_pw_policy_verifier **verifiers; 250c19800e8SDoug Rabson static int num_verifiers; 251b528cefcSMark Murray 252b528cefcSMark Murray /* 253b528cefcSMark Murray * setup the password quality hook 254b528cefcSMark Murray */ 255b528cefcSMark Murray 256c19800e8SDoug Rabson #ifndef RTLD_NOW 257c19800e8SDoug Rabson #define RTLD_NOW 0 258c19800e8SDoug Rabson #endif 259c19800e8SDoug Rabson 260b528cefcSMark Murray void 261b528cefcSMark Murray kadm5_setup_passwd_quality_check(krb5_context context, 262b528cefcSMark Murray const char *check_library, 263b528cefcSMark Murray const char *check_function) 264b528cefcSMark Murray { 265b528cefcSMark Murray #ifdef HAVE_DLOPEN 266b528cefcSMark Murray void *handle; 267b528cefcSMark Murray void *sym; 268b528cefcSMark Murray int *version; 269b528cefcSMark Murray const char *tmp; 270b528cefcSMark Murray 271b528cefcSMark Murray if(check_library == NULL) { 272b528cefcSMark Murray tmp = krb5_config_get_string(context, NULL, 273b528cefcSMark Murray "password_quality", 274b528cefcSMark Murray "check_library", 275b528cefcSMark Murray NULL); 276b528cefcSMark Murray if(tmp != NULL) 277b528cefcSMark Murray check_library = tmp; 278b528cefcSMark Murray } 279b528cefcSMark Murray if(check_function == NULL) { 280b528cefcSMark Murray tmp = krb5_config_get_string(context, NULL, 281b528cefcSMark Murray "password_quality", 282b528cefcSMark Murray "check_function", 283b528cefcSMark Murray NULL); 284b528cefcSMark Murray if(tmp != NULL) 285b528cefcSMark Murray check_function = tmp; 286b528cefcSMark Murray } 287b528cefcSMark Murray if(check_library != NULL && check_function == NULL) 288b528cefcSMark Murray check_function = "passwd_check"; 289b528cefcSMark Murray 290b528cefcSMark Murray if(check_library == NULL) 291b528cefcSMark Murray return; 292c19800e8SDoug Rabson handle = dlopen(check_library, RTLD_NOW); 293b528cefcSMark Murray if(handle == NULL) { 294b528cefcSMark Murray krb5_warnx(context, "failed to open `%s'", check_library); 295b528cefcSMark Murray return; 296b528cefcSMark Murray } 297b528cefcSMark Murray version = dlsym(handle, "version"); 298b528cefcSMark Murray if(version == NULL) { 299b528cefcSMark Murray krb5_warnx(context, 300b528cefcSMark Murray "didn't find `version' symbol in `%s'", check_library); 301b528cefcSMark Murray dlclose(handle); 302b528cefcSMark Murray return; 303b528cefcSMark Murray } 304c19800e8SDoug Rabson if(*version != KADM5_PASSWD_VERSION_V0) { 305b528cefcSMark Murray krb5_warnx(context, 306b528cefcSMark Murray "version of loaded library is %d (expected %d)", 307c19800e8SDoug Rabson *version, KADM5_PASSWD_VERSION_V0); 308b528cefcSMark Murray dlclose(handle); 309b528cefcSMark Murray return; 310b528cefcSMark Murray } 311b528cefcSMark Murray sym = dlsym(handle, check_function); 312b528cefcSMark Murray if(sym == NULL) { 313b528cefcSMark Murray krb5_warnx(context, 314b528cefcSMark Murray "didn't find `%s' symbol in `%s'", 315b528cefcSMark Murray check_function, check_library); 316b528cefcSMark Murray dlclose(handle); 317b528cefcSMark Murray return; 318b528cefcSMark Murray } 319c19800e8SDoug Rabson passwd_quality_check = (kadm5_passwd_quality_check_func_v0) sym; 320b528cefcSMark Murray #endif /* HAVE_DLOPEN */ 321b528cefcSMark Murray } 322b528cefcSMark Murray 323c19800e8SDoug Rabson #ifdef HAVE_DLOPEN 324c19800e8SDoug Rabson 325c19800e8SDoug Rabson static krb5_error_code 326c19800e8SDoug Rabson add_verifier(krb5_context context, const char *check_library) 327c19800e8SDoug Rabson { 328c19800e8SDoug Rabson struct kadm5_pw_policy_verifier *v, **tmp; 329c19800e8SDoug Rabson void *handle; 330c19800e8SDoug Rabson int i; 331c19800e8SDoug Rabson 332c19800e8SDoug Rabson handle = dlopen(check_library, RTLD_NOW); 333c19800e8SDoug Rabson if(handle == NULL) { 334c19800e8SDoug Rabson krb5_warnx(context, "failed to open `%s'", check_library); 335c19800e8SDoug Rabson return ENOENT; 336c19800e8SDoug Rabson } 337c19800e8SDoug Rabson v = dlsym(handle, "kadm5_password_verifier"); 338c19800e8SDoug Rabson if(v == NULL) { 339c19800e8SDoug Rabson krb5_warnx(context, 340c19800e8SDoug Rabson "didn't find `kadm5_password_verifier' symbol " 341c19800e8SDoug Rabson "in `%s'", check_library); 342c19800e8SDoug Rabson dlclose(handle); 343c19800e8SDoug Rabson return ENOENT; 344c19800e8SDoug Rabson } 345c19800e8SDoug Rabson if(v->version != KADM5_PASSWD_VERSION_V1) { 346c19800e8SDoug Rabson krb5_warnx(context, 347c19800e8SDoug Rabson "version of loaded library is %d (expected %d)", 348c19800e8SDoug Rabson v->version, KADM5_PASSWD_VERSION_V1); 349c19800e8SDoug Rabson dlclose(handle); 350c19800e8SDoug Rabson return EINVAL; 351c19800e8SDoug Rabson } 352c19800e8SDoug Rabson for (i = 0; i < num_verifiers; i++) { 353c19800e8SDoug Rabson if (strcmp(v->name, verifiers[i]->name) == 0) 354c19800e8SDoug Rabson break; 355c19800e8SDoug Rabson } 356c19800e8SDoug Rabson if (i < num_verifiers) { 357c19800e8SDoug Rabson krb5_warnx(context, "password verifier library `%s' is already loaded", 358c19800e8SDoug Rabson v->name); 359c19800e8SDoug Rabson dlclose(handle); 360c19800e8SDoug Rabson return 0; 361c19800e8SDoug Rabson } 362c19800e8SDoug Rabson 363c19800e8SDoug Rabson tmp = realloc(verifiers, (num_verifiers + 1) * sizeof(*verifiers)); 364c19800e8SDoug Rabson if (tmp == NULL) { 365c19800e8SDoug Rabson krb5_warnx(context, "out of memory"); 366c19800e8SDoug Rabson dlclose(handle); 367c19800e8SDoug Rabson return 0; 368c19800e8SDoug Rabson } 369c19800e8SDoug Rabson verifiers = tmp; 370c19800e8SDoug Rabson verifiers[num_verifiers] = v; 371c19800e8SDoug Rabson num_verifiers++; 372c19800e8SDoug Rabson 373c19800e8SDoug Rabson return 0; 374c19800e8SDoug Rabson } 375c19800e8SDoug Rabson 376c19800e8SDoug Rabson #endif 377c19800e8SDoug Rabson 378c19800e8SDoug Rabson krb5_error_code 379c19800e8SDoug Rabson kadm5_add_passwd_quality_verifier(krb5_context context, 380c19800e8SDoug Rabson const char *check_library) 381c19800e8SDoug Rabson { 382c19800e8SDoug Rabson #ifdef HAVE_DLOPEN 383c19800e8SDoug Rabson 384c19800e8SDoug Rabson if(check_library == NULL) { 385c19800e8SDoug Rabson krb5_error_code ret; 386c19800e8SDoug Rabson char **tmp; 387c19800e8SDoug Rabson 388c19800e8SDoug Rabson tmp = krb5_config_get_strings(context, NULL, 389c19800e8SDoug Rabson "password_quality", 390c19800e8SDoug Rabson "policy_libraries", 391c19800e8SDoug Rabson NULL); 392c19800e8SDoug Rabson if(tmp == NULL) 393c19800e8SDoug Rabson return 0; 394c19800e8SDoug Rabson 395c19800e8SDoug Rabson while(tmp) { 396c19800e8SDoug Rabson ret = add_verifier(context, *tmp); 397c19800e8SDoug Rabson if (ret) 398c19800e8SDoug Rabson return ret; 399c19800e8SDoug Rabson tmp++; 400c19800e8SDoug Rabson } 401c19800e8SDoug Rabson } 402c19800e8SDoug Rabson return add_verifier(context, check_library); 403c19800e8SDoug Rabson #else 404c19800e8SDoug Rabson return 0; 405c19800e8SDoug Rabson #endif /* HAVE_DLOPEN */ 406c19800e8SDoug Rabson } 407c19800e8SDoug Rabson 408c19800e8SDoug Rabson /* 409c19800e8SDoug Rabson * 410c19800e8SDoug Rabson */ 411c19800e8SDoug Rabson 412c19800e8SDoug Rabson static const struct kadm5_pw_policy_check_func * 413c19800e8SDoug Rabson find_func(krb5_context context, const char *name) 414c19800e8SDoug Rabson { 415c19800e8SDoug Rabson const struct kadm5_pw_policy_check_func *f; 416c19800e8SDoug Rabson char *module = NULL; 417c19800e8SDoug Rabson const char *p, *func; 418c19800e8SDoug Rabson int i; 419c19800e8SDoug Rabson 420c19800e8SDoug Rabson p = strchr(name, ':'); 421c19800e8SDoug Rabson if (p) { 422c19800e8SDoug Rabson func = p + 1; 423c19800e8SDoug Rabson module = strndup(name, p - name); 424c19800e8SDoug Rabson if (module == NULL) 425c19800e8SDoug Rabson return NULL; 426c19800e8SDoug Rabson } else 427c19800e8SDoug Rabson func = name; 428c19800e8SDoug Rabson 429c19800e8SDoug Rabson /* Find module in loaded modules first */ 430c19800e8SDoug Rabson for (i = 0; i < num_verifiers; i++) { 431c19800e8SDoug Rabson if (module && strcmp(module, verifiers[i]->name) != 0) 432c19800e8SDoug Rabson continue; 433c19800e8SDoug Rabson for (f = verifiers[i]->funcs; f->name ; f++) 434c19800e8SDoug Rabson if (strcmp(name, f->name) == 0) { 435c19800e8SDoug Rabson if (module) 436c19800e8SDoug Rabson free(module); 437c19800e8SDoug Rabson return f; 438c19800e8SDoug Rabson } 439c19800e8SDoug Rabson } 440c19800e8SDoug Rabson /* Lets try try the builtin modules */ 441c19800e8SDoug Rabson if (module == NULL || strcmp(module, "builtin") == 0) { 442c19800e8SDoug Rabson for (f = builtin_verifier.funcs; f->name ; f++) 443c19800e8SDoug Rabson if (strcmp(func, f->name) == 0) { 444c19800e8SDoug Rabson if (module) 445c19800e8SDoug Rabson free(module); 446c19800e8SDoug Rabson return f; 447c19800e8SDoug Rabson } 448c19800e8SDoug Rabson } 449c19800e8SDoug Rabson if (module) 450c19800e8SDoug Rabson free(module); 451c19800e8SDoug Rabson return NULL; 452c19800e8SDoug Rabson } 453c19800e8SDoug Rabson 454b528cefcSMark Murray const char * 455b528cefcSMark Murray kadm5_check_password_quality (krb5_context context, 456b528cefcSMark Murray krb5_principal principal, 457b528cefcSMark Murray krb5_data *pwd_data) 458b528cefcSMark Murray { 459c19800e8SDoug Rabson const struct kadm5_pw_policy_check_func *proc; 460c19800e8SDoug Rabson static char error_msg[1024]; 461c19800e8SDoug Rabson const char *msg; 462c19800e8SDoug Rabson char **v, **vp; 463c19800e8SDoug Rabson int ret; 464c19800e8SDoug Rabson 465c19800e8SDoug Rabson /* 466c19800e8SDoug Rabson * Check if we should use the old version of policy function. 467c19800e8SDoug Rabson */ 468c19800e8SDoug Rabson 469c19800e8SDoug Rabson v = krb5_config_get_strings(context, NULL, 470c19800e8SDoug Rabson "password_quality", 471c19800e8SDoug Rabson "policies", 472c19800e8SDoug Rabson NULL); 473c19800e8SDoug Rabson if (v == NULL) { 474c19800e8SDoug Rabson msg = (*passwd_quality_check) (context, principal, pwd_data); 475c19800e8SDoug Rabson krb5_set_error_string(context, "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"; 486c19800e8SDoug Rabson krb5_set_error_string(context, "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) { 493c19800e8SDoug Rabson krb5_set_error_string(context, "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) 507c19800e8SDoug Rabson krb5_set_error_string(context, "(old) password policy " 508c19800e8SDoug Rabson "failed with %s", msg); 509c19800e8SDoug Rabson 510c19800e8SDoug Rabson } 511c19800e8SDoug Rabson return msg; 512b528cefcSMark Murray } 513