svn rev #24266: branches/plugins2/src/ include/krb5/ lib/kadm5/ lib/kadm5/srv/

ghudson@MIT.EDU ghudson at MIT.EDU
Sat Aug 28 18:39:40 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24266
Commit By: ghudson
Log Message:
Revise the password quality pluggable interface to match the project
page:

* Modules receive the policy name but not the policy object.
* Enforcement of password policy is out of the interface's scope.
* Built-in modules are: empty, dict, hesiod, princ.
* The consumer API loader takes care of open/close, so there is only
  a wrapper function for check.

The project page is at:
http://k5wiki.kerberos.org/wiki/Projects/Password_quality_pluggable_interface



Changed Files:
U   branches/plugins2/src/include/krb5/pwqual_plugin.h
U   branches/plugins2/src/lib/kadm5/server_internal.h
U   branches/plugins2/src/lib/kadm5/srv/Makefile.in
U   branches/plugins2/src/lib/kadm5/srv/pwqual.c
U   branches/plugins2/src/lib/kadm5/srv/pwqual_dict.c
A   branches/plugins2/src/lib/kadm5/srv/pwqual_empty.c
A   branches/plugins2/src/lib/kadm5/srv/pwqual_hesiod.c
D   branches/plugins2/src/lib/kadm5/srv/pwqual_policy.c
A   branches/plugins2/src/lib/kadm5/srv/pwqual_princ.c
U   branches/plugins2/src/lib/kadm5/srv/server_misc.c
Modified: branches/plugins2/src/include/krb5/pwqual_plugin.h
===================================================================
--- branches/plugins2/src/include/krb5/pwqual_plugin.h	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/include/krb5/pwqual_plugin.h	2010-08-28 22:39:40 UTC (rev 24266)
@@ -51,8 +51,6 @@
 
 #include <krb5/krb5.h>
 #include <krb5/plugin.h>
-#include <kadm5/admin.h>
-#include <kdb.h>
 
 /* An abstract type for password quality module data. */
 typedef struct krb5_pwqual_moddata_st *krb5_pwqual_moddata;
@@ -65,12 +63,14 @@
 (*krb5_pwqual_open_fn)(krb5_context context, const char *dict_file,
                        krb5_pwqual_moddata *data);
 
-/* Mandatory: Check a password for the principal princ, possibly making use
- * of the password policy given by policy.  Return an error if the password
- * check fails. */
+/*
+ * 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).  Return an error if the password check fails.
+ */
 typedef krb5_error_code
 (*krb5_pwqual_check_fn)(krb5_context context, krb5_pwqual_moddata data,
-                        const char *password, kadm5_policy_ent_t policy,
+                        const char *password, const char *policy_name,
                         krb5_principal princ);
 
 /* Optional: Release resources used by module data. */

Modified: branches/plugins2/src/lib/kadm5/server_internal.h
===================================================================
--- branches/plugins2/src/lib/kadm5/server_internal.h	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/lib/kadm5/server_internal.h	2010-08-28 22:39:40 UTC (rev 24266)
@@ -158,32 +158,23 @@
 
 /*** Password quality plugin consumer interface ***/
 
-/* Load the available password quality plugins and store the result into
- * *handles.  Free the result with k5_pwqual_free_handles. */
+/* 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);
+k5_pwqual_load(krb5_context context, pwqual_handle **handles,
+               const char *dict_file);
 
-/* Release a handle list allocated by k5_pwqual_load.  All modules must have
- * been closed by the caller. */
-krb5_error_code
+/* Release a handle list allocated by k5_pwqual_load. */
+void
 k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles);
 
-/* Initialize a password quality plugin, possibly using the realm's configured
- * dictionary filename. */
+/* Check a password using a password quality plugin module. */
 krb5_error_code
-k5_pwqual_open(krb5_context context, pwqual_handle handle,
-               const char *dict_file);
-
-/* Check a password using a password quality plugin. */
-krb5_error_code
 k5_pwqual_check(krb5_context context, pwqual_handle handle,
-                const char *password, kadm5_policy_ent_t policy,
+                const char *password, const char *policy_name,
                 krb5_principal princ);
 
-/* Release the memory used by a password quality plugin. */
-void
-k5_pwqual_close(krb5_context context, pwqual_handle handle);
-
 /*** initvt functions for built-in password quality modules ***/
 
 /* The dict module checks passwords against the realm's dictionary. */
@@ -191,9 +182,20 @@
 pwqual_dict_initvt(krb5_context context, int maj_ver, int min_ver,
                    krb5_plugin_vtable vtable);
 
