svn rev #24284: trunk/ doc/ src/config-files/ src/include/ src/include/krb5/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Wed Sep 1 12:40:22 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24284
Commit By: ghudson
Log Message:
ticket: 6765
subject: 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



Changed Files:
U   trunk/doc/admin.texinfo
U   trunk/doc/krb5conf.texinfo
A   trunk/pwqual_combo/
U   trunk/src/config-files/krb5.conf.M
U   trunk/src/include/Makefile.in
U   trunk/src/include/k5-int.h
A   trunk/src/include/krb5/pwqual_plugin.h
U   trunk/src/lib/kadm5/kadm_err.et
U   trunk/src/lib/kadm5/server_internal.h
U   trunk/src/lib/kadm5/srv/Makefile.in
U   trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports
A   trunk/src/lib/kadm5/srv/pwqual.c
A   trunk/src/lib/kadm5/srv/pwqual_dict.c
A   trunk/src/lib/kadm5/srv/pwqual_empty.c
A   trunk/src/lib/kadm5/srv/pwqual_hesiod.c
A   trunk/src/lib/kadm5/srv/pwqual_princ.c
D   trunk/src/lib/kadm5/srv/server_dict.c
U   trunk/src/lib/kadm5/srv/server_init.c
U   trunk/src/lib/kadm5/srv/server_misc.c
U   trunk/src/lib/kadm5/srv/svr_principal.c
U   trunk/src/lib/krb5/krb/Makefile.in
U   trunk/src/lib/krb5/krb/plugin.c
Modified: trunk/doc/admin.texinfo
===================================================================
--- trunk/doc/admin.texinfo	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/doc/admin.texinfo	2010-09-01 16:40:22 UTC (rev 24284)
@@ -410,6 +410,7 @@
 * capaths::                     
 * dbdefaults::                  
 * dbmodules::                   
+* plugins::
 * pkinit client options::
 * Sample krb5.conf File::       
 @end menu
@@ -1042,7 +1043,7 @@
 This LDAP specific tag indicates the number of connections to be maintained per LDAP server. This value is used if the number of connections per LDAP server are not mentioned in the configuration section under [dbmodules]. The default value is 5.
 @end table
 
- at node dbmodules, pkinit client options, dbdefaults, krb5.conf
+ at node dbmodules, plugins, dbdefaults, krb5.conf
 @subsection [dbmodules]
 
 Contains database specific parameters used by the database library. Each tag in the [dbmodules] section of the file names a configuration section for database specific parameters that can be referred to by a realm. The value of the tag is a subsection where the relations in that subsection define the database specific parameters.
@@ -1090,7 +1091,65 @@
 
 @end table
 
- at node pkinit client options, Sample krb5.conf File, dbmodules, krb5.conf
+ at node plugins, pkinit client options, dbmodules, krb5.conf
+
+ at menu
+* pwqual interface::             
+ at end menu
+
+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.
+
+Each pluggable interface corresponds to a subsection of [plugins].
+All subsections support the same tags:
+
+ at table @b
+ at itemx 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.
+
+ at itemx 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.
+
+ at itemx 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.
+ at end table
+
+The following subsections are currently supported within the [plugins]
+section:
+
+ at node pwqual interface, , plugins, plugins
+
+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):
+
+ at table @b
+ at itemx dict
+Checks against the realm dictionary file
+
+ at itemx empty
+Rejects empty passwords
+
+ at itemx hesiod
+Checks against user information stored in Hesiod (only if Kerberos was
+built with Hesiod support)
+
+ at itemx princ
+Checks against components of the principal name
+ at end table
+
+ at node pkinit client options, Sample krb5.conf File, plugins, krb5.conf
 @subsection pkinit options
 
 @menu

Modified: trunk/doc/krb5conf.texinfo
===================================================================
--- trunk/doc/krb5conf.texinfo	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/doc/krb5conf.texinfo	2010-09-01 16:40:22 UTC (rev 24284)
@@ -89,6 +89,10 @@
 cross-realm authentication.  It is also used by the end-service when
 checking the transited field for trusted intermediate realms.
 
+ at itemx plugins
+Contains tags to register dynamic plugin modules and to turn modules on
+and off.
+
 @ignore
 this doesn't seem to be used
 @itemx kdc

Modified: trunk/src/config-files/krb5.conf.M
===================================================================
--- trunk/src/config-files/krb5.conf.M	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/config-files/krb5.conf.M	2010-09-01 16:40:22 UTC (rev 24284)
@@ -110,6 +110,9 @@
 
 .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 @@
 .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

