diff options
Diffstat (limited to 'src/lib/kadm5')
-rw-r--r-- | src/lib/kadm5/server_internal.h | 53 | ||||
-rw-r--r-- | src/lib/kadm5/srv/Makefile.in | 16 | ||||
-rw-r--r-- | src/lib/kadm5/srv/libkadm5srv_mit.exports | 3 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual.c | 114 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_dict.c | 242 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_policy.c | 81 | ||||
-rw-r--r-- | src/lib/kadm5/srv/server_dict.c | 208 | ||||
-rw-r--r-- | src/lib/kadm5/srv/server_init.c | 4 | ||||
-rw-r--r-- | src/lib/kadm5/srv/server_misc.c | 187 | ||||
-rw-r--r-- | src/lib/kadm5/srv/svr_principal.c | 6 |
10 files changed, 553 insertions, 361 deletions
diff --git a/src/lib/kadm5/server_internal.h b/src/lib/kadm5/server_internal.h index cc589fa..52f71e9 100644 --- a/src/lib/kadm5/server_internal.h +++ b/src/lib/kadm5/server_internal.h @@ -22,6 +22,7 @@ #include <errno.h> #include <kdb.h> #include <kadm5/admin.h> +#include <krb5/plugin.h> #include "admin_internal.h" /* @@ -33,6 +34,9 @@ */ #define INITIAL_HIST_KVNO 2 +/* A pwqual_handle represents a password quality plugin module. */ +typedef struct pwqual_handle_st *pwqual_handle; + typedef struct _kadm5_server_handle_t { krb5_ui_4 magic_number; krb5_ui_4 struct_version; @@ -42,6 +46,7 @@ typedef struct _kadm5_server_handle_t { kadm5_config_params params; struct _kadm5_server_handle_t *lhandle; char **db_args; + pwqual_handle *qual_handles; } kadm5_server_handle_rec, *kadm5_server_handle_t; #define OSA_ADB_PRINC_VERSION_1 0x12345C01 @@ -65,8 +70,7 @@ typedef struct _osa_princ_ent_t { kadm5_ret_t adb_policy_init(kadm5_server_handle_t handle); kadm5_ret_t adb_policy_close(kadm5_server_handle_t handle); kadm5_ret_t passwd_check(kadm5_server_handle_t handle, - char *pass, int use_policy, - kadm5_policy_ent_t policy, + const char *pass, kadm5_policy_ent_t policy, krb5_principal principal); kadm5_ret_t principal_exists(krb5_principal principal); krb5_error_code kdb_init_master(kadm5_server_handle_t handle, @@ -90,9 +94,8 @@ krb5_error_code kdb_iter_entry(kadm5_server_handle_t handle, void (*iter_fct)(void *, krb5_principal), void *data); -int init_dict(kadm5_config_params *); -int find_word(const char *word); -void destroy_dict(void); +kadm5_ret_t init_pwqual(kadm5_server_handle_t handle); +void destroy_pwqual(kadm5_server_handle_t handle); /* XXX this ought to be in libkrb5.a, but isn't */ kadm5_ret_t krb5_copy_key_data_contents(krb5_context context, @@ -153,4 +156,44 @@ bool_t xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp); void osa_free_princ_ent(osa_princ_ent_t val); +/*** Password quality plugin consumer interface ***/ + +/* Load the available password quality plugins and store the result into + * *handles. Free the result with k5_pwqual_free_handles. */ +krb5_error_code +k5_pwqual_load(krb5_context context, pwqual_handle **handles); + +/* Release a handle list allocated by k5_pwqual_load. All modules must have + * been closed by the caller. */ +krb5_error_code +k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles); + +/* Initialize a password quality plugin, possibly using the realm's configured + * dictionary filename. */ +krb5_error_code +k5_pwqual_open(krb5_context context, pwqual_handle handle, + const char *dict_file); + +/* Check a password using a password quality plugin. */ +krb5_error_code +k5_pwqual_check(krb5_context context, pwqual_handle handle, + const char *password, kadm5_policy_ent_t policy, + krb5_principal princ); + +/* Release the memory used by a password quality plugin. */ +void +k5_pwqual_close(krb5_context context, pwqual_handle handle); + +/*** Init functions for built-in password quality modules ***/ + +/* The dict module checks passwords against the realm's dictionary. */ +krb5_error_code +pwqual_dict_init(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +/* The policy module enforces password policy constraints. */ +krb5_error_code +pwqual_policy_init(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + #endif /* __KADM5_SERVER_INTERNAL_H__ */ diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in index c7e0fac..6000d73 100644 --- a/src/lib/kadm5/srv/Makefile.in +++ b/src/lib/kadm5/srv/Makefile.in @@ -27,36 +27,42 @@ SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) RELDIR=kadm5/srv -SRCS = $(srcdir)/svr_policy.c \ +SRCS = $(srcdir)/pwqual.c \ + $(srcdir)/pwqual_dict.c \ + $(srcdir)/pwqual_policy.c \ + $(srcdir)/svr_policy.c \ $(srcdir)/svr_principal.c \ $(srcdir)/server_acl.c \ $(srcdir)/server_kdb.c \ $(srcdir)/server_misc.c \ $(srcdir)/server_init.c \ - $(srcdir)/server_dict.c \ $(srcdir)/svr_iters.c \ $(srcdir)/svr_chpass_util.c \ $(srcdir)/adb_xdr.c -OBJS = svr_policy.$(OBJEXT) \ +OBJS = pwqual.$(OBJEXT) \ + pwqual_dict.$(OBJEXT) \ + pwqual_policy.$(OBJECT) \ + svr_policy.$(OBJEXT) \ svr_principal.$(OBJEXT) \ server_acl.$(OBJEXT) \ server_kdb.$(OBJEXT) \ server_misc.$(OBJEXT) \ server_init.$(OBJEXT) \ - server_dict.$(OBJEXT) \ svr_iters.$(OBJEXT) \ svr_chpass_util.$(OBJEXT) \ adb_xdr.$(OBJEXT) STLIBOBJS = \ + pwqual.o \ + pwqual_dict.o \ + pwqual_policy.o \ svr_policy.o \ svr_principal.o \ server_acl.o \ server_kdb.o \ server_misc.o \ server_init.o \ - server_dict.o \ svr_iters.o \ svr_chpass_util.o \ adb_xdr.o diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports index 6da95bd..345957a 100644 --- a/src/lib/kadm5/srv/libkadm5srv_mit.exports +++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports @@ -7,10 +7,7 @@ kadm5int_acl_impose_restrictions kadm5int_acl_init adb_policy_close adb_policy_init -destroy_dict -find_word hist_princ -init_dict kadm5_set_use_password_server kadm5_chpass_principal kadm5_chpass_principal_3 diff --git a/src/lib/kadm5/srv/pwqual.c b/src/lib/kadm5/srv/pwqual.c new file mode 100644 index 0000000..4452376 --- /dev/null +++ b/src/lib/kadm5/srv/pwqual.c @@ -0,0 +1,114 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual.c + * + * Copyright (C) 2010 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Consumer interface for password quality plugins + */ + +#include "k5-int.h" +#include "server_internal.h" +#include <krb5/pwqual_plugin.h> + +struct pwqual_handle_st { + struct krb5_pwqual_vtable_st vt; + krb5_pwqual_moddata data; +}; + +krb5_error_code +k5_pwqual_load(krb5_context context, pwqual_handle **handles) +{ + krb5_error_code ret; + krb5_plugin_init_fn *modules = NULL, *mod; + size_t count; + pwqual_handle *list = NULL, handle = NULL; + + ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &modules); + if (ret != 0) + goto cleanup; + + /* Allocate a large enough list of handles. */ + for (count = 0; modules[count] != NULL; count++); + list = k5alloc((count + 1) * sizeof(*list), &ret); + if (list == NULL) + goto cleanup; + + /* For each module, allocate a handle and initialize its vtable. Skip + * modules which don't successfully initialize. */ + count = 0; + for (mod = modules; *mod != NULL; mod++) { + handle = k5alloc(sizeof(*handle), &ret); + if (handle == NULL) + goto cleanup; + ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&handle->vt); + if (ret == 0) + list[count++] = handle; + else + free(handle); + } + + *handles = list; + list = NULL; + +cleanup: + k5_plugin_free_modules(context, modules); + k5_pwqual_free_handles(context, list); + return ret; +} + +krb5_error_code +k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles) +{ + /* It's the caller's responsibility to close each handle, so all of the + * module data should be freed by now, leaving only the list itself. */ + free(handles); +} + +krb5_error_code +k5_pwqual_open(krb5_context context, pwqual_handle handle, + const char *dict_file) +{ + if (handle->data != NULL) + return EINVAL; + if (handle->vt.open == NULL) + return 0; + return handle->vt.open(context, dict_file, &handle->data); +} + +krb5_error_code +k5_pwqual_check(krb5_context context, pwqual_handle handle, + const char *password, kadm5_policy_ent_t policy, + krb5_principal princ) +{ + return handle->vt.check(context, handle->data, password, policy, princ); +} + +void +k5_pwqual_close(krb5_context context, pwqual_handle handle) +{ + if (handle->vt.close) + handle->vt.close(context, handle->data); + handle->data = NULL; +} diff --git a/src/lib/kadm5/srv/pwqual_dict.c b/src/lib/kadm5/srv/pwqual_dict.c new file mode 100644 index 0000000..60bc5ff --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_dict.c @@ -0,0 +1,242 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include "k5-platform.h" +#include <krb5/pwqual_plugin.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <kadm5/admin.h> +#include "adm_proto.h" +#include <syslog.h> +#include "server_internal.h" + +typedef struct dict_moddata_st { + char **word_list; /* list of word pointers */ + char *word_block; /* actual word data */ + unsigned int word_count; /* number of words */ +} *dict_moddata; + + +/* + * Function: word_compare + * + * Purpose: compare two words in the dictionary. + * + * Arguments: + * w1 (input) pointer to first word + * w2 (input) pointer to second word + * <return value> result of strcmp + * + * Requires: + * w1 and w2 to point to valid memory + * + */ + +static int +word_compare(const void *s1, const void *s2) +{ + return (strcasecmp(*(const char **)s1, *(const char **)s2)); +} + +/* + * Function: init-dict + * + * Purpose: Initialize in memory word dictionary + * + * Arguments: + * none + * <return value> KADM5_OK on success errno on failure; + * (but success on ENOENT) + * + * Requires: + * If WORDFILE exists, it must contain a list of words, + * one word per-line. + * + * Effects: + * If WORDFILE exists, it is read into memory sorted for future + * use. If it does not exist, it syslogs an error message and returns + * success. + * + * Modifies: + * word_list to point to a chunck of allocated memory containing + * pointers to words + * word_block to contain the dictionary. + * + */ + +static int +init_dict(dict_moddata dict, const char *dict_file) +{ + int fd; + size_t len, i; + char *p, *t; + struct stat sb; + + if (dict_file == NULL) { + krb5_klog_syslog(LOG_INFO, "No dictionary file specified, continuing " + "without one."); + return KADM5_OK; + } + if ((fd = open(dict_file, O_RDONLY)) == -1) { + if (errno == ENOENT) { + krb5_klog_syslog(LOG_ERR, + "WARNING! Cannot find dictionary file %s, " + "continuing without one.", dict_file); + return KADM5_OK; + } else + return errno; + } + set_cloexec_fd(fd); + if (fstat(fd, &sb) == -1) { + close(fd); + return errno; + } + if ((dict->word_block = malloc(sb.st_size + 1)) == NULL) + return ENOMEM; + if (read(fd, dict->word_block, sb.st_size) != sb.st_size) + return errno; + (void) close(fd); + dict->word_block[sb.st_size] = '\0'; + + p = dict->word_block; + len = sb.st_size; + while(len > 0 && (t = memchr(p, '\n', len)) != NULL) { + *t = '\0'; + len -= t - p + 1; + p = t + 1; + dict->word_count++; + } + if ((dict->word_list = malloc(dict->word_count * sizeof(char *))) == NULL) + return ENOMEM; + p = dict->word_block; + for (i = 0; i < dict->word_count; i++) { + dict->word_list[i] = p; + p += strlen(p) + 1; + } + qsort(dict->word_list, dict->word_count, sizeof(char *), word_compare); + return KADM5_OK; +} + +/* + * Function: destroy_dict + * + * Purpose: destroy in-core copy of dictionary. + * + * Arguments: + * none + * <return value> none + * Requires: + * nothing + * Effects: + * frees up memory occupied by word_list and word_block + * sets count back to 0, and resets the pointers to NULL + * + * Modifies: + * word_list, word_block, and word_count. + * + */ + +static void +destroy_dict(dict_moddata dict) +{ + if (dict == NULL) + return; + free(dict->word_list); + free(dict->word_block); + free(dict); + return; +} + +/* Implement the password quality open method by reading in dict_file. */ +static krb5_error_code +dict_open(krb5_context context, const char *dict_file, + krb5_pwqual_moddata *data) +{ + krb5_error_code ret; + dict_moddata dict; + + *data = NULL; + + /* Allocate and initialize a dictionary structure. */ + dict = malloc(sizeof(*dict)); + if (dict == NULL) + return ENOMEM; + dict->word_list = NULL; + dict->word_block = NULL; + dict->word_count = 0; + + /* Fill in the dictionary structure with data from dict_file. */ + ret = init_dict(dict, dict_file); + if (ret != 0) { + destroy_dict(dict); + return ret; + } + + *data = (krb5_pwqual_moddata)dict; + return 0; +} + +/* Implement the password quality check method by checking the password + * against the dictionary, as well as against principal components. */ +static krb5_error_code +dict_check(krb5_context context, krb5_pwqual_moddata data, + const char *password, kadm5_policy_ent_t policy, + krb5_principal princ) +{ + dict_moddata dict = (dict_moddata)data; + int i, n; + char *cp; + + /* Don't check the dictionary for principals with no password policy. */ + if (policy == NULL) + return 0; + + /* Check against words in the dictionary if we successfully loaded one. */ + if (dict->word_list != NULL && + bsearch(&password, dict->word_list, dict->word_count, sizeof(char *), + word_compare) != NULL) + return KADM5_PASS_Q_DICT; + + /* Check against components of the principal. */ + n = krb5_princ_size(handle->context, princ); + cp = krb5_princ_realm(handle->context, princ)->data; + if (strcasecmp(cp, password) == 0) + return KADM5_PASS_Q_DICT; + for (i = 0; i < n; i++) { + cp = krb5_princ_component(handle->context, princ, i)->data; + if (strcasecmp(cp, password) == 0) + return KADM5_PASS_Q_DICT; + } + return 0; +} + +/* Implement the password quality close method. */ +static void +dict_close(krb5_context context, krb5_pwqual_moddata data) +{ + destroy_dict((dict_moddata)data); +} + +krb5_error_code +pwqual_dict_init(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return EINVAL; /* XXX create error code */ + vt = (krb5_pwqual_vtable)vtable; + vt->open = dict_open; + vt->check = dict_check; + vt->close = dict_close; + return 0; +} diff --git a/src/lib/kadm5/srv/pwqual_policy.c b/src/lib/kadm5/srv/pwqual_policy.c new file mode 100644 index 0000000..978744d --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_policy.c @@ -0,0 +1,81 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual_policy.c + * + * Copyright (C) 2010 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Password quality module to enforce password policy + */ + +#include "k5-platform.h" +#include <krb5/pwqual_plugin.h> +#include <kadm5/admin.h> +#include <ctype.h> +#include "server_internal.h" + +/* Implement the password quality check module. */ +static krb5_error_code +policy_check(krb5_context context, krb5_pwqual_moddata data, + const char *password, kadm5_policy_ent_t policy, + krb5_principal princ) +{ + int nupper = 0, nlower = 0, ndigit = 0, npunct = 0, nspec = 0; + const char *s; + unsigned char c; + + if (policy == NULL) + return (*password == '\0') ? KADM5_PASS_Q_TOOSHORT : 0; + + if(strlen(password) < (size_t)policy->pw_min_length) + return KADM5_PASS_Q_TOOSHORT; + s = password; + while ((c = (unsigned char)*s++)) { + if (islower(c)) + nlower = 1; + else if (isupper(c)) + nupper = 1; + else if (isdigit(c)) + ndigit = 1; + else if (ispunct(c)) + npunct = 1; + else + nspec = 1; + } + if ((nupper + nlower + ndigit + npunct + nspec) < policy->pw_min_classes) + return KADM5_PASS_Q_CLASS; + return 0; +} + +krb5_error_code +pwqual_policy_init(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return EINVAL; /* XXX create error code */ + vt = (krb5_pwqual_vtable)vtable; + vt->check = policy_check; + return 0; +} diff --git a/src/lib/kadm5/srv/server_dict.c b/src/lib/kadm5/srv/server_dict.c deleted file mode 100644 index 81cc5f9..0000000 --- a/src/lib/kadm5/srv/server_dict.c +++ /dev/null @@ -1,208 +0,0 @@ -/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved - * - * $Header$ - */ - -#if !defined(lint) && !defined(__CODECENTER__) -static char *rcsid = "$Header$"; -#endif - -#include <sys/types.h> -#include <sys/file.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <unistd.h> -#include <errno.h> -#include <kadm5/admin.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#ifdef HAVE_MEMORY_H -#include <memory.h> -#endif -#include "adm_proto.h" -#include <syslog.h> -#include "server_internal.h" -#include "k5-platform.h" - -static char **word_list = NULL; /* list of word pointers */ -static char *word_block = NULL; /* actual word data */ -static unsigned int word_count = 0; /* number of words */ - - -/* - * Function: word_compare - * - * Purpose: compare two words in the dictionary. - * - * Arguments: - * w1 (input) pointer to first word - * w2 (input) pointer to second word - * <return value> result of strcmp - * - * Requires: - * w1 and w2 to point to valid memory - * - */ - -static int -word_compare(const void *s1, const void *s2) -{ - return (strcasecmp(*(const char **)s1, *(const char **)s2)); -} - -/* - * Function: init-dict - * - * Purpose: Initialize in memory word dictionary - * - * Arguments: - * none - * <return value> KADM5_OK on success errno on failure; - * (but success on ENOENT) - * - * Requires: - * If WORDFILE exists, it must contain a list of words, - * one word per-line. - * - * Effects: - * If WORDFILE exists, it is read into memory sorted for future - * use. If it does not exist, it syslogs an error message and returns - * success. - * - * Modifies: - * word_list to point to a chunck of allocated memory containing - * pointers to words - * word_block to contain the dictionary. - * - */ - -int init_dict(kadm5_config_params *params) -{ - int fd, - len, - i; - char *p, - *t; - struct stat sb; - - if(word_list != NULL && word_block != NULL) - return KADM5_OK; - if (! (params->mask & KADM5_CONFIG_DICT_FILE)) { - krb5_klog_syslog(LOG_INFO, "No dictionary file specified, continuing " - "without one."); - return KADM5_OK; - } - if ((fd = open(params->dict_file, O_RDONLY)) == -1) { - if (errno == ENOENT) { - krb5_klog_syslog(LOG_ERR, - "WARNING! Cannot find dictionary file %s, " - "continuing without one.", params->dict_file); - return KADM5_OK; - } else - return errno; - } - set_cloexec_fd(fd); - if (fstat(fd, &sb) == -1) { - close(fd); - return errno; - } - if ((word_block = (char *) malloc(sb.st_size + 1)) == NULL) - return ENOMEM; - if (read(fd, word_block, sb.st_size) != sb.st_size) - return errno; - (void) close(fd); - word_block[sb.st_size] = '\0'; - - p = word_block; - len = sb.st_size; - while(len > 0 && (t = memchr(p, '\n', len)) != NULL) { - *t = '\0'; - len -= t - p + 1; - p = t + 1; - word_count++; - } - if ((word_list = (char **) malloc(word_count * sizeof(char *))) == NULL) - return ENOMEM; - p = word_block; - for (i = 0; i < word_count; i++) { - word_list[i] = p; - p += strlen(p) + 1; - } - qsort(word_list, word_count, sizeof(char *), word_compare); - return KADM5_OK; -} - -/* - * Function: find_word - * - * Purpose: See if the specified word exists in the in-core dictionary - * - * Arguments: - * word (input) word to search for. - * <return value> WORD_NOT_FOUND if not in dictionary, - * KADM5_OK if if found word - * errno if init needs to be called and returns an - * error - * - * Requires: - * word to be a null terminated string. - * That word_list and word_block besetup - * - * Effects: - * finds word in dictionary. - * Modifies: - * nothing. - * - */ - -int -find_word(const char *word) -{ - char **value; - - if(word_list == NULL || word_block == NULL) - return WORD_NOT_FOUND; - if ((value = (char **) bsearch(&word, word_list, word_count, sizeof(char *), - word_compare)) == NULL) - return WORD_NOT_FOUND; - else - return KADM5_OK; -} - -/* - * Function: destroy_dict - * - * Purpose: destroy in-core copy of dictionary. - * - * Arguments: - * none - * <return value> none - * Requires: - * nothing - * Effects: - * frees up memory occupied by word_list and word_block - * sets count back to 0, and resets the pointers to NULL - * - * Modifies: - * word_list, word_block, and word_count. - * - */ - -void -destroy_dict(void) -{ - if(word_list) { - free(word_list); - word_list = NULL; - } - if(word_block) { - free(word_block); - word_block = NULL; - } - if(word_count) - word_count = 0; - return; -} diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c index 557ef0a..9ebc13e 100644 --- a/src/lib/kadm5/srv/server_init.c +++ b/src/lib/kadm5/srv/server_init.c @@ -317,7 +317,7 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass, return ret; } - ret = init_dict(&handle->params); + ret = init_pwqual(handle); if (ret) { krb5_db_fini(handle->context); krb5_free_principal(handle->context, handle->current_caller); @@ -337,7 +337,7 @@ kadm5_ret_t kadm5_destroy(void *server_handle) CHECK_HANDLE(server_handle); - destroy_dict(); + destroy_pwqual(handle); adb_policy_close(handle); krb5_db_fini(handle->context); diff --git a/src/lib/kadm5/srv/server_misc.c b/src/lib/kadm5/srv/server_misc.c index 1faeb86..38c0607 100644 --- a/src/lib/kadm5/srv/server_misc.c +++ b/src/lib/kadm5/srv/server_misc.c @@ -13,10 +13,6 @@ static char *rcsid = "$Header$"; #include <kdb.h> #include <ctype.h> #include <pwd.h> - -/* for strcasecmp */ -#include <string.h> - #include "server_internal.h" kadm5_ret_t @@ -37,147 +33,68 @@ adb_policy_close(kadm5_server_handle_t handle) return KADM5_OK; } -#ifdef HESIOD -/* stolen from v4sever/kadm_funcs.c */ -static char * -reverse(str) - char *str; -{ - static char newstr[80]; - char *p, *q; - int i; - - i = strlen(str); - if (i >= sizeof(newstr)) - i = sizeof(newstr)-1; - p = str+i-1; - q = newstr; - q[i]='\0'; - for(; i > 0; i--) - *q++ = *p--; - - return(newstr); -} -#endif /* HESIOD */ - -#if 0 -static int -lower(str) - char *str; +kadm5_ret_t +init_pwqual(kadm5_server_handle_t handle) { - register char *cp; - int effect=0; - - for (cp = str; *cp; cp++) { - if (isupper(*cp)) { - *cp = tolower(*cp); - effect++; + krb5_error_code ret; + pwqual_handle *list, *h; + const char *dict_file = NULL; + + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "dict", pwqual_dict_init); + if (ret != 0) + return ret; + + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "policy", pwqual_policy_init); + if (ret != 0) + return ret; + + ret = k5_pwqual_load(handle->context, &list); + if (ret != 0) + return ret; + + if (handle->params.mask & KADM5_CONFIG_DICT_FILE) + dict_file = handle->params.dict_file; + + for (h = list; *h != NULL; h++) { + ret = k5_pwqual_open(handle->context, *h, dict_file); + if (ret != 0) { + /* Close any previously opened modules and error out. */ + for (; h > list; h--) + k5_pwqual_close(handle->context, *(h - 1)); + k5_pwqual_free_handles(handle->context, list); + return ret; } } - return(effect); + + handle->qual_handles = list; + return 0; } -#endif -#ifdef HESIOD -static int -str_check_gecos(gecos, pwstr) - char *gecos; - char *pwstr; +/* Check a password against all available password quality plugin modules. */ +kadm5_ret_t +passwd_check(kadm5_server_handle_t handle, const char *password, + kadm5_policy_ent_t policy, krb5_principal princ) { - char *cp, *ncp, *tcp; - - for (cp = gecos; *cp; ) { - /* Skip past punctuation */ - for (; *cp; cp++) - if (isalnum(*cp)) - break; - /* Skip to the end of the word */ - for (ncp = cp; *ncp; ncp++) - if (!isalnum(*ncp) && *ncp != '\'') - break; - /* Delimit end of word */ - if (*ncp) - *ncp++ = '\0'; - /* Check word to see if it's the password */ - if (*cp) { - if (!strcasecmp(pwstr, cp)) - return 1; - tcp = reverse(cp); - if (!strcasecmp(pwstr, tcp)) - return 1; - cp = ncp; - } else - break; + krb5_error_code ret; + pwqual_handle *h; + + for (h = handle->qual_handles; *h != NULL; h++) { + ret = k5_pwqual_check(handle->context, *h, password, policy, princ); + if (ret != 0) + return ret; } return 0; } -#endif /* HESIOD */ -/* some of this is stolen from gatekeeper ... */ -kadm5_ret_t -passwd_check(kadm5_server_handle_t handle, - char *password, int use_policy, kadm5_policy_ent_t pol, - krb5_principal principal) +void +destroy_pwqual(kadm5_server_handle_t handle) { - int nupper = 0, - nlower = 0, - ndigit = 0, - npunct = 0, - nspec = 0; - char c, *s, *cp; -#ifdef HESIOD - extern struct passwd *hes_getpwnam(); - struct passwd *ent; -#endif + pwqual_handle *h; - if(use_policy) { - if(strlen(password) < pol->pw_min_length) - return KADM5_PASS_Q_TOOSHORT; - s = password; - while ((c = *s++)) { - if (islower((unsigned char) c)) { - nlower = 1; - continue; - } - else if (isupper((unsigned char) c)) { - nupper = 1; - continue; - } else if (isdigit((unsigned char) c)) { - ndigit = 1; - continue; - } else if (ispunct((unsigned char) c)) { - npunct = 1; - continue; - } else { - nspec = 1; - continue; - } - } - if ((nupper + nlower + ndigit + npunct + nspec) < pol->pw_min_classes) - return KADM5_PASS_Q_CLASS; - if((find_word(password) == KADM5_OK)) - return KADM5_PASS_Q_DICT; - else { - int i, n = krb5_princ_size(handle->context, principal); - cp = krb5_princ_realm(handle->context, principal)->data; - if (strcasecmp(cp, password) == 0) - return KADM5_PASS_Q_DICT; - for (i = 0; i < n ; i++) { - cp = krb5_princ_component(handle->context, principal, i)->data; - if (strcasecmp(cp, password) == 0) - return KADM5_PASS_Q_DICT; -#ifdef HESIOD - ent = hes_getpwnam(cp); - if (ent && ent->pw_gecos) - if (str_check_gecos(ent->pw_gecos, password)) - return KADM5_PASS_Q_DICT; /* XXX new error code? */ -#endif - } - return KADM5_OK; - } - } else { - if (strlen(password) < 1) - return KADM5_PASS_Q_TOOSHORT; - } - return KADM5_OK; + for (h = handle->qual_handles; *h != NULL; h++) + k5_pwqual_close(handle->context, *h); + k5_pwqual_free_handles(handle->context, handle->qual_handles); + handle->qual_handles = NULL; } diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index 6b14d3b..dc16406 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -292,7 +292,7 @@ kadm5_create_principal_3(void *server_handle, have_polent = TRUE; } if (password) { - ret = passwd_check(handle, password, have_polent, &polent, + ret = passwd_check(handle, password, have_polent ? &polent : NULL, entry->principal); if (ret) goto cleanup; @@ -1341,8 +1341,8 @@ kadm5_chpass_principal_3(void *server_handle, have_pol = 1; } - if ((ret = passwd_check(handle, password, adb.aux_attributes & - KADM5_POLICY, &pol, principal))) + if ((ret = passwd_check(handle, password, have_pol ? &pol : NULL, + principal))) goto done; ret = krb5_dbe_find_act_mkey(handle->context, master_keylist, |