-/* The policy module enforces password policy constraints. */
+/* The empty module rejects empty passwords (even with no password policy). */
 krb5_error_code
-pwqual_policy_initvt(krb5_context context, int maj_ver, int min_ver,
+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: branches/plugins2/src/lib/kadm5/srv/Makefile.in
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/Makefile.in	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/lib/kadm5/srv/Makefile.in	2010-08-28 22:39:40 UTC (rev 24266)
@@ -29,7 +29,9 @@
 
 SRCS =	$(srcdir)/pwqual.c \
 	$(srcdir)/pwqual_dict.c \
-	$(srcdir)/pwqual_policy.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 \
@@ -42,7 +44,9 @@
 
 OBJS =	pwqual.$(OBJEXT) \
 	pwqual_dict.$(OBJEXT) \
-	pwqual_policy.$(OBJECT) \
+	pwqual_empty.$(OBJEXT) \
+	pwqual_hesiod.$(OBJEXT) \
+	pwqual_princ.$(OBJEXT) \
 	svr_policy.$(OBJEXT) \
 	svr_principal.$(OBJEXT) \
 	server_acl.$(OBJEXT) \
@@ -56,7 +60,9 @@
 STLIBOBJS = \
 	pwqual.o \
 	pwqual_dict.o \
-	pwqual_policy.o \
+	pwqual_empty.o \
+	pwqual_hesiod.o \
+	pwqual_princ.o \
 	svr_policy.o \
 	svr_principal.o \
 	server_acl.o \

Modified: branches/plugins2/src/lib/kadm5/srv/pwqual.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/pwqual.c	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/lib/kadm5/srv/pwqual.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -25,7 +25,7 @@
  * or implied warranty.
  *
  *
- * Consumer interface for password quality plugins
+ * Consumer interface for password quality plugins.
  */
 
 #include "k5-int.h"
@@ -38,7 +38,8 @@
 };
 
 krb5_error_code
-k5_pwqual_load(krb5_context context, pwqual_handle **handles)
+k5_pwqual_load(krb5_context context, pwqual_handle **handles,
+               const char *dict_file)
 {
     krb5_error_code ret;
     krb5_plugin_initvt_fn *modules = NULL, *mod;
@@ -55,60 +56,60 @@
     if (list == NULL)
         goto cleanup;
 
-    /* For each module, allocate a handle and initialize its vtable.  Skip
-     * modules which don't successfully initialize. */
+    /* 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)
-            list[count++] = handle;
-        else
+        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;
 }
 
-krb5_error_code
+void
 k5_pwqual_free_handles(krb5_context context, pwqual_handle *handles)
 {
-    /* It's the caller's responsibility to close each handle, so all of the
-     * module data should be freed by now, leaving only the list itself. */
+    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_open(krb5_context context, pwqual_handle handle,
-               const char *dict_file)
-{
-    if (handle->data != NULL)
-        return EINVAL;
-    if (handle->vt.open == NULL)
-        return 0;
-    return handle->vt.open(context, dict_file, &handle->data);
-}
-
-krb5_error_code
 k5_pwqual_check(krb5_context context, pwqual_handle handle,
-                const char *password, kadm5_policy_ent_t policy,
+                const char *password, const char *policy_name,
                 krb5_principal princ)
 {
-    return handle->vt.check(context, handle->data, password, policy, princ);
+    return handle->vt.check(context, handle->data, password, policy_name,
+                            princ);
 }
-
-void
-k5_pwqual_close(krb5_context context, pwqual_handle handle)
-{
-    if (handle->vt.close)
-        handle->vt.close(context, handle->data);
-    handle->data = NULL;
-}

Modified: branches/plugins2/src/lib/kadm5/srv/pwqual_dict.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/pwqual_dict.c	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/lib/kadm5/srv/pwqual_dict.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -1,16 +1,38 @@
 /* -*- 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
  *
- * $Header$
+ *
+ * Password quality module to look up passwords within the realm dictionary.
  */
 
-/* Password quality module to look up paswords within the realm dictionary. */
-
-#if !defined(lint) && !defined(__CODECENTER__)
-static char *rcsid = "$Header$";
-#endif
-
 #include "k5-platform.h"
 #include <krb5/pwqual_plugin.h>
 #include <sys/types.h>
@@ -191,15 +213,13 @@
  * against the dictionary, as well as against principal components. */
 static krb5_error_code
 dict_check(krb5_context context, krb5_pwqual_moddata data,
-           const char *password, kadm5_policy_ent_t policy,
+           const char *password, const char *policy_name,
            krb5_principal princ)
 {
     dict_moddata dict = (dict_moddata)data;
-    int i, n;
-    char *cp;
 
     /* Don't check the dictionary for principals with no password policy. */
-    if (policy == NULL)
+    if (policy_name == NULL)
         return 0;
 
     /* Check against words in the dictionary if we successfully loaded one. */
@@ -208,16 +228,6 @@
                 word_compare) != NULL)
         return KADM5_PASS_Q_DICT;
 
