diff options
author | Greg Hudson <ghudson@mit.edu> | 2010-09-01 16:40:22 +0000 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2010-09-01 16:40:22 +0000 |
commit | bd399cad888d90e99da3e5787040b34da857a34e (patch) | |
tree | af01e6e0bd5b66a3dd3e05959f34e61623114916 /src | |
parent | 18fda42e0ef82c51228ba7cbfb3915330f0c352e (diff) | |
download | krb5-bd399cad888d90e99da3e5787040b34da857a34e.tar.gz krb5-bd399cad888d90e99da3e5787040b34da857a34e.tar.xz krb5-bd399cad888d90e99da3e5787040b34da857a34e.zip |
Password quality pluggable interface
Merge branches/plugins2 to trunk. Adds a password quality pluggable
interface described in this project page:
http://k5wiki.kerberos.org/wiki/Projects/Password_quality_pluggable_interface
ticket: 6765
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24284 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r-- | src/config-files/krb5.conf.M | 56 | ||||
-rw-r--r-- | src/include/Makefile.in | 1 | ||||
-rw-r--r-- | src/include/k5-int.h | 3 | ||||
-rw-r--r-- | src/include/krb5/pwqual_plugin.h | 109 | ||||
-rw-r--r-- | src/lib/kadm5/kadm_err.et | 1 | ||||
-rw-r--r-- | src/lib/kadm5/server_internal.h | 55 | ||||
-rw-r--r-- | src/lib/kadm5/srv/Makefile.in | 22 | ||||
-rw-r--r-- | src/lib/kadm5/srv/libkadm5srv_mit.exports | 3 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual.c | 115 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_dict.c | 254 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_empty.c | 61 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_hesiod.c | 133 | ||||
-rw-r--r-- | src/lib/kadm5/srv/pwqual_princ.c | 75 | ||||
-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 | 246 | ||||
-rw-r--r-- | src/lib/kadm5/srv/svr_principal.c | 6 | ||||
-rw-r--r-- | src/lib/krb5/krb/Makefile.in | 2 | ||||
-rw-r--r-- | src/lib/krb5/krb/plugin.c | 1 |
19 files changed, 988 insertions, 367 deletions
diff --git a/src/config-files/krb5.conf.M b/src/config-files/krb5.conf.M index db3305f59..2995aa2be 100644 --- a/src/config-files/krb5.conf.M +++ b/src/config-files/krb5.conf.M @@ -110,6 +110,9 @@ Contains default values for database specific parameters. .IP [dbmodules] Contains database specific parameters used by the database library. + +.ip [plugins] +Contains plugin module registration and filtering parameters. .PP Each of these sections will be covered in more details in the following sections. @@ -682,6 +685,59 @@ is whitespace-separated. The LDAP server is specified by a LDAP URI. .IP ldap_conns_per_server This LDAP specific tag indicates the number of connections to be maintained per LDAP server. + +.SH PLUGINS SECTION + +Tags in the [plugins] section can be used to register dynamic plugin +modules and to turn modules on and off. Not every krb5 pluggable +interface uses the [plugins] section; the ones that do are documented +here. + +.PP +Each pluggable interface corresponds to a subsection of [plugins]. +All subsections support the same tags: + +.IP module +This tag may have multiple values. Each value is a string of the form +"modulename:pathname", which causes the shared object located at +pathname to be registered as a dynamic module named modulename for the +pluggable interface. If pathname is not an absolute path, it will be +treated as relative to the "krb5/plugins" subdirectory of the krb5 +library directory. + +.IP enable_only +This tag may have multiple values. If there are values for this tag, +then only the named modules will be enabled for the pluggable +interface. + +.IP disable +This tag may have multiple values. If there are values for this tag, +then the named modules will be disabled for the pluggable interface. + +.PP +The following subsections are currently supported within the [plugins] +section: + +.SS pwqual interface + +The pwqual subsection controls modules for the password quality +interface, which is used to reject weak passwords when passwords are +changed. In addition to any registered dynamic modules, the following +built-in modules exist (and may be disabled with the disable tag): + +.IP dict +Checks against the realm dictionary file + +.IP empty +Rejects empty passwords + +.IP hesiod +Checks against user information stored in Hesiod (only if Kerberos was +built with Hesiod support) + +.IP princ +Checks against components of the principal name + .SH FILES /etc/krb5.conf .SH SEE ALSO diff --git a/src/include/Makefile.in b/src/include/Makefile.in index 930712d18..5c178a24a 100644 --- a/src/include/Makefile.in +++ b/src/include/Makefile.in @@ -138,6 +138,7 @@ install-headers-unix install:: krb5/krb5.h profile.h $(INSTALL_DATA) krb5/krb5.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)krb5.h $(INSTALL_DATA) $(srcdir)/krb5/locate_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)locate_plugin.h $(INSTALL_DATA) $(srcdir)/krb5/plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/pwqual_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)pwqual_plugin.h $(INSTALL_DATA) profile.h $(DESTDIR)$(KRB5_INCDIR)$(S)profile.h $(INSTALL_DATA) $(srcdir)/gssapi.h $(DESTDIR)$(KRB5_INCDIR)$(S)gssapi.h diff --git a/src/include/k5-int.h b/src/include/k5-int.h index ec701c1df..4b2fdd25d 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -1516,7 +1516,8 @@ struct plugin_interface { /* A list of plugin interface IDs. Make sure to increment * PLUGIN_NUM_INTERFACES when a new interface is added. */ -#define PLUGIN_NUM_INTERFACES 0 +#define PLUGIN_INTERFACE_PWQUAL 0 +#define PLUGIN_NUM_INTERFACES 1 /* Retrieve the plugin module of type interface_id and name modname, * storing the result into module. */ diff --git a/src/include/krb5/pwqual_plugin.h b/src/include/krb5/pwqual_plugin.h new file mode 100644 index 000000000..403bb1152 --- /dev/null +++ b/src/include/krb5/pwqual_plugin.h @@ -0,0 +1,109 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * prototype/prototype.h + * + * 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. + * + * + * Declarations for password quality plugin module implementors. + * + * The password quality pluggable interface currently has only one supported + * major version, which is 1. Major version 1 has a current minor version + * number of 1. + * + * Password quality plugin modules should define a function named + * pwqual_<modulename>_initvt, matching the signature: + * + * krb5_error_code + * pwqual_modname_initvt(krb5_context context, int maj_ver, int min_ver, + * krb5_plugin_vtable vtable); + * + * The initvt function should: + * + * - Check that the supplied maj_ver number is supported by the module, or + * return KRB5_PLUGIN_VER_NOTSUPP if it is not. + * + * - Cast the vtable pointer as appropriate for maj_ver: + * maj_ver == 1: Cast to krb5_pwqual_vtable + * + * - Initialize the methods of the vtable, stopping as appropriate for the + * supplied min_ver. Optional methods may be left uninitialized. + * + * Memory for the vtable is allocated by the caller, not by the module. + */ + +#ifndef KRB5_PWQUAL_PLUGIN_H +#define KRB5_PWQUAL_PLUGIN_H + +#include <krb5/krb5.h> +#include <krb5/plugin.h> +#include <kadm5/admin.h> + +/* An abstract type for password quality module data. */ +typedef struct krb5_pwqual_moddata_st *krb5_pwqual_moddata; + +/*** Method type declarations ***/ + +/* Optional: Initialize module data. dictfile is the realm's configured + * dictionary filename. */ +typedef krb5_error_code +(*krb5_pwqual_open_fn)(krb5_context context, const char *dict_file, + krb5_pwqual_moddata *data); + +/* + * Mandatory: Check a password for the principal princ, which has an associated + * password policy named policy_name (or no associated policy if policy_name is + * NULL). The parameter languages, if not NULL, contains a null-terminated + * list of client-specified language tags as defined in RFC 5646. The method + * should return one of the following errors if the password fails quality + * standards: + * + * - KADM5_PASS_Q_TOOSHORT: password should be longer + * - KADM5_PASS_Q_CLASS: password must have more character classes + * - KADM5_PASS_Q_DICT: password contains dictionary words + * - KADM5_PASS_Q_GENERIC: unspecified quality failure + * + * The module should also set an extended error message with + * krb5_set_error_message(). The message may be localized according to one of + * the language tags in languages. + */ +typedef krb5_error_code +(*krb5_pwqual_check_fn)(krb5_context context, krb5_pwqual_moddata data, + const char *password, const char *policy_name, + krb5_principal princ, const char **languages); + +/* Optional: Release resources used by module data. */ +typedef void +(*krb5_pwqual_close_fn)(krb5_context context, krb5_pwqual_moddata data); + +/*** vtable declarations **/ + +/* Password quality plugin vtable for major version 1. */ +typedef struct krb5_pwqual_vtable_st { + krb5_pwqual_open_fn open; + krb5_pwqual_check_fn check; + krb5_pwqual_close_fn close; + /* Minor version 1 ends here. */ +} *krb5_pwqual_vtable; + +#endif /* KRB5_PWQUAL_PLUGIN_H */ diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et index a6086b111..5530ccafa 100644 --- a/src/lib/kadm5/kadm_err.et +++ b/src/lib/kadm5/kadm_err.et @@ -61,4 +61,5 @@ error_code KADM5_SETKEY3_ETYPE_MISMATCH, "Mismatched enctypes for setkey3" error_code KADM5_MISSING_KRB5_CONF_PARAMS, "Missing parameters in krb5.conf required for kadmin client" error_code KADM5_XDR_FAILURE, "XDR encoding error" error_code KADM5_CANT_RESOLVE, "Cannot resolve network address for admin server in requested realm" +error_code KADM5_PASS_Q_GENERIC, "Unspecified password quality failure" end diff --git a/src/lib/kadm5/server_internal.h b/src/lib/kadm5/server_internal.h index cc589fad2..076c18fc0 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,46 @@ 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 all available password quality plugin modules, bind each module to the + * realm's dictionary file, 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, + const char *dict_file); + +/* Release a handle list allocated by k5_pwqual_load. */ +void +k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles); + +/* Check a password using a password quality plugin module. */ +krb5_error_code +k5_pwqual_check(krb5_context context, pwqual_handle handle, + const char *password, const char *policy_name, + krb5_principal princ); + +/*** initvt functions for built-in password quality modules ***/ + +/* The dict module checks passwords against the realm's dictionary. */ +krb5_error_code +pwqual_dict_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +/* The empty module rejects empty passwords (even with no password policy). */ +krb5_error_code +pwqual_empty_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +/* The hesiod module checks passwords against GECOS fields from Hesiod passwd + * information (only if the tree was built with Hesiod support). */ +krb5_error_code +pwqual_hesiod_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +/* The princ module checks passwords against principal components. */ +krb5_error_code +pwqual_princ_initvt(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 c7e0fac9b..a513035d5 100644 --- a/src/lib/kadm5/srv/Makefile.in +++ b/src/lib/kadm5/srv/Makefile.in @@ -27,36 +27,48 @@ 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_empty.c \ + $(srcdir)/pwqual_hesiod.c \ + $(srcdir)/pwqual_princ.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_empty.$(OBJEXT) \ + pwqual_hesiod.$(OBJEXT) \ + pwqual_princ.$(OBJEXT) \ + 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_empty.o \ + pwqual_hesiod.o \ + pwqual_princ.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 6da95bd7c..345957a13 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 000000000..646bfcb3c --- /dev/null +++ b/src/lib/kadm5/srv/pwqual.c @@ -0,0 +1,115 @@ +/* -*- 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, + const char *dict_file) +{ + krb5_error_code ret; + krb5_plugin_initvt_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, initialize its vtable, and bind the + * dictionary filename. */ + 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) { /* Failed vtable init is non-fatal. */ + free(handle); + continue; + } + handle->data = NULL; + if (handle->vt.open != NULL) { + ret = handle->vt.open(context, dict_file, &handle->data); + if (ret != 0) /* Failed dictionary binding is fatal. */ + goto cleanup; + } + list[count++] = handle; + list[count] = NULL; + handle = NULL; + } + list[count] = NULL; + + *handles = list; + list = NULL; + +cleanup: + free(handle); + k5_plugin_free_modules(context, modules); + k5_pwqual_free_handles(context, list); + return ret; +} + +void +k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles) +{ + pwqual_handle *hp, handle; + + if (handles == NULL) + return; + for (hp = handles; *hp != NULL; hp++) { + handle = *hp; + if (handle->vt.close != NULL) + handle->vt.close(context, handle->data); + } + free(handles); +} + +krb5_error_code +k5_pwqual_check(krb5_context context, pwqual_handle handle, + const char *password, const char *policy_name, + krb5_principal princ) +{ + return handle->vt.check(context, handle->data, password, policy_name, + princ, NULL); +} diff --git a/src/lib/kadm5/srv/pwqual_dict.c b/src/lib/kadm5/srv/pwqual_dict.c new file mode 100644 index 000000000..2df9a8b94 --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_dict.c @@ -0,0 +1,254 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual_dict.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. + * + * Dictionary initialization and lookup code is (see top-level NOTICE file for + * license): + * + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * + * Password quality module to look up passwords within the realm dictionary. + */ + +#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, const char *policy_name, + krb5_principal princ, const char **languages) +{ + dict_moddata dict = (dict_moddata)data; + + /* Don't check the dictionary for principals with no password policy. */ + if (policy_name == 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; + + 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_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + 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_empty.c b/src/lib/kadm5/srv/pwqual_empty.c new file mode 100644 index 000000000..df3505aaf --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_empty.c @@ -0,0 +1,61 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual_empty.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 reject empty passwords. + */ + +#include "k5-platform.h" +#include <krb5/pwqual_plugin.h> +#include "server_internal.h" + +static krb5_error_code +empty_check(krb5_context context, krb5_pwqual_moddata data, + const char *password, const char *policy_name, + krb5_principal princ, const char **languages) +{ + /* Unlike other built-in modules, this one operates even for principals + * with no password policy. */ + if (*password == '\0') { + krb5_set_error_message(context, KADM5_PASS_Q_TOOSHORT, + "Empty passwords are not allowed"); + return KADM5_PASS_Q_TOOSHORT; + } + return 0; +} + +krb5_error_code +pwqual_empty_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_pwqual_vtable)vtable; + vt->check = empty_check; + return 0; +} diff --git a/src/lib/kadm5/srv/pwqual_hesiod.c b/src/lib/kadm5/srv/pwqual_hesiod.c new file mode 100644 index 000000000..993992d19 --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_hesiod.c @@ -0,0 +1,133 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual_hesiod.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 check passwords against GECOS fields of Hesiod + * passwd information, if the tree is compiled with Hesiod support. + */ + +#include "k5-platform.h" +#include <krb5/pwqual_plugin.h> +#include "server_internal.h" +#include <ctype.h> + +#ifdef HESIOD +#include <pwd.h> + +static char * +reverse(char *str, char *newstr, size_t newstr_size) +{ + char *p, *q; + size_t i; + + i = strlen(str); + if (i >= newstr_size) + i = newstr_size - 1; + p = str + i - 1; + q = newstr; + q[i] = '\0'; + for (; i > 0; i--) + *q++ = *p--; + + return newstr; +} + +static int +str_check_gecos(char *gecos, const char *pwstr) +{ + char *cp, *ncp, *tcp, revbuf[80]; + + 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, revbuf, sizeof(revbuf)); + if (!strcasecmp(pwstr, tcp)) + return 1; + cp = ncp; + } else + break; + } + return 0; +} +#endif /* HESIOD */ + +static krb5_error_code +hesiod_check(krb5_context context, krb5_pwqual_moddata data, + const char *password, const char *policy_name, + krb5_principal princ, const char **languages) +{ +#ifdef HESIOD + extern struct passwd *hes_getpwnam(); + struct passwd *ent; + int i, n; + const char *cp; + + /* Don't check for principals with no password policy. */ + if (policy_name == NULL) + return 0; + + n = krb5_princ_size(handle->context, princ); + for (i = 0; i < n; i++) { + ent = hes_getpwnam(cp); + if (ent && ent->pw_gecos && str_check_gecos(ent->pw_gecos, password)) { + krb5_set_error_message(context, KADM5_PASS_Q_DICT, + "Password maynot match user information."); + return KADM5_PASS_Q_DICT; + } + } +#endif /* HESIOD */ + return 0; +} + +krb5_error_code +pwqual_hesiod_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_pwqual_vtable)vtable; + vt->check = hesiod_check; + return 0; +} diff --git a/src/lib/kadm5/srv/pwqual_princ.c b/src/lib/kadm5/srv/pwqual_princ.c new file mode 100644 index 000000000..dfe5f2033 --- /dev/null +++ b/src/lib/kadm5/srv/pwqual_princ.c @@ -0,0 +1,75 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * lib/kadm5/srv/pwqual_princ.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 check passwords against principal components. + */ + +#include "k5-platform.h" +#include <krb5/pwqual_plugin.h> +#include "server_internal.h" + +static krb5_error_code +princ_check(krb5_context context, krb5_pwqual_moddata data, + const char *password, const char *policy_name, + krb5_principal princ, const char **languages) +{ + int i, n; + char *cp; + + /* Don't check for principals with no password policy. */ + if (policy_name == NULL) + return 0; + + /* 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) { + krb5_set_error_message(context, KADM5_PASS_Q_DICT, + "Password may not match principal name"); + return KADM5_PASS_Q_DICT; + } + } + + return 0; +} + +krb5_error_code +pwqual_princ_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_pwqual_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_pwqual_vtable)vtable; + vt->check = princ_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 81cc5f997..000000000 --- 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 557ef0ad4..9ebc13eea 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 1faeb86b1..93369f000 100644 --- a/src/lib/kadm5/srv/server_misc.c +++ b/src/lib/kadm5/srv/server_misc.c @@ -1,22 +1,38 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* + * 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. + * + * check_against_policy code is originally (see top-level NOTICE file for + * license): + * * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * - * $Header$ */ -#if !defined(lint) && !defined(__CODECENTER__) -static char *rcsid = "$Header$"; -#endif - #include "k5-int.h" #include <kdb.h> #include <ctype.h> #include <pwd.h> - -/* for strcasecmp */ -#include <string.h> - #include "server_internal.h" kadm5_ret_t @@ -37,147 +53,99 @@ 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; +kadm5_ret_t +init_pwqual(kadm5_server_handle_t handle) { - 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); + krb5_error_code ret; + pwqual_handle *list; + const char *dict_file = NULL; + + /* Register the built-in password quality modules. */ + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "dict", pwqual_dict_initvt); + if (ret != 0) + return ret; + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "empty", pwqual_empty_initvt); + if (ret != 0) + return ret; + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "hesiod", pwqual_hesiod_initvt); + if (ret != 0) + return ret; + ret = k5_plugin_register(handle->context, PLUGIN_INTERFACE_PWQUAL, + "princ", pwqual_princ_initvt); + if (ret != 0) + return ret; + + /* Load all available password quality modules. */ + if (handle->params.mask & KADM5_CONFIG_DICT_FILE) + dict_file = handle->params.dict_file; + ret = k5_pwqual_load(handle->context, &list, dict_file); + if (ret != 0) + return ret; + + handle->qual_handles = list; + return 0; } -#endif /* HESIOD */ -#if 0 -static int -lower(str) - char *str; +/* Check that a password meets the quality constraints given in pol. */ +static kadm5_ret_t +check_against_policy(kadm5_server_handle_t handle, const char *password, + kadm5_policy_ent_t pol) { - register char *cp; - int effect=0; - - for (cp = str; *cp; cp++) { - if (isupper(*cp)) { - *cp = tolower(*cp); - effect++; - } + int hasupper = 0, haslower = 0, hasdigit = 0, haspunct = 0, hasspec = 0; + int c, nclasses; + + /* Check against the policy's minimum length. */ + if (strlen(password) < (size_t)pol->pw_min_length) + return KADM5_PASS_Q_TOOSHORT; + + /* Check against the policy's minimum number of character classes. */ + while ((c = (unsigned char)*password++) != '\0') { + if (islower(c)) + haslower = 1; + else if (isupper(c)) + hasupper = 1; + else if (isdigit(c)) + hasdigit = 1; + else if (ispunct(c)) + haspunct = 1; + else + hasspec = 1; } - return(effect); + nclasses = hasupper + haslower + hasdigit + haspunct + hasspec; + if (nclasses < pol->pw_min_classes) + return KADM5_PASS_Q_CLASS; + return KADM5_OK; } -#endif -#ifdef HESIOD -static int -str_check_gecos(gecos, pwstr) - char *gecos; - char *pwstr; +/* Check a password against all available password quality plugin modules + * and against policy. */ +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; + const char *polname = (policy == NULL) ? NULL : policy->policy; + + if (policy != NULL) { + ret = check_against_policy(handle, password, policy); + if (ret != 0) + return ret; + } + for (h = handle->qual_handles; *h != NULL; h++) { + ret = k5_pwqual_check(handle->context, *h, password, polname, 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 - - 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; + 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 6b14d3ba6..dc1640643 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, diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 4f3081428..0737a2e53 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -353,7 +353,7 @@ T_PAC_OBJS= t_pac.o pac.o pac_sign.o copy_data.o T_PRINC_OBJS= t_princ.o parse.o unparse.o -T_ETYPES_OBJS= t_etypes.o init_ctx.o plugin.o etype_list.o +T_ETYPES_OBJS= t_etypes.o init_ctx.o etype_list.o plugin.o t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS) $(CC_LINK) -o t_walk_rtree $(T_WALK_RTREE_OBJS) $(KRB5_BASE_LIBS) diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c index d868f3319..277da2472 100644 --- a/src/lib/krb5/krb/plugin.c +++ b/src/lib/krb5/krb/plugin.c @@ -31,6 +31,7 @@ #include "k5-int.h" const char *interface_names[PLUGIN_NUM_INTERFACES] = { + "pwqual" }; /* Return the context's interface structure for id, or NULL if invalid. */ |