Modified: trunk/src/include/Makefile.in
===================================================================
--- trunk/src/include/Makefile.in	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/include/Makefile.in	2010-09-01 16:40:22 UTC (rev 24284)
@@ -138,6 +138,7 @@
 	$(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
 

Modified: trunk/src/include/k5-int.h
===================================================================
--- trunk/src/include/k5-int.h	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/include/k5-int.h	2010-09-01 16:40:22 UTC (rev 24284)
@@ -1516,7 +1516,8 @@
 
 /* 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. */

Copied: trunk/src/include/krb5/pwqual_plugin.h (from rev 24283, branches/plugins2/src/include/krb5/pwqual_plugin.h)
===================================================================
--- trunk/src/include/krb5/pwqual_plugin.h	                        (rev 0)
+++ trunk/src/include/krb5/pwqual_plugin.h	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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 */

Modified: trunk/src/lib/kadm5/kadm_err.et
===================================================================
--- trunk/src/lib/kadm5/kadm_err.et	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/kadm_err.et	2010-09-01 16:40:22 UTC (rev 24284)
@@ -61,4 +61,5 @@
 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

Modified: trunk/src/lib/kadm5/server_internal.h
===================================================================
--- trunk/src/lib/kadm5/server_internal.h	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/server_internal.h	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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 @@
     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 @@
 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 @@
                                    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 @@
 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__ */

Modified: trunk/src/lib/kadm5/srv/Makefile.in
===================================================================
--- trunk/src/lib/kadm5/srv/Makefile.in	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/srv/Makefile.in	2010-09-01 16:40:22 UTC (rev 24284)
@@ -27,36 +27,48 @@
 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

Modified: trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports
===================================================================
--- trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports	2010-09-01 16:40:22 UTC (rev 24284)
@@ -7,10 +7,7 @@
 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

Copied: trunk/src/lib/kadm5/srv/pwqual.c (from rev 24283, branches/plugins2/src/lib/kadm5/srv/pwqual.c)
===================================================================
--- trunk/src/lib/kadm5/srv/pwqual.c	                        (rev 0)
+++ trunk/src/lib/kadm5/srv/pwqual.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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);
+}

Copied: trunk/src/lib/kadm5/srv/pwqual_dict.c (from rev 24283, branches/plugins2/src/lib/kadm5/srv/pwqual_dict.c)
===================================================================
--- trunk/src/lib/kadm5/srv/pwqual_dict.c	                        (rev 0)
+++ trunk/src/lib/kadm5/srv/pwqual_dict.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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;
+}

Copied: trunk/src/lib/kadm5/srv/pwqual_empty.c (from rev 24283, branches/plugins2/src/lib/kadm5/srv/pwqual_empty.c)
===================================================================
--- trunk/src/lib/kadm5/srv/pwqual_empty.c	                        (rev 0)
+++ trunk/src/lib/kadm5/srv/pwqual_empty.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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;
+}

Copied: trunk/src/lib/kadm5/srv/pwqual_hesiod.c (from rev 24283, branches/plugins2/src/lib/kadm5/srv/pwqual_hesiod.c)
===================================================================
--- trunk/src/lib/kadm5/srv/pwqual_hesiod.c	                        (rev 0)
+++ trunk/src/lib/kadm5/srv/pwqual_hesiod.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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;
+}

Copied: trunk/src/lib/kadm5/srv/pwqual_princ.c (from rev 24283, branches/plugins2/src/lib/kadm5/srv/pwqual_princ.c)
===================================================================
--- trunk/src/lib/kadm5/srv/pwqual_princ.c	                        (rev 0)
+++ trunk/src/lib/kadm5/srv/pwqual_princ.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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;
+}

Modified: trunk/src/lib/kadm5/srv/server_init.c
===================================================================
--- trunk/src/lib/kadm5/srv/server_init.c	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/srv/server_init.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -317,7 +317,7 @@
         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 @@
 
     CHECK_HANDLE(server_handle);
 
-    destroy_dict();
+    destroy_pwqual(handle);
 
     adb_policy_close(handle);
     krb5_db_fini(handle->context);

Modified: trunk/src/lib/kadm5/srv/server_misc.c
===================================================================
--- trunk/src/lib/kadm5/srv/server_misc.c	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/srv/server_misc.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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 @@
     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;
+    krb5_error_code ret;
+    pwqual_handle *list;
+    const char *dict_file = NULL;
 
-    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--;
+    /* 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;
 
-    return(newstr);
+    /* 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;
+    int hasupper = 0, haslower = 0, hasdigit = 0, haspunct = 0, hasspec = 0;
+    int c, nclasses;
 
-    for (cp = str; *cp; cp++) {
-        if (isupper(*cp)) {
-            *cp = tolower(*cp);
-            effect++;
-        }
+    /* 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;
+    krb5_error_code ret;
+    pwqual_handle *h;
+    const char *polname = (policy == NULL) ? NULL : policy->policy;
 
-    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;
+    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;
 }

Modified: trunk/src/lib/kadm5/srv/svr_principal.c
===================================================================
--- trunk/src/lib/kadm5/srv/svr_principal.c	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/kadm5/srv/svr_principal.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -292,7 +292,7 @@
         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 @@
         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,

Modified: trunk/src/lib/krb5/krb/Makefile.in
===================================================================
--- trunk/src/lib/krb5/krb/Makefile.in	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/krb5/krb/Makefile.in	2010-09-01 16:40:22 UTC (rev 24284)
@@ -353,7 +353,7 @@
 
 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)

Modified: trunk/src/lib/krb5/krb/plugin.c
===================================================================
--- trunk/src/lib/krb5/krb/plugin.c	2010-09-01 16:00:56 UTC (rev 24283)
+++ trunk/src/lib/krb5/krb/plugin.c	2010-09-01 16:40:22 UTC (rev 24284)
@@ -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. */




More information about the cvs-krb5 mailing list