-    /* Check against components of the principal. */
-    n = krb5_princ_size(handle->context, princ);
-    cp = krb5_princ_realm(handle->context, princ)->data;
-    if (strcasecmp(cp, password) == 0)
-        return KADM5_PASS_Q_DICT;
-    for (i = 0; i < n; i++) {
-        cp = krb5_princ_component(handle->context, princ, i)->data;
-        if (strcasecmp(cp, password) == 0)
-            return KADM5_PASS_Q_DICT;
-    }
     return 0;
 }
 

Added: branches/plugins2/src/lib/kadm5/srv/pwqual_empty.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/pwqual_empty.c	                        (rev 0)
+++ branches/plugins2/src/lib/kadm5/srv/pwqual_empty.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -0,0 +1,58 @@
+/* -*- 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)
+{
+    /* Unlike other built-in modules, this one operates even for principals
+     * with no password policy. */
+    if (*password == '\0')
+        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;
+}

Added: branches/plugins2/src/lib/kadm5/srv/pwqual_hesiod.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/pwqual_hesiod.c	                        (rev 0)
+++ branches/plugins2/src/lib/kadm5/srv/pwqual_hesiod.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -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)
+{
+#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++) {
+        cp = krb5_princ_component(handle->context, princ, i)->data;
+        if (strcasecmp(cp, password) == 0)
+            return KADM5_PASS_Q_DICT;
+        ent = hes_getpwnam(cp);
+        if (ent && ent->pw_gecos && str_check_gecos(ent->pw_gecos, password))
+            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;
+}

Added: branches/plugins2/src/lib/kadm5/srv/pwqual_princ.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/pwqual_princ.c	                        (rev 0)
+++ branches/plugins2/src/lib/kadm5/srv/pwqual_princ.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -0,0 +1,72 @@
+/* -*- 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)
+{
+    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)
+            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: branches/plugins2/src/lib/kadm5/srv/server_misc.c
===================================================================
--- branches/plugins2/src/lib/kadm5/srv/server_misc.c	2010-08-28 20:20:14 UTC (rev 24265)
+++ branches/plugins2/src/lib/kadm5/srv/server_misc.c	2010-08-28 22:39:40 UTC (rev 24266)
@@ -1,14 +1,34 @@
 /* -*- 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>
@@ -37,51 +57,86 @@
 init_pwqual(kadm5_server_handle_t handle)
 {
     krb5_error_code ret;
-    pwqual_handle *list, *h;
+    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,
-                             "policy", pwqual_policy_initvt);
+                             "empty", pwqual_empty_initvt);
     if (ret != 0)
         return ret;
-
-    ret = k5_pwqual_load(handle->context, &list);
+    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;
 
-    for (h = list; *h != NULL; h++) {
-        ret = k5_pwqual_open(handle->context, *h, dict_file);
-        if (ret != 0) {
-            /* Close any previously opened modules and error out. */
-            for (; h > list; h--)
-                k5_pwqual_close(handle->context, *(h - 1));
-            k5_pwqual_free_handles(handle->context, list);
-            return ret;
-        }
-    }
-
     handle->qual_handles = list;
     return 0;
 }
 
-/* Check a password against all available password quality plugin modules. */
+/* 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)
+{
+    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;
+    }
+    nclasses = hasupper + haslower + hasdigit + haspunct + hasspec;
+    if (nclasses < pol->pw_min_classes)
+        return KADM5_PASS_Q_CLASS;
+    return KADM5_OK;
+}
+
+/* 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)
 {
     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, policy, princ);
+        ret = k5_pwqual_check(handle->context, *h, password, polname, princ);
         if (ret != 0)
             return ret;
     }
@@ -91,10 +146,6 @@
 void
 destroy_pwqual(kadm5_server_handle_t handle)
 {
-    pwqual_handle *h;
-
-    for (h = handle->qual_handles; *h != NULL; h++)
-        k5_pwqual_close(handle->context, *h);
     k5_pwqual_free_handles(handle->context, handle->qual_handles);
     handle->qual_handles = NULL;
 }




More information about the cvs-krb5 mailing list