svn rev #24970: trunk/src/ include/ include/krb5/ kdc/ lib/krb5/ lib/krb5/krb/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Fri Jun 17 09:44:34 EDT 2011


http://src.mit.edu/fisheye/changelog/krb5/?cs=24970
Commit By: ghudson
Log Message:
ticket: 6921
subject: Convert preauth_plugin.h to new plugin framework

The preauth plugin interface was introduced in 1.6 but was never made
a public API.  In preparation for making it public in 1.10, convert it
to use the new plugin framework.  This will require changes to any
existing preauth plugins.

A number of symbols were renamed for namespace cleanliness, and
abstract types were introduced for module data and module per-request
data for better type safety.

On the consumer end (preauth2.c and kdc_preauth.c), this is a pretty
rough conversion.  Eventually we should create proper consumer APIs
with module handles, and the flat lists of preauth types should hold
pointers to module handles rather than copies of the vtables.  The
built-in preauth type handlers should then be converted to built-in
module providers linked into the consumer code (as should encrypted
challenge, since it has no external dependencies).  None of this will
impact the provider API for preauth plugins, so it can wait.


Changed Files:
U   trunk/src/include/k5-int.h
U   trunk/src/include/krb5/preauth_plugin.h
U   trunk/src/kdc/do_as_req.c
U   trunk/src/kdc/kdc_preauth.c
U   trunk/src/kdc/kdc_util.h
U   trunk/src/lib/krb5/krb/copy_ctx.c
U   trunk/src/lib/krb5/krb/get_in_tkt.c
U   trunk/src/lib/krb5/krb/gic_opt_set_pa.c
U   trunk/src/lib/krb5/krb/init_creds_ctx.h
U   trunk/src/lib/krb5/krb/plugin.c
U   trunk/src/lib/krb5/krb/preauth2.c
U   trunk/src/lib/krb5/libkrb5.exports
U   trunk/src/lib/krb5/os/init_os_ctx.c
U   trunk/src/plugins/preauth/cksum_body/cksum_body.exports
U   trunk/src/plugins/preauth/cksum_body/cksum_body_main.c
U   trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports
U   trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c
U   trunk/src/plugins/preauth/fast_factor.h
U   trunk/src/plugins/preauth/pkinit/pkinit.exports
U   trunk/src/plugins/preauth/pkinit/pkinit_clnt.c
U   trunk/src/plugins/preauth/pkinit/pkinit_srv.c
U   trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c
U   trunk/src/plugins/preauth/wpse/wpse.exports
U   trunk/src/plugins/preauth/wpse/wpse_main.c
U   trunk/src/tests/dejagnu/Makefile.in
U   trunk/src/tests/dejagnu/config/default.exp
U   trunk/src/tests/dejagnu/krb-standalone/standalone.exp
U   trunk/src/util/k5test.py
Modified: trunk/src/include/k5-int.h
===================================================================
--- trunk/src/include/k5-int.h	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/include/k5-int.h	2011-06-17 13:44:33 UTC (rev 24970)
@@ -809,49 +809,12 @@
  * expanded in the future as new types of requests are defined which
  * may require other things to be passed through. */
 struct krb5int_fast_request_state;
-typedef struct _krb5_preauth_client_rock {
-    krb5_magic      magic;
+struct krb5_clpreauth_rock_st {
+    krb5_magic magic;
     krb5_enctype *etype;
     struct krb5int_fast_request_state *fast_state;
-} krb5_preauth_client_rock;
+};
 
-/* This structure lets us keep track of all of the modules which are loaded,
- * turning the list of modules and their lists of implemented preauth types
- * into a single list which we can walk easily. */
-typedef struct _krb5_preauth_context {
-    int n_modules;
-    struct _krb5_preauth_context_module {
-        /* Which of the possibly more than one preauth types which the
-         * module supports we're using at this point in the list. */
-        krb5_preauthtype pa_type;
-        /* Encryption types which the client claims to support -- we
-         * copy them directly into the krb5_kdc_req structure during
-         * krb5_preauth_prepare_request(). */
-        krb5_enctype *enctypes;
-        /* The plugin's per-plugin context and a function to clear it. */
-        void *plugin_context;
-        preauth_client_plugin_fini_proc client_fini;
-        /* The module's table, and some of its members, copied here for
-         * convenience when we populated the list. */
-        struct krb5plugin_preauth_client_ftable_v1 *ftable;
-        const char *name;
-        int flags, use_count;
-        preauth_client_process_proc client_process;
-        preauth_client_tryagain_proc client_tryagain;
-        preauth_client_supply_gic_opts_proc client_supply_gic_opts;
-        preauth_client_request_init_proc client_req_init;
-        preauth_client_request_fini_proc client_req_fini;
-        /* The per-request context which the client_req_init() function
-         * might allocate, which we'll need to clean up later by
-         * calling the client_req_fini() function. */
-        void *request_context;
-        /* A pointer to the request_context pointer.  All modules within
-         * a plugin will point at the request_context of the first
-         * module within the plugin. */
-        void **request_context_pp;
-    } *modules;
-} krb5_preauth_context;
-
 typedef struct _krb5_pa_enc_ts {
     krb5_timestamp      patimestamp;
     krb5_int32          pausec;
@@ -1121,7 +1084,7 @@
                 krb5_data *s2kparams, krb5_enctype *etype,
                 krb5_keyblock *as_key, krb5_prompter_fct prompter,
                 void *prompter_data, krb5_gic_get_as_key_fct gak_fct,
-                void *gak_data, krb5_preauth_client_rock *get_data_rock,
+                void *gak_data, krb5_clpreauth_rock preauth_rock,
                 krb5_gic_opt_ext *opte);
 
 krb5_error_code KRB5_CALLCONV
@@ -1134,7 +1097,7 @@
                          krb5_enctype *etype, krb5_keyblock *as_key,
                          krb5_prompter_fct prompter, void *prompter_data,
                          krb5_gic_get_as_key_fct gak_fct, void *gak_data,
-                         krb5_preauth_client_rock *get_data_rock,
+                         krb5_clpreauth_rock preauth_rock,
                          krb5_gic_opt_ext *opte);
 
 void KRB5_CALLCONV krb5_init_preauth_context(krb5_context);
@@ -1411,9 +1374,11 @@
 
 /* A list of plugin interface IDs.  Make sure to increment
  * PLUGIN_NUM_INTERFACES when a new interface is added. */
-#define PLUGIN_INTERFACE_PWQUAL 0
-#define PLUGIN_INTERFACE_KADM5_HOOK 1
-#define PLUGIN_NUM_INTERFACES   2
+#define PLUGIN_INTERFACE_PWQUAL      0
+#define PLUGIN_INTERFACE_KADM5_HOOK  1
+#define PLUGIN_INTERFACE_CLPREAUTH   2
+#define PLUGIN_INTERFACE_KDCPREAUTH  3
+#define PLUGIN_NUM_INTERFACES        4
 
 /* Retrieve the plugin module of type interface_id and name modname,
  * storing the result into module. */
@@ -1452,6 +1417,7 @@
 struct _kdb5_dal_handle;        /* private, in kdb5.h */
 typedef struct _kdb5_dal_handle kdb5_dal_handle;
 struct _kdb_log_context;
+typedef struct krb5_preauth_context_st krb5_preauth_context;
 struct _krb5_context {
     krb5_magic      magic;
     krb5_enctype    *in_tkt_etypes;
@@ -1490,7 +1456,6 @@
     void (**locate_fptrs)(void);
 
     /* preauth module stuff */
-    struct plugin_dir_handle preauth_plugins;
     krb5_preauth_context *preauth_context;
 
     /* error detail info */

Modified: trunk/src/include/krb5/preauth_plugin.h
===================================================================
--- trunk/src/include/krb5/preauth_plugin.h	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/include/krb5/preauth_plugin.h	2011-06-17 13:44:33 UTC (rev 24970)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
  * Copyright (c) 2006 Red Hat, Inc.
- * Portions copyright (c) 2006 Massachusetts Institute of Technology
+ * Portions copyright (c) 2006, 2011 Massachusetts Institute of Technology
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,22 +30,52 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* Preauthentication plugin definitions for Kerberos 5 */
+/*
+ * Declarations for preauth plugin module implementors.
+ *
+ * This header defines two preauth interfaces, clpreauth and kdcpreauth.  A
+ * shared object can implement both interfaces or it can implement just one.
+ *
+ *
+ * The clpreauth interface has a single supported major version, which is
+ * 1.  Major version 1 has a current minor version of 1.  clpreauth modules
+ * should define a function named clpreauth_<modulename>_initvt, matching
+ * the signature:
+ *
+ *   krb5_error_code
+ *   clpreauth_modname_initvt(krb5_context context, int maj_ver,
+ *                            int min_ver, krb5_plugin_vtable vtable);
+ *
+ * The kdcpreauth interface has a single supported major version, which is 1.
+ * Major version 1 has a current minor version of 1.  kdcpreauth modules should
+ * define a function named kdcpreauth_<modulename>_initvt, matching the
+ * signature:
+ *
+ *   krb5_error_code
+ *   kdcpreauth_modname_initvt(krb5_context context, int maj_ver, int min_ver,
+ *                             krb5_plugin_vtable vtable);
+ *
+ * For both interfaces, 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 the interface and maj_ver:
+ *     clpreauth, maj_ver == 1:  Cast to krb5_clpreauth_vtable
+ *     kdcpreauth, maj_ver == 1: Cast to krb5_kdcpreauth_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_PREAUTH_PLUGIN_H_INCLUDED
 #define KRB5_PREAUTH_PLUGIN_H_INCLUDED
 #include <krb5/krb5.h>
+#include <krb5/plugin.h>
 
 /*
- * While arguments of these types are passed-in, for the most part a preauth
- * module can treat them as opaque.  If we need keying data, we can ask for
- * it directly.
- */
-struct _krb5_db_entry_new;
-struct _krb5_key_data;
-struct _krb5_preauth_client_rock;
-
-/*
  * Preauth mechanism property flags, unified from previous definitions in the
  * KDC and libkrb5 sources.
  */
@@ -58,452 +88,398 @@
  * REAL mechanism callbacks (client-only). */
 #define PA_INFO         0x00000002
 
-/* Causes the KDC to include this mechanism in a list of supported preauth
+/*
+ * Causes the KDC to include this mechanism in a list of supported preauth
  * types if the user's DB entry flags the user as requiring hardware-based
- * preauthentication (server-only). */
+ * preauthentication (KDC-only).
+ */
 #define PA_HARDWARE     0x00000004
 
-/* Causes the KDC to include this mechanism in a list of supported preauth
+/*
+ * Causes the KDC to include this mechanism in a list of supported preauth
  * types if the user's DB entry flags the user as requiring preauthentication,
  * and to fail preauthentication if we can't verify the client data.  The
- * flipside of PA_SUFFICIENT (server-only). */
+ * flipside of PA_SUFFICIENT (KDC-only).
+ */
 #define PA_REQUIRED     0x00000008
 
-/* Causes the KDC to include this mechanism in a list of supported preauth
+/*
+ * Causes the KDC to include this mechanism in a list of supported preauth
  * types if the user's DB entry flags the user as requiring preauthentication,
  * and to mark preauthentication as successful if we can verify the client
- * data.  The flipside of PA_REQUIRED (server-only). */
+ * data.  The flipside of PA_REQUIRED (KDC-only).
+ */
 #define PA_SUFFICIENT   0x00000010
 
-/* Marks this preauthentication mechanism as one which changes the key which is
+/*
+ * Marks this preauthentication mechanism as one which changes the key which is
  * used for encrypting the response to the client.  Modules which have this
- * flag have their server_return_proc called before modules which do not, and
- * are passed over if a previously-called module has modified the encrypting
- * key (server-only). */
+ * flag have their server_return_fn called before modules which do not, and are
+ * passed over if a previously-called module has modified the encrypting key
+ * (KDC-only).
+ */
 #define PA_REPLACES_KEY 0x00000020
 
-/* Causes the KDC to check with this preauthentication module even if the
- * client has no entry in the realm database.  If the module returns a success
- * code, continue processing and assume that its return_padata callback will
- * supply us with a key for encrypting the AS reply (server-only). */
-/* #define PA_VIRTUAL   (0x00000040 | PA_REPLACES_KEY) */
-
-/* Not really a padata type, so don't include it in any list of preauth types
- * which gets sent over the wire. */
+/*
+ * Not really a padata type, so don't include it in any list of preauth types
+ * which gets sent over the wire.
+ */
 #define PA_PSEUDO       0x00000080
 
 
-/***************************************************************************
- *
- * Client-side preauthentication plugin interface definition.
- *
- ***************************************************************************/
+/*
+ * clpreauth plugin interface definition.
+ */
 
+/* Abstract type for a client request information handle. */
+typedef struct krb5_clpreauth_rock_st *krb5_clpreauth_rock;
+
+/* Abstract types for module data and per-request module data. */
+typedef struct krb5_clpreauth_moddata_st *krb5_clpreauth_moddata;
+typedef struct krb5_clpreauth_modreq_st *krb5_clpreauth_modreq;
+
 /*
- * A callback which will obtain the user's long-term AS key by prompting the
- * user for the password, then salting it properly, and so on.  For the moment,
- * it's identical to the get_as_key callback used inside of libkrb5, but we
- * define a new typedef here instead of making the existing one public to
- * isolate ourselves from potential future changes.
+ * Provided by krb5: a callback which will obtain the user's long-term AS key
+ * by prompting the user for the password, then salting it properly, and so on.
+ * For the moment, it's identical to the get_as_key callback used inside of
+ * libkrb5, but we define a new typedef here instead of making the existing one
+ * public to isolate ourselves from potential future changes.
  */
 typedef krb5_error_code
-(*preauth_get_as_key_proc)(krb5_context,
-                           krb5_principal,
-                           krb5_enctype,
-                           krb5_prompter_fct,
-                           void *prompter_data,
-                           krb5_data *salt,
-                           krb5_data *s2kparams,
-                           krb5_keyblock *as_key,
-                           void *gak_data);
+(*krb5_clpreauth_get_as_key_fn)(krb5_context context,
+                                krb5_principal princ,
+                                krb5_enctype enctype,
+                                krb5_prompter_fct prompter,
+                                void *prompter_data,
+                                krb5_data *salt,
+                                krb5_data *s2kparams,
+                                krb5_keyblock *as_key,
+                                void *gak_data);
 
 /*
- * A client module's callback functions are allowed to request various
- * information to enable it to process a request.
+ * Provided by krb5: a client module's callback functions are allowed to
+ * request various information to enable it to process a request.
  */
-enum krb5plugin_preauth_client_request_type {
-    /* The returned krb5_data item holds the enctype expected to be  used to encrypt the
-     * encrypted portion of the AS_REP packet. When handling a
-     * PREAUTH_REQUIRED error, this typically comes from etype-info2.
-     * When handling an AS reply, it is initialized from the AS reply itself.*/
-    krb5plugin_preauth_client_get_etype = 1,
-    /* Free the data returned from krb5plugin_preauth_client_req_get_etype */
-    krb5plugin_preauth_client_free_etype = 2,
-    /* The returned krb5_data contains the FAST armor key in a
-     * krb5_keyblock.  Returns success with a NULL data item in the
-     * krb5_data if the client library supports FAST but is not using it.*/
-    krb5plugin_preauth_client_fast_armor = 3,
-    /* Frees return from KRB5PLUGIN_PREAUTH_CLIENT_FAST_ARMOR.  It is
-     * acceptable to set data to NULL and free the keyblock using
-     * krb5_free_keyblock; in that case, this frees the krb5_data
-     * only.*/
-    krb5plugin_preauth_client_free_fast_armor = 4
+enum krb5_clpreauth_request_type {
+    /*
+     * The returned krb5_data item holds the enctype expected to be used to
+     * encrypt the encrypted portion of the AS_REP packet. When handling a
+     * PREAUTH_REQUIRED error, this typically comes from etype-info2.  When
+     * handling an AS reply, it is initialized from the AS reply itself.
+     */
+    krb5_clpreauth_get_etype = 1,
+
+    /* Free the data returned from krb5plugin_clpreauth_req_get_etype */
+    krb5_clpreauth_free_etype = 2,
+
+    /*
+     * The returned krb5_data contains the FAST armor key in a krb5_keyblock.
+     * Returns success with a NULL data item in the krb5_data if the client
+     * library supports FAST but is not using it.
+     */
+    krb5_clpreauth_fast_armor = 3,
+
+    /*
+     * Frees return from KRB5PLUGIN_CLPREAUTH_FAST_ARMOR.  It is
+     * acceptable to set data->data to NULL and free the keyblock using
+     * krb5_free_keyblock; in that case, this frees the krb5_data only.
+     */
+    krb5_clpreauth_free_fast_armor = 4
 };
 typedef krb5_error_code
-(*preauth_get_client_data_proc)(krb5_context,
-                                struct _krb5_preauth_client_rock *,
-                                krb5_int32 request_type,
-                                krb5_data **);
+(*krb5_clpreauth_get_data_fn)(krb5_context context,
+                              krb5_clpreauth_rock rock,
+                              krb5_int32 request_type, krb5_data **data);
 
-/* Per-plugin initialization/cleanup.  The init function is called
- * by libkrb5 when the plugin is loaded, and the fini function is
- * called before the plugin is unloaded.  Both are optional and
- * may be called multiple times in case the plugin is used in
- * multiple contexts.  The returned context lives the lifetime of
- * the krb5_context */
+/*
+ * Optional: per-plugin initialization/cleanup.  The init function is called by
+ * libkrb5 when the plugin is loaded, and the fini function is called before
+ * the plugin is unloaded.  These may be called multiple times in case the
+ * plugin is used in multiple contexts.  The returned context lives the
+ * lifetime of the krb5_context.
+ */
 typedef krb5_error_code
-(*preauth_client_plugin_init_proc)(krb5_context context,
-                                   void **plugin_context);
+(*krb5_clpreauth_init_fn)(krb5_context context,
+                          krb5_clpreauth_moddata *moddata_out);
 typedef void
-(*preauth_client_plugin_fini_proc)(krb5_context context,
-                                   void *plugin_context);
+(*krb5_clpreauth_fini_fn)(krb5_context context,
+                          krb5_clpreauth_moddata moddata);
 
-/* A callback which returns flags indicating if the module is a "real" or
- * an "info" mechanism, and so on.  This function is called for each entry
- * in the client_pa_type_list. */
+/*
+ * Mandatory: Return flags indicating if the module is a "real" or an "info"
+ * mechanism, and so on.  This function is called for each entry in the
+ * client_pa_type_list.
+ */
 typedef int
-(*preauth_client_get_flags_proc)(krb5_context context,
-                                 krb5_preauthtype pa_type);
+(*krb5_clpreauth_get_flags_fn)(krb5_context context, krb5_preauthtype pa_type);
 
-/* Per-request initialization/cleanup.  The request_init function is
+/*
+ * Optional: per-request initialization/cleanup.  The request_init function is
  * called when beginning to process a get_init_creds request and the
- * request_fini function is called when processing of the request is
- * complete.  This is optional.  It may be called multiple times in
- * the lifetime of a krb5_context. */
+ * request_fini function is called when processing of the request is complete.
+ * This is optional.  It may be called multiple times in the lifetime of a
+ * krb5_context.
+ */
 typedef void
-(*preauth_client_request_init_proc)(krb5_context context,
-                                    void *plugin_context,
-                                    void **request_context);
+(*krb5_clpreauth_request_init_fn)(krb5_context context,
+                                  krb5_clpreauth_moddata moddata,
+                                  krb5_clpreauth_modreq *modreq_out);
 typedef void
-(*preauth_client_request_fini_proc)(krb5_context context,
-                                    void *plugin_context,
-                                    void *request_context);
+(*krb5_clpreauth_request_fini_fn)(krb5_context context,
+                                  krb5_clpreauth_moddata moddata,
+                                  krb5_clpreauth_modreq modreq);
 
-/* Client function which processes server-supplied data in pa_data,
- * returns created data in out_pa_data, storing any of its own state in
- * client_context if data for the associated preauthentication type is
- * needed.  It is also called after the AS-REP is received if the AS-REP
- * includes preauthentication data of the associated type.
- * NOTE! the encoded_previous_request will be NULL the first time this
- * function is called, because it is expected to only ever contain the data
- * obtained from a previous call to this function. */
+/*
+ * Mandatory: process server-supplied data in pa_data and returns created data
+ * in out_pa_data.  It is also called after the AS-REP is received if the
+ * AS-REP includes preauthentication data of the associated type.  NOTE: the
+ * encoded_previous_request will be NULL the first time this function is
+ * called, because it is expected to only ever contain the data obtained from a
+ * previous call to this function.
+ */
 typedef krb5_error_code
-(*preauth_client_process_proc)(krb5_context context,
-                               void *plugin_context,
-                               void *request_context,
-                               krb5_get_init_creds_opt *opt,
-                               preauth_get_client_data_proc get_data_proc,
-                               struct _krb5_preauth_client_rock *rock,
-                               krb5_kdc_req *request,
-                               krb5_data *encoded_request_body,
-                               krb5_data *encoded_previous_request,
-                               krb5_pa_data *pa_data,
-                               krb5_prompter_fct prompter,
-                               void *prompter_data,
-                               preauth_get_as_key_proc gak_fct,
-                               void *gak_data,
-                               krb5_data *salt,
-                               krb5_data *s2kparams,
-                               krb5_keyblock *as_key,
-                               krb5_pa_data ***out_pa_data);
+(*krb5_clpreauth_process_fn)(krb5_context context,
+                             krb5_clpreauth_moddata moddata,
+                             krb5_clpreauth_modreq modreq,
+                             krb5_get_init_creds_opt *opt,
+                             krb5_clpreauth_get_data_fn get_data,
+                             krb5_clpreauth_rock rock,
+                             krb5_kdc_req *request,
+                             krb5_data *encoded_request_body,
+                             krb5_data *encoded_previous_request,
+                             krb5_pa_data *pa_data,
+                             krb5_prompter_fct prompter, void *prompter_data,
+                             krb5_clpreauth_get_as_key_fn gak_fct,
+                             void *gak_data,
+                             krb5_data *salt, krb5_data *s2kparams,
+                             krb5_keyblock *as_key,
+                             krb5_pa_data ***out_pa_data);
 
-/* Client function which can attempt to use e-data in the error response to
- * try to recover from the given error.  If this function is not NULL, and
- * it stores data in out_pa_data which is different data from the contents
- * of in_pa_data, then the client library will retransmit the request. */
-typedef krb5_error_code
-(*preauth_client_tryagain_proc)(krb5_context context,
-                                void *plugin_context,
-                                void *request_context,
-                                krb5_get_init_creds_opt *opt,
-                                preauth_get_client_data_proc get_data_proc,
-                                struct _krb5_preauth_client_rock *rock,
-                                krb5_kdc_req *request,
-                                krb5_data *encoded_request_body,
-                                krb5_data *encoded_previous_request,
-                                krb5_pa_data *in_pa_data,
-                                krb5_error *error,
-                                krb5_prompter_fct prompter,
-                                void *prompter_data,
-                                preauth_get_as_key_proc gak_fct,
-                                void *gak_data,
-                                krb5_data *salt,
-                                krb5_data *s2kparams,
-                                krb5_keyblock *as_key,
-                                krb5_pa_data ***out_pa_data);
-
 /*
- * Client function which receives krb5_get_init_creds_opt information.
- * The attr and value information supplied should be copied locally by
- * the module if it wishes to reference it after returning from this call.
+ * Optional: Attempt to use e-data in the error response to try to recover from
+ * the given error.  If this function is provided, and it stores data in
+ * out_pa_data which is different data from the contents of in_pa_data, then
+ * the client library will retransmit the request.
  */
 typedef krb5_error_code
-(*preauth_client_supply_gic_opts_proc)(krb5_context context,
-                                       void *plugin_context,
-                                       krb5_get_init_creds_opt *opt,
-                                       const char *attr,
-                                       const char *value);
+(*krb5_clpreauth_tryagain_fn)(krb5_context context,
+                              krb5_clpreauth_moddata moddata,
+                              krb5_clpreauth_modreq modreq,
+                              krb5_get_init_creds_opt *opt,
+                              krb5_clpreauth_get_data_fn get_data,
+                              krb5_clpreauth_rock rock,
+                              krb5_kdc_req *request,
+                              krb5_data *encoded_request_body,
+                              krb5_data *encoded_previous_request,
+                              krb5_pa_data *in_pa_data,
+                              krb5_error *error,
+                              krb5_prompter_fct prompter, void *prompter_data,
+                              krb5_clpreauth_get_as_key_fn gak_fct,
+                              void *gak_data,
+                              krb5_data *salt, krb5_data *s2kparams,
+                              krb5_keyblock *as_key,
+                              krb5_pa_data ***out_pa_data);
 
 /*
- * The function table / structure which a preauth client module must export as
- * "preauthentication_client_0".  If the interfaces work correctly, future
- * versions of the table will add either more callbacks or more arguments to
- * callbacks, and in both cases we'll be able to wrap the v0 functions.
+ * Optional: receive krb5_get_init_creds_opt information.  The attr and value
+ * information supplied should be copied into moddata by the module if it
+ * wishes to reference it after returning from this call.
  */
-typedef struct krb5plugin_preauth_client_ftable_v1 {
-    /* Not-usually-visible name. */
+typedef krb5_error_code
+(*krb5_clpreauth_supply_gic_opts_fn)(krb5_context context,
+                                     krb5_clpreauth_moddata moddata,
+                                     krb5_get_init_creds_opt *opt,
+                                     const char *attr, const char *value);
+
+typedef struct krb5_clpreauth_vtable_st {
+    /* Mandatory: name of module. */
     char *name;
 
-    /* Pointer to zero-terminated list of pa_types which this module can
-     * provide services for. */
+    /* Mandatory: pointer to zero-terminated list of pa_types which this module
+     * can provide services for. */
     krb5_preauthtype *pa_type_list;
 
-    /* Pointer to zero-terminated list of enc_types which this module claims
-     * to add support for. */
+    /* Optional: pointer to zero-terminated list of enc_types which this module
+     * claims to add support for. */
     krb5_enctype *enctype_list;
 
-    /* Per-plugin initialization/cleanup.  The init function is called
-     * by libkrb5 when the plugin is loaded, and the fini function is
-     * called before the plugin is unloaded.  Both are optional and
-     * may be called multiple times in case the plugin is used in
-     * multiple contexts.  The returned context lives the lifetime of
-     * the krb5_context */
-    preauth_client_plugin_init_proc init;
-    preauth_client_plugin_fini_proc fini;
+    krb5_clpreauth_init_fn init;
+    krb5_clpreauth_fini_fn fini;
+    krb5_clpreauth_get_flags_fn flags;
+    krb5_clpreauth_request_init_fn request_init;
+    krb5_clpreauth_request_fini_fn request_fini;
+    krb5_clpreauth_process_fn process;
+    krb5_clpreauth_tryagain_fn tryagain;
+    krb5_clpreauth_supply_gic_opts_fn gic_opts;
+    /* Minor version 1 ends here. */
+} *krb5_clpreauth_vtable;
 
-    /* A callback which returns flags indicating if the module is a "real" or
-     * an "info" mechanism, and so on.  This function is called for each entry
-     * in the client_pa_type_list. */
-    preauth_client_get_flags_proc flags;
 
-    /* Per-request initialization/cleanup.  The request_init function is
-     * called when beginning to process a get_init_creds request and the
-     * request_fini function is called when processing of the request is
-     * complete.  This is optional.  It may be called multiple times in
-     * the lifetime of a krb5_context. */
-    preauth_client_request_init_proc request_init;
-    preauth_client_request_fini_proc request_fini;
+/*
+ * kdcpreauth plugin interface definition.
+ */
 
-    /* Client function which processes server-supplied data in pa_data,
-     * returns created data in out_pa_data, storing any of its own state in
-     * client_context if data for the associated preauthentication type is
-     * needed.  It is also called after the AS-REP is received if the AS-REP
-     * includes preauthentication data of the associated type.
-     * NOTE! the encoded_previous_request will be NULL the first time this
-     * function is called, because it is expected to only ever contain the data
-     * obtained from a previous call to this function. */
-    preauth_client_process_proc process;
+/* While arguments of these types are passed in, they are opaque to kdcpreauth
+ * modules. */
+struct _krb5_db_entry_new;
+struct _krb5_key_data;
 
-    /* Client function which can attempt to use e-data in the error response to
-     * try to recover from the given error.  If this function is not NULL, and
-     * it stores data in out_pa_data which is different data from the contents
-     * of in_pa_data, then the client library will retransmit the request. */
-    preauth_client_tryagain_proc tryagain;
+/* Abstract type for module data and per-request module data. */
+typedef struct krb5_kdcpreauth_moddata_st *krb5_kdcpreauth_moddata;
+typedef struct krb5_kdcpreauth_modreq_st *krb5_kdcpreauth_modreq;
 
-    /*
-     * Client function which receives krb5_get_init_creds_opt information.
-     * The attr and value information supplied should be copied locally by
-     * the module if it wishes to reference it after returning from this call.
-     */
-    preauth_client_supply_gic_opts_proc gic_opts;
-
-} krb5plugin_preauth_client_ftable_v1;
-
-
-/***************************************************************************
- *
- * Server-side preauthentication plugin interface definition.
- *
- ***************************************************************************/
-
 /*
- * A server module's callback functions are allowed to request specific types
- * of information about the given client or server record or request, even
- * though the database records themselves are opaque to the module.
+ * Provided by krb5: a kdcpreauth module's callback functions are allowed to
+ * request specific types of information about the given client or server
+ * record or request, even though the database records themselves are opaque to
+ * the module.
  */
-enum krb5plugin_preauth_entry_request_type {
+enum krb5_kdcpreauth_request_type {
     /* The returned krb5_data item holds a DER-encoded X.509 certificate. */
-    krb5plugin_preauth_entry_request_certificate = 1,
+    krb5_kdcpreauth_request_certificate = 1,
     /* The returned krb5_data_item holds a krb5_deltat. */
-    krb5plugin_preauth_entry_max_time_skew = 2,
-    /* The returned krb5_data_item holds an array of krb5_keyblock structures,
-     * terminated by an entry with key type = 0.
-     * Each keyblock should have its contents freed in turn, and then the data
-     * item itself should be freed. */
-    krb5plugin_preauth_keys = 3,
-    /* The returned krb5_data_item holds the request structure, re-encoded
+    krb5_kdcpreauth_max_time_skew = 2,
+    /*
+     * The returned krb5_data_item holds an array of krb5_keyblock structures,
+     * terminated by an entry with key type = 0.  Each keyblock should have its
+     * contents freed in turn, and then the data item itself should be freed.
+     */
+    krb5_kdcpreauth_keys = 3,
+    /*
+     * The returned krb5_data_item holds the request structure, re-encoded
      * using DER.  Unless the client implementation is the same as the server
      * implementation, there's a good chance that the result will not match
-     * what the client sent, so don't go creating any fatal errors if it
-     * doesn't match up. */
-    krb5plugin_preauth_request_body = 4,
-    /* The returned krb5_data contains a krb5_keyblock with the FAST
-       armor key.  The data member is NULL if this method is not part
-       of a FAST tunnel */
-    krb5plugin_preauth_fast_armor = 5,
-    /* Frees a fast armor key; it is acceptable to set data to NULL
-       and free the keyblock using krb5_free_keyblock; in that  case,
-       this function simply frees the data*/
-    krb5plugin_preauth_free_fast_armor = 6
+     * what the client sent, so don't create any fatal errors if it doesn't
+     * match up.
+     */
+    krb5_kdcpreauth_request_body = 4,
+    /*
+     * The returned krb5_data contains a krb5_keyblock with the FAST armor key.
+     * The data member is NULL if this method is not part of a FAST tunnel.
+     */
+    krb5_kdcpreauth_fast_armor = 5,
+    /*
+     * Frees a fast armor key. It is acceptable to set data to NULL and free
+     * the keyblock using krb5_free_keyblock; in that case, this function
+     * simply frees the data.
+     */
+    krb5_kdcpreauth_free_fast_armor = 6
 };
-
 typedef krb5_error_code
-(*preauth_get_entry_data_proc)(krb5_context,
-                               krb5_kdc_req *,
-                               struct _krb5_db_entry_new *,
+(*krb5_kdcpreauth_get_data_fn)(krb5_context context, krb5_kdc_req *request,
+                               struct _krb5_db_entry_new *entry,
                                krb5_int32 request_type,
                                krb5_data **);
 
-/* Preauth plugin initialization function */
+/* Optional: preauth plugin initialization function. */
 typedef krb5_error_code
-(*preauth_server_init_proc)(krb5_context context,
-                            void **plugin_context,
-                            const char** realmnames);
+(*krb5_kdcpreauth_init_fn)(krb5_context context,
+                           krb5_kdcpreauth_moddata *moddata_out,
+                           const char **realmnames);
 
-/* Preauth plugin cleanup function */
+/* Optional: preauth plugin cleanup function. */
 typedef void
-(*preauth_server_fini_proc)(krb5_context context, void *plugin_context);
+(*krb5_kdcpreauth_fini_fn)(krb5_context context,
+                           krb5_kdcpreauth_moddata moddata);
 
-/* Return the flags which the KDC should use for this module.  This is a
- * callback instead of a static value because the module may or may not
- * wish to count itself as a hardware preauthentication module (in other
- * words, the flags may be affected by the configuration, for example if a
- * site administrator can force a particular preauthentication type to be
- * supported using only hardware).  This function is called for each entry
- * entry in the server_pa_type_list. */
+/*
+ * Optional: return the flags which the KDC should use for this module.  This
+ * is a callback instead of a static value because the module may or may not
+ * wish to count itself as a hardware preauthentication module (in other words,
+ * the flags may be affected by the configuration, for example if a site
+ * administrator can force a particular preauthentication type to be supported
+ * using only hardware).  This function is called for each entry entry in the
+ * server_pa_type_list.
+ */
 typedef int
-(*preauth_server_flags_proc)(krb5_context context, krb5_preauthtype patype);
+(*krb5_kdcpreauth_flags_fn)(krb5_context context, krb5_preauthtype patype);
 
-/* Get preauthentication data to send to the client as part of the "you
- * need to use preauthentication" error.  The module doesn't need to
- * actually provide data if the protocol doesn't require it, but it should
- * return either zero or non-zero to control whether its padata type is
- * included in the list which is sent back to the client.  Is not allowed
- * to create a context because we have no guarantee that the client will
- * ever call again (or that it will hit this server if it does), in which
- * case a context might otherwise hang around forever. */
+/*
+ * Optional: fill in pa_out->length and pa_out->contents with data to send to
+ * the client as part of the "you need to use preauthentication" error.  If
+ * this function returns non-zero, the padata type will not be included in the
+ * list; if this function is not provided or returns zero without changing
+ * pa_out, the padata type will be included in the list with an empty value.
+ * This function not allowed to create a context because we have no guarantee
+ * that the client will ever call again (or that it will hit this server if it
+ * does), in which case a context might otherwise hang around forever.
+ */
 typedef krb5_error_code
-(*preauth_server_edata_proc)(krb5_context,
-                             krb5_kdc_req *request,
-                             struct _krb5_db_entry_new *client,
-                             struct _krb5_db_entry_new *server,
-                             preauth_get_entry_data_proc,
-                             void *pa_module_context,
-                             krb5_pa_data *data);
+(*krb5_kdcpreauth_edata_fn)(krb5_context context, krb5_kdc_req *request,
+                            struct _krb5_db_entry_new *client,
+                            struct _krb5_db_entry_new *server,
+                            krb5_kdcpreauth_get_data_fn get_data,
+                            krb5_kdcpreauth_moddata moddata,
+                            krb5_pa_data *pa_out);
 
-/* Verify preauthentication data sent by the client, setting the
+/*
+ * Optional: verify preauthentication data sent by the client, setting the
  * TKT_FLG_PRE_AUTH or TKT_FLG_HW_AUTH flag in the enc_tkt_reply's "flags"
  * field as appropriate, and returning nonzero on failure.  Can create
- * context data for consumption by the return_proc or freepa_proc below. */
+ * per-request module data for consumption by the return_fn or free_modreq_fn
+ * below.
+ */
 typedef krb5_error_code
-(*preauth_server_verify_proc)(krb5_context context,
-                              struct _krb5_db_entry_new *client,
-                              krb5_data *req_pkt,
-                              krb5_kdc_req *request,
-                              krb5_enc_tkt_part *enc_tkt_reply,
-                              krb5_pa_data *data,
-                              preauth_get_entry_data_proc,
-                              void *pa_module_context,
-                              void **pa_request_context,
-                              krb5_data **e_data,
-                              krb5_authdata ***authz_data);
+(*krb5_kdcpreauth_verify_fn)(krb5_context context,
+                             struct _krb5_db_entry_new *client,
+                             krb5_data *req_pkt, krb5_kdc_req *request,
+                             krb5_enc_tkt_part *enc_tkt_reply,
+                             krb5_pa_data *data,
+                             krb5_kdcpreauth_get_data_fn get_data,
+                             krb5_kdcpreauth_moddata moddata,
+                             krb5_kdcpreauth_modreq *modreq_out,
+                             krb5_data **e_data_out,
+                             krb5_authdata ***authz_data_out);
 
-/* Generate preauthentication response data to send to the client as part
- * of the AS-REP.  If it needs to override the key which is used to encrypt
- * the response, it can do so.  The module is expected (but not required,
- * if a preauth_server_free_reqcontext_proc is also provided) to free any
- * context data it saved in "pa_request_context". */
+/*
+ * Optional: generate preauthentication response data to send to the client as
+ * part of the AS-REP.  If it needs to override the key which is used to
+ * encrypt the response, it can do so.
+ */
 typedef krb5_error_code
-(*preauth_server_return_proc)(krb5_context context,
-                              krb5_pa_data * padata,
-                              struct _krb5_db_entry_new *client,
-                              krb5_data *req_pkt,
-                              krb5_kdc_req *request,
-                              krb5_kdc_rep *reply,
-                              struct _krb5_key_data *client_keys,
-                              krb5_keyblock *encrypting_key,
-                              krb5_pa_data **send_pa,
-                              preauth_get_entry_data_proc,
-                              void *pa_module_context,
-                              void **pa_request_context);
+(*krb5_kdcpreauth_return_fn)(krb5_context context,
+                             krb5_pa_data *padata,
+                             struct _krb5_db_entry_new *client,
+                             krb5_data *req_pkt,
+                             krb5_kdc_req *request,
+                             krb5_kdc_rep *reply,
+                             struct _krb5_key_data *client_keys,
+                             krb5_keyblock *encrypting_key,
+                             krb5_pa_data **send_pa_out,
+                             krb5_kdcpreauth_get_data_fn,
+                             krb5_kdcpreauth_moddata moddata,
+                             krb5_kdcpreauth_modreq modreq);
 
-/* Free up the server-side per-request context, in cases where
- * server_return_proc() didn't or for whatever reason was not called.
- * Can be NULL. */
-typedef krb5_error_code
-(*preauth_server_free_reqcontext_proc)(krb5_context,
-                                       void *pa_module_context,
-                                       void **request_pa_context);
+/* Optional: free a per-request context. */
+typedef void
+(*krb5_kdcpreauth_free_modreq_fn)(krb5_context,
+                                  krb5_kdcpreauth_moddata moddata,
+                                  krb5_kdcpreauth_modreq modreq);
 
-/*
- * The function table / structure which a preauth server module must export as
- * "preauthentication_server_0".  NOTE: replace "0" with "1" for the type and
- * variable names if this gets picked up by upstream.  If the interfaces work
- * correctly, future versions of the table will add either more callbacks or
- * more arguments to callbacks, and in both cases we'll be able to wrap the v0
- * functions.
- */
-typedef struct krb5plugin_preauth_server_ftable_v1 {
-    /* Not-usually-visible name. */
+typedef struct krb5_kdcpreauth_vtable_st {
+    /* Mandatory: name of module. */
     char *name;
 
-    /* Pointer to zero-terminated list of pa_types which this module can
-     * provide services for. */
+    /* Mandatory: pointer to zero-terminated list of pa_types which this module
+     * can provide services for. */
     krb5_preauthtype *pa_type_list;
 
-    /* Per-plugin initialization/cleanup.  The init function is called by the
-     * KDC when the plugin is loaded, and the fini function is called before
-     * the plugin is unloaded.  Both are optional. */
-    preauth_server_init_proc init_proc;
-    preauth_server_fini_proc fini_proc;
+    krb5_kdcpreauth_init_fn init;
+    krb5_kdcpreauth_fini_fn fini;
+    krb5_kdcpreauth_flags_fn flags;
+    krb5_kdcpreauth_edata_fn edata;
+    krb5_kdcpreauth_verify_fn verify;
+    krb5_kdcpreauth_return_fn return_padata;
+    krb5_kdcpreauth_free_modreq_fn free_modreq;
+} *krb5_kdcpreauth_vtable;
 
-    /* Return the flags which the KDC should use for this module.  This is a
-     * callback instead of a static value because the module may or may not
-     * wish to count itself as a hardware preauthentication module (in other
-     * words, the flags may be affected by the configuration, for example if a
-     * site administrator can force a particular preauthentication type to be
-     * supported using only hardware).  This function is called for each entry
-     * entry in the server_pa_type_list. */
-    preauth_server_flags_proc flags_proc;
-
-    /* Get preauthentication data to send to the client as part of the "you
-     * need to use preauthentication" error.  The module doesn't need to
-     * actually provide data if the protocol doesn't require it, but it should
-     * return either zero or non-zero to control whether its padata type is
-     * included in the list which is sent back to the client.  Is not allowed
-     * to create a context because we have no guarantee that the client will
-     * ever call again (or that it will hit this server if it does), in which
-     * case a context might otherwise hang around forever. */
-    preauth_server_edata_proc edata_proc;
-
-    /* Verify preauthentication data sent by the client, setting the
-     * TKT_FLG_PRE_AUTH or TKT_FLG_HW_AUTH flag in the enc_tkt_reply's "flags"
-     * field as appropriate, and returning nonzero on failure.  Can create
-     * context data for consumption by the return_proc or freepa_proc below. */
-    preauth_server_verify_proc verify_proc;
-
-    /* Generate preauthentication response data to send to the client as part
-     * of the AS-REP.  If it needs to override the key which is used to encrypt
-     * the response, it can do so.  The module is expected (but not required,
-     * if a freepa_proc is also provided) to free any context data it saved in
-     * "request_pa_context". */
-    preauth_server_return_proc return_proc;
-
-    /* Free up the server-side per-request context, in cases where
-     * server_return_proc() didn't or for whatever reason was not called.
-     * Can be NULL. */
-    preauth_server_free_reqcontext_proc freepa_reqcontext_proc;
-
-} krb5plugin_preauth_server_ftable_v1;
-
-
 /*
  * This function allows a preauth plugin to obtain preauth
  * options.  The preauth_data returned from this function
  * should be freed by calling krb5_get_init_creds_opt_free_pa().
  *
  * The 'opt' pointer supplied to this function must have been
- * obtained using krb5_get_init_creds_opt_alloc()
+ * obtained using krb5_get_init_creds_opt_alloc().
  */
 krb5_error_code KRB5_CALLCONV
 krb5_get_init_creds_opt_get_pa(krb5_context context,

Modified: trunk/src/kdc/do_as_req.c
===================================================================
--- trunk/src/kdc/do_as_req.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/kdc/do_as_req.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -616,8 +616,7 @@
     /* fall through */
 
 egress:
-    if (pa_context)
-        free_padata_context(kdc_context, &pa_context);
+    free_padata_context(kdc_context, pa_context);
     if (as_encrypting_key)
         krb5_free_keyblock(kdc_context, as_encrypting_key);
     if (errcode)

Modified: trunk/src/kdc/kdc_preauth.c
===================================================================
--- trunk/src/kdc/kdc_preauth.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/kdc/kdc_preauth.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -91,58 +91,45 @@
 #include <assert.h>
 #include "../include/krb5/preauth_plugin.h"
 
-#if TARGET_OS_MAC
-static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR,
-                                 LIBDIR "/krb5/plugins/preauth",
-                                 NULL }; /* should be a list */
-#else
-static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
-#endif
-
-typedef struct _krb5_preauth_systems {
+typedef struct preauth_system_st {
     const char *name;
-    int         type;
-    int         flags;
-    void       *plugin_context;
-    preauth_server_init_proc    init;
-    preauth_server_fini_proc    fini;
-    preauth_server_edata_proc   get_edata;
-    preauth_server_verify_proc  verify_padata;
-    preauth_server_return_proc  return_padata;
-    preauth_server_free_reqcontext_proc free_pa_reqctx;
-} krb5_preauth_systems;
+    int type;
+    int flags;
+    krb5_kdcpreauth_moddata moddata;
+    krb5_kdcpreauth_init_fn init;
+    krb5_kdcpreauth_fini_fn fini;
+    krb5_kdcpreauth_edata_fn get_edata;
+    krb5_kdcpreauth_verify_fn verify_padata;
+    krb5_kdcpreauth_return_fn return_padata;
+    krb5_kdcpreauth_free_modreq_fn free_modreq;
+} preauth_system;
 
 static krb5_error_code
-verify_enc_timestamp (krb5_context, krb5_db_entry *client,
-                      krb5_data *req_pkt,
-                      krb5_kdc_req *request,
-                      krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data,
-                      preauth_get_entry_data_proc get_entry_data,
-                      void *pa_system_context,
-                      void **pa_request_context,
-                      krb5_data **e_data,
-                      krb5_authdata ***authz_data);
+verify_enc_timestamp(krb5_context, krb5_db_entry *client, krb5_data *req_pkt,
+                     krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
+                     krb5_pa_data *data,
+                     krb5_kdcpreauth_get_data_fn get_entry_data,
+                     krb5_kdcpreauth_moddata moddata,
+                     krb5_kdcpreauth_modreq *modreq_out, krb5_data **e_data,
+                     krb5_authdata ***authz_data);
 
 static krb5_error_code
-get_enc_ts(krb5_context, krb5_kdc_req *request,
+get_enc_ts(krb5_context context, krb5_kdc_req *request,
            krb5_db_entry *client, krb5_db_entry *server,
-           preauth_get_entry_data_proc get_entry_data,
-           void *pa_system_context,
-           krb5_pa_data *data);
+           krb5_kdcpreauth_get_data_fn get_entry_data,
+           krb5_kdcpreauth_moddata modata, krb5_pa_data *data);
 
 static krb5_error_code
-get_etype_info(krb5_context, krb5_kdc_req *request,
+get_etype_info(krb5_context context, krb5_kdc_req *request,
                krb5_db_entry *client, krb5_db_entry *server,
-               preauth_get_entry_data_proc get_entry_data,
-               void *pa_system_context,
-               krb5_pa_data *data);
+               krb5_kdcpreauth_get_data_fn get_entry_data,
+               krb5_kdcpreauth_moddata moddata, krb5_pa_data *data);
 
 static krb5_error_code
 get_etype_info2(krb5_context context, krb5_kdc_req *request,
                 krb5_db_entry *client, krb5_db_entry *server,
-                preauth_get_entry_data_proc get_entry_data,
-                void *pa_system_context,
-                krb5_pa_data *pa_data);
+                krb5_kdcpreauth_get_data_fn get_entry_data,
+                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data);
 
 static krb5_error_code
 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
@@ -154,40 +141,31 @@
                          int etype_info2);
 
 static krb5_error_code
-return_etype_info(krb5_context, krb5_pa_data * padata,
-                  krb5_db_entry *client,
-                  krb5_data *req_pkt,
-                  krb5_kdc_req *request, krb5_kdc_rep *reply,
-                  krb5_key_data *client_key,
-                  krb5_keyblock *encrypting_key,
-                  krb5_pa_data **send_pa,
-                  preauth_get_entry_data_proc get_entry_data,
-                  void *pa_system_context,
-                  void **pa_request_context);
+return_etype_info(krb5_context, krb5_pa_data *padata, krb5_db_entry *client,
+                  krb5_data *req_pkt, krb5_kdc_req *request,
+                  krb5_kdc_rep *reply, krb5_key_data *client_key,
+                  krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
+                  krb5_kdcpreauth_get_data_fn get_entry_data,
+                  krb5_kdcpreauth_moddata moddata,
+                  krb5_kdcpreauth_modreq modreq);
 
 static krb5_error_code
-return_etype_info2(krb5_context, krb5_pa_data * padata,
-                   krb5_db_entry *client,
-                   krb5_data *req_pkt,
-                   krb5_kdc_req *request, krb5_kdc_rep *reply,
-                   krb5_key_data *client_key,
-                   krb5_keyblock *encrypting_key,
-                   krb5_pa_data **send_pa,
-                   preauth_get_entry_data_proc get_entry_data,
-                   void *pa_system_context,
-                   void **pa_request_context);
+return_etype_info2(krb5_context, krb5_pa_data *padata, krb5_db_entry *client,
+                   krb5_data *req_pkt, krb5_kdc_req *request,
+                   krb5_kdc_rep *reply, krb5_key_data *client_key,
+                   krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
+                   krb5_kdcpreauth_get_data_fn get_entry_data,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq modreq);
 
 static krb5_error_code
-return_pw_salt(krb5_context, krb5_pa_data * padata,
-               krb5_db_entry *client,
-               krb5_data *req_pkt,
-               krb5_kdc_req *request, krb5_kdc_rep *reply,
-               krb5_key_data *client_key,
-               krb5_keyblock *encrypting_key,
+return_pw_salt(krb5_context, krb5_pa_data *padata, krb5_db_entry *client,
+               krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
+               krb5_key_data *client_key, krb5_keyblock *encrypting_key,
                krb5_pa_data **send_pa,
-               preauth_get_entry_data_proc get_entry_data,
-               void *pa_system_context,
-               void **pa_request_context);
+               krb5_kdcpreauth_get_data_fn get_entry_data,
+               krb5_kdcpreauth_moddata moddata,
+               krb5_kdcpreauth_modreq modreq);
 
 
 #if APPLE_PKINIT
@@ -227,7 +205,7 @@
     void **pa_request_context);
 #endif /* APPLE_PKINIT */
 
-static krb5_preauth_systems static_preauth_systems[] = {
+static preauth_system static_preauth_systems[] = {
 #if APPLE_PKINIT
     {
         "pkinit",
@@ -239,7 +217,7 @@
         get_pkinit_edata,
         verify_pkinit_request,
         return_pkinit_response,
-        NULL                    /* free_pa_request_context */
+        NULL                    /* free_modreq */
     },
 #endif /* APPLE_PKINIT */
     {
@@ -318,219 +296,168 @@
         return_server_referral
     },
 #endif
-    { "[end]", -1,}
 };
 
-static krb5_preauth_systems *preauth_systems;
-static int n_preauth_systems;
-static struct plugin_dir_handle preauth_plugins;
+#define NUM_STATIC_PREAUTH_SYSTEMS (sizeof(static_preauth_systems) / \
+                                    sizeof(*static_preauth_systems))
 
-/* Open plugin directories for preauth modules. */
-static krb5_error_code
-open_preauth_plugin_dirs(krb5_context ctx)
+static preauth_system *preauth_systems;
+static size_t n_preauth_systems;
+
+/* Get all available kdcpreauth vtables and a count of preauth types they
+ * support.  Return an empty list on failure. */
+static void
+get_plugin_vtables(krb5_context context,
+                   struct krb5_kdcpreauth_vtable_st **vtables_out,
+                   size_t *n_tables_out, size_t *n_systems_out)
 {
-    static const char *path[] = {
-        KRB5_CONF_LIBDEFAULTS, KRB5_CONF_PREAUTH_MODULE_DIR, NULL,
-    };
-    char **profpath = NULL;
-    const char **dirs;
-    krb5_error_code ret;
+    krb5_plugin_initvt_fn *plugins = NULL, *pl;
+    struct krb5_kdcpreauth_vtable_st *vtables;
+    size_t count, n_tables, n_systems, i;
 
-    ret = profile_get_values(ctx->profile, path, &profpath);
-    if (ret != 0 && ret != PROF_NO_RELATION)
-        return ret;
-    dirs = (profpath != NULL) ? (const char **) profpath : objdirs;
-    ret = krb5int_open_plugin_dirs(dirs, NULL, &preauth_plugins, &ctx->err);
-    profile_free_list(profpath);
-    return ret;
-}
+    *vtables_out = NULL;
+    *n_tables_out = *n_systems_out = 0;
 
-krb5_error_code
-load_preauth_plugins(krb5_context context)
-{
-    void **preauth_plugins_ftables;
-    struct krb5plugin_preauth_server_ftable_v1 *ftable;
-    size_t module_count, i, j, k;
-    void *plugin_context;
-    preauth_server_init_proc server_init_proc = NULL;
-    char **kdc_realm_names = NULL;
+    /* Auto-register pkinit and encrypted challenge if possible. */
+    k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "pkinit",
+                           "preauth");
+    k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH,
+                           "encrypted_challenge", "preauth");
 
-    /* Attempt to load all of the preauth plugins we can find. */
-    PLUGIN_DIR_INIT(&preauth_plugins);
-    if (PLUGIN_DIR_OPEN(&preauth_plugins) == 0) {
-        if (open_preauth_plugin_dirs(context) != 0)
-            return KRB5_PLUGIN_NO_HANDLE;
+    if (k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPREAUTH, &plugins))
+        return;
+    for (count = 0; plugins[count]; count++);
+    vtables = calloc(count + 1, sizeof(*vtables));
+    if (vtables == NULL)
+        goto cleanup;
+    for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
+        if ((*pl)(context, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
+            n_tables++;
     }
-
-    /* Get the method tables provided by the loaded plugins. */
-    preauth_plugins_ftables = NULL;
-    if (krb5int_get_plugin_dir_data(&preauth_plugins,
-                                    "preauthentication_server_1",
-                                    &preauth_plugins_ftables, &context->err) != 0) {
-        return KRB5_PLUGIN_NO_HANDLE;
+    for (i = 0, n_systems = 0; i < n_tables; i++) {
+        for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
+        n_systems += count;
     }
+    *vtables_out = vtables;
+    *n_tables_out = n_tables;
+    *n_systems_out = n_systems;
 
-    /* Count the valid modules. */
-    module_count = sizeof(static_preauth_systems)
-        / sizeof(static_preauth_systems[0]);
-    if (preauth_plugins_ftables != NULL) {
-        for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
-            ftable = preauth_plugins_ftables[i];
-            if ((ftable->flags_proc == NULL) &&
-                (ftable->edata_proc == NULL) &&
-                (ftable->verify_proc == NULL) &&
-                (ftable->return_proc == NULL)) {
-                continue;
-            }
-            for (j = 0;
-                 ftable->pa_type_list != NULL &&
-                     ftable->pa_type_list[j] > 0;
-                 j++) {
-                module_count++;
-            }
-        }
-    }
+cleanup:
+    k5_plugin_free_modules(context, plugins);
+}
 
-    /* Build the complete list of supported preauthentication options, and
-     * leave room for a terminator entry. */
-    preauth_systems = malloc(sizeof(krb5_preauth_systems) * (module_count + 1));
-    if (preauth_systems == NULL) {
-        krb5int_free_plugin_dir_data(preauth_plugins_ftables);
-        return ENOMEM;
-    }
+/* Make a list of realm names.  The caller should free the list container but
+ * not the list elements (which are aliases into kdc_realmlist). */
+static krb5_error_code
+get_realm_names(const char ***list_out)
+{
+    const char **list;
+    int i;
 
-    /* Build a list of the names of the supported realms for this KDC.
-     * The list of names is terminated with a NULL. */
-    kdc_realm_names = malloc(sizeof(char *) * (kdc_numrealms + 1));
-    if (kdc_realm_names == NULL) {
-        krb5int_free_plugin_dir_data(preauth_plugins_ftables);
+    list = calloc(kdc_numrealms + 1, sizeof(*list));
+    if (list == NULL)
         return ENOMEM;
-    }
-    for (i = 0; i < (size_t)kdc_numrealms; i++) {
-        kdc_realm_names[i] = kdc_realmlist[i]->realm_name;
-    }
-    kdc_realm_names[i] = NULL;
+    for (i = 0; i < kdc_numrealms; i++)
+        list[i] = kdc_realmlist[i]->realm_name;
+    list[i] = NULL;
+    *list_out = list;
+    return 0;
+}
 
-    /* Add the locally-supplied mechanisms to the dynamic list first. */
-    for (i = 0, k = 0;
-         i < sizeof(static_preauth_systems) / sizeof(static_preauth_systems[0]);
-         i++) {
-        if (static_preauth_systems[i].type == -1)
-            break;
-        preauth_systems[k] = static_preauth_systems[i];
-        /* Try to initialize the preauth system.  If it fails, we'll remove it
-         * from the list of systems we'll be using. */
-        plugin_context = NULL;
-        server_init_proc = static_preauth_systems[i].init;
-        if ((server_init_proc != NULL) &&
-            ((*server_init_proc)(context, &plugin_context,
-                                 (const char **)kdc_realm_names) != 0)) {
-            memset(&preauth_systems[k], 0, sizeof(preauth_systems[k]));
-            continue;
-        }
-        preauth_systems[k].plugin_context = plugin_context;
-        k++;
-    }
+void
+load_preauth_plugins(krb5_context context)
+{
+    krb5_error_code ret;
+    struct krb5_kdcpreauth_vtable_st *vtables = NULL, *vt;
+    size_t n_systems, n_tables, i, j;
+    krb5_kdcpreauth_moddata moddata;
+    const char **realm_names = NULL, *emsg;
+    preauth_system *sys;
 
-    /* Now add the dynamically-loaded mechanisms to the list. */
-    if (preauth_plugins_ftables != NULL) {
-        for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
-            ftable = preauth_plugins_ftables[i];
-            if ((ftable->flags_proc == NULL) &&
-                (ftable->edata_proc == NULL) &&
-                (ftable->verify_proc == NULL) &&
-                (ftable->return_proc == NULL)) {
+    /* Get all available kdcpreauth vtables. */
+    get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
+
+    /* Allocate the list of static and plugin preauth systems. */
+    n_systems += NUM_STATIC_PREAUTH_SYSTEMS;
+    preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
+    if (preauth_systems == NULL)
+        goto cleanup;
+
+    if (get_realm_names(&realm_names))
+        goto cleanup;
+
+    /* Add the static system to the list first.  No static systems require
+     * initialization, so just make a direct copy. */
+    memcpy(preauth_systems, static_preauth_systems,
+           sizeof(static_preauth_systems));
+
+    /* Add the dynamically-loaded mechanisms to the list. */
+    n_systems = NUM_STATIC_PREAUTH_SYSTEMS;
+    for (i = 0; i < n_tables; i++) {
+        /* Try to initialize this module. */
+        vt = &vtables[i];
+        moddata = NULL;
+        if (vt->init) {
+            ret = vt->init(context, &moddata, realm_names);
+            if (ret) {
+                emsg = krb5_get_error_message(context, ret);
+                krb5_klog_syslog(LOG_ERR, _("preauth %s failed to "
+                                            "initialize: %s"), vt->name, emsg);
+                krb5_free_error_message(context, emsg);
                 continue;
             }
-            plugin_context = NULL;
-            for (j = 0;
-                 ftable->pa_type_list != NULL &&
-                     ftable->pa_type_list[j] > 0;
-                 j++) {
-                /* Try to initialize the plugin.  If it fails, we'll remove it
-                 * from the list of modules we'll be using. */
-                if (j == 0) {
-                    server_init_proc = ftable->init_proc;
-                    if (server_init_proc != NULL) {
-                        krb5_error_code initerr;
-                        initerr = (*server_init_proc)(context, &plugin_context,
-                                                      (const char **)kdc_realm_names);
-                        if (initerr) {
-                            const char *emsg;
-                            emsg = krb5_get_error_message(context, initerr);
-                            krb5_klog_syslog(LOG_ERR, _("preauth %s failed to "
-                                                        "initialize: %s"),
-                                             ftable->name, emsg);
-                            krb5_free_error_message(context, emsg);
-                            memset(&preauth_systems[k], 0,
-                                   sizeof(preauth_systems[k]));
-
-                            break;      /* skip all modules in this plugin */
-                        }
-                    }
-                }
-                preauth_systems[k].name = ftable->name;
-                preauth_systems[k].type = ftable->pa_type_list[j];
-                if (ftable->flags_proc != NULL)
-                    preauth_systems[k].flags = ftable->flags_proc(context,
-                                                                  preauth_systems[k].type);
-                else
-                    preauth_systems[k].flags = 0;
-                preauth_systems[k].plugin_context = plugin_context;
-                preauth_systems[k].init = server_init_proc;
-                /* Only call fini once for each plugin */
-                if (j == 0)
-                    preauth_systems[k].fini = ftable->fini_proc;
-                else
-                    preauth_systems[k].fini = NULL;
-                preauth_systems[k].get_edata = ftable->edata_proc;
-                preauth_systems[k].verify_padata = ftable->verify_proc;
-                preauth_systems[k].return_padata = ftable->return_proc;
-                preauth_systems[k].free_pa_reqctx =
-                    ftable->freepa_reqcontext_proc;
-                k++;
-            }
         }
-        krb5int_free_plugin_dir_data(preauth_plugins_ftables);
+        /* Add this module to the systems list once for each pa type. */
+        for (j = 0; vt->pa_type_list[j] > 0; j++) {
+            sys = &preauth_systems[n_systems];
+            sys->name = vt->name;
+            sys->type = vt->pa_type_list[j];
+            sys->flags = (vt->flags) ? vt->flags(context, sys->type) : 0;
+            sys->moddata = moddata;
+            sys->init = vt->init;
+            /* Only call fini once for each plugin. */
+            sys->fini = (j == 0) ? vt->fini : NULL;
+            sys->get_edata = vt->edata;
+            sys->verify_padata = vt->verify;
+            sys->return_padata = vt->return_padata;
+            sys->free_modreq = vt->free_modreq;
+            n_systems++;
+        }
     }
-    free(kdc_realm_names);
-    n_preauth_systems = k;
+    n_preauth_systems = n_systems;
     /* Add the end-of-list marker. */
-    preauth_systems[k].name = "[end]";
-    preauth_systems[k].type = -1;
-    return 0;
+    preauth_systems[n_systems].name = "[end]";
+    preauth_systems[n_systems].type = -1;
+
+cleanup:
+    free(vtables);
+    free(realm_names);
 }
 
-krb5_error_code
+void
 unload_preauth_plugins(krb5_context context)
 {
-    int i;
-    if (preauth_systems != NULL) {
-        for (i = 0; i < n_preauth_systems; i++) {
-            if (preauth_systems[i].fini != NULL) {
-                (*preauth_systems[i].fini)(context,
-                                           preauth_systems[i].plugin_context);
-            }
-            memset(&preauth_systems[i], 0, sizeof(preauth_systems[i]));
-        }
-        free(preauth_systems);
-        preauth_systems = NULL;
-        n_preauth_systems = 0;
-        krb5int_close_plugin_dirs(&preauth_plugins);
+    size_t i;
+
+    for (i = 0; i < n_preauth_systems; i++) {
+        if (preauth_systems[i].fini)
+            preauth_systems[i].fini(context, preauth_systems[i].moddata);
     }
-    return 0;
+    free(preauth_systems);
+    preauth_systems = NULL;
+    n_preauth_systems = 0;
 }
 
 /*
- * The make_padata_context() function creates a space for storing any context
- * information which will be needed by return_padata() later.  Each preauth
- * type gets a context storage location of its own.
+ * The make_padata_context() function creates a space for storing any
+ * request-specific module data which will be needed by return_padata() later.
+ * Each preauth type gets a storage location of its own.
  */
 struct request_pa_context {
     int n_contexts;
     struct {
-        krb5_preauth_systems *pa_system;
-        void *pa_context;
+        preauth_system *pa_system;
+        krb5_kdcpreauth_modreq modreq;
     } *contexts;
 };
 
@@ -556,7 +483,7 @@
 
     for (i = 0; i < ret->n_contexts; i++) {
         ret->contexts[i].pa_system = &preauth_systems[i];
-        ret->contexts[i].pa_context = NULL;
+        ret->contexts[i].modreq = NULL;
     }
 
     *padata_context = ret;
@@ -569,35 +496,25 @@
  * which the check_padata() function created but which weren't already cleaned
  * up by return_padata().
  */
-krb5_error_code
-free_padata_context(krb5_context kcontext, void **padata_context)
+void
+free_padata_context(krb5_context kcontext, void *padata_context)
 {
-    struct request_pa_context *context;
-    krb5_preauth_systems *preauth_system;
-    void **pctx, *mctx;
+    struct request_pa_context *context = padata_context;
+    preauth_system *sys;
     int i;
 
-    if (padata_context == NULL)
-        return 0;
-
-    context = *padata_context;
-
+    if (context == NULL)
+        return;
     for (i = 0; i < context->n_contexts; i++) {
-        if (context->contexts[i].pa_context != NULL) {
-            preauth_system = context->contexts[i].pa_system;
-            mctx = preauth_system->plugin_context;
-            if (preauth_system->free_pa_reqctx != NULL) {
-                pctx = &context->contexts[i].pa_context;
-                (*preauth_system->free_pa_reqctx)(kcontext, mctx, pctx);
-            }
-            context->contexts[i].pa_context = NULL;
-        }
+        sys = context->contexts[i].pa_system;
+        if (!sys->free_modreq || !context->contexts[i].modreq)
+            continue;
+        sys->free_modreq(kcontext, sys->moddata, context->contexts[i].modreq);
+        context->contexts[i].modreq = NULL;
     }
 
     free(context->contexts);
     free(context);
-
-    return 0;
 }
 
 /* Retrieve a specified tl_data item from the given entry, and return its
@@ -637,10 +554,8 @@
  * modules.
  */
 static krb5_error_code
-get_entry_data(krb5_context context,
-               krb5_kdc_req *request, krb5_db_entry *entry,
-               krb5_int32  type,
-               krb5_data **result)
+get_entry_data(krb5_context context, krb5_kdc_req *request,
+               krb5_db_entry *entry, krb5_int32 type, krb5_data **result)
 {
     int i, k;
     krb5_data *ret;
@@ -651,11 +566,11 @@
     struct kdc_request_state *state = request->kdc_state;
 
     switch (type) {
-    case krb5plugin_preauth_entry_request_certificate:
+    case krb5_kdcpreauth_request_certificate:
         return get_entry_tl_data(context, entry,
                                  KRB5_TL_USER_CERTIFICATE, result);
         break;
-    case krb5plugin_preauth_entry_max_time_skew:
+    case krb5_kdcpreauth_max_time_skew:
         ret = malloc(sizeof(krb5_data));
         if (ret == NULL)
             return ENOMEM;
@@ -670,7 +585,7 @@
         *result = ret;
         return 0;
         break;
-    case krb5plugin_preauth_keys:
+    case krb5_kdcpreauth_keys:
         ret = malloc(sizeof(krb5_data));
         if (ret == NULL)
             return ENOMEM;
@@ -705,7 +620,7 @@
             free(ret);
         }
         break;
-    case krb5plugin_preauth_request_body:
+    case krb5_kdcpreauth_request_body:
         ret = NULL;
         encode_krb5_kdc_req_body(request, &ret);
         if (ret != NULL) {
@@ -714,7 +629,7 @@
         }
         return ASN1_PARSE_ERROR;
         break;
-    case krb5plugin_preauth_fast_armor:
+    case krb5_kdcpreauth_fast_armor:
         ret = calloc(1, sizeof(krb5_data));
         if (ret == NULL)
             return ENOMEM;
@@ -731,7 +646,7 @@
         }
         free(ret);
         return error;
-    case krb5plugin_preauth_free_fast_armor:
+    case krb5_kdcpreauth_free_fast_armor:
         if ((*result)->data) {
             keys = (krb5_keyblock *) (*result)->data;
             krb5_free_keyblock(context, keys);
@@ -745,9 +660,9 @@
 }
 
 static krb5_error_code
-find_pa_system(int type, krb5_preauth_systems **preauth)
+find_pa_system(int type, preauth_system **preauth)
 {
-    krb5_preauth_systems *ap;
+    preauth_system *ap;
 
     ap = preauth_systems ? preauth_systems : static_preauth_systems;
     while ((ap->type != -1) && (ap->type != type))
@@ -758,21 +673,20 @@
     return 0;
 }
 
+/* Find a pointer to the request-specific module data for pa_sys. */
 static krb5_error_code
-find_pa_context(krb5_preauth_systems *pa_sys,
-                struct request_pa_context *context,
-                void ***pa_context)
+find_modreq(preauth_system *pa_sys, struct request_pa_context *context,
+            krb5_kdcpreauth_modreq **modreq_out)
 {
     int i;
 
-    *pa_context = 0;
-
+    *modreq_out = NULL;
     if (context == NULL)
         return KRB5KRB_ERR_GENERIC;
 
     for (i = 0; i < context->n_contexts; i++) {
         if (context->contexts[i].pa_system == pa_sys) {
-            *pa_context = &context->contexts[i].pa_context;
+            *modreq_out = &context->contexts[i].modreq;
             return 0;
         }
     }
@@ -797,7 +711,7 @@
 static void
 sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
 {
-    int i, j, k, n_repliers, n_key_replacers;
+    size_t i, j, k, n_repliers, n_key_replacers;
 
     /* First, set up the default order. */
     i = 0;
@@ -909,7 +823,7 @@
                       krb5_db_entry *server, krb5_data *e_data)
 {
     int hw_only;
-    krb5_preauth_systems *ap;
+    preauth_system *ap;
     krb5_pa_data **pa_data, **pa;
     krb5_data *edat;
     krb5_error_code retval;
@@ -937,8 +851,8 @@
         (*pa)->magic = KV5M_PA_DATA;
         (*pa)->pa_type = ap->type;
         if (ap->get_edata) {
-            retval = (ap->get_edata)(kdc_context, request, client, server,
-                                     get_entry_data, ap->plugin_context, *pa);
+            retval = ap->get_edata(kdc_context, request, client, server,
+                                   get_entry_data, ap->moddata, *pa);
             if (retval) {
                 /* just failed on this type, continue */
                 free(*pa);
@@ -1033,8 +947,8 @@
 {
     krb5_error_code retval = 0;
     krb5_pa_data **padata;
-    krb5_preauth_systems *pa_sys;
-    void **pa_context;
+    preauth_system *pa_sys;
+    krb5_kdcpreauth_modreq *modreq_ptr;
     krb5_data *pa_e_data = NULL, *tmp_e_data = NULL;
     int pa_ok = 0, pa_found = 0;
     krb5_error_code saved_retval = 0;
@@ -1058,7 +972,7 @@
 #endif
         if (find_pa_system((*padata)->pa_type, &pa_sys))
             continue;
-        if (find_pa_context(pa_sys, *padata_context, &pa_context))
+        if (find_modreq(pa_sys, *padata_context, &modreq_ptr))
             continue;
 #ifdef DEBUG
         krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name);
@@ -1068,8 +982,9 @@
         pa_found++;
         retval = pa_sys->verify_padata(context, client, req_pkt, request,
                                        enc_tkt_reply, *padata,
-                                       get_entry_data, pa_sys->plugin_context,
-                                       pa_context, &tmp_e_data, &tmp_authz_data);
+                                       get_entry_data, pa_sys->moddata,
+                                       modreq_ptr, &tmp_e_data,
+                                       &tmp_authz_data);
         if (retval) {
             emsg = krb5_get_error_message (context, retval);
             krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s",
@@ -1211,11 +1126,11 @@
     krb5_pa_data **             send_pa;
     krb5_pa_data *              pa = 0;
     krb5_pa_data null_item;
-    krb5_preauth_systems *      ap;
+    preauth_system *            ap;
     int *                       pa_order;
     int *                       pa_type;
     int                         size = 0;
-    void **                     pa_context;
+    krb5_kdcpreauth_modreq      *modreq_ptr;
     krb5_boolean                key_modified;
     krb5_keyblock               original_key;
     if ((!*padata_context) &&
@@ -1265,7 +1180,7 @@
             continue;
         if (ap->return_padata == 0)
             continue;
-        if (find_pa_context(ap, *padata_context, &pa_context))
+        if (find_modreq(ap, *padata_context, &modreq_ptr))
             continue;
         pa = &null_item;
         null_item.pa_type = ap->type;
@@ -1280,8 +1195,8 @@
         if ((retval = ap->return_padata(context, pa, client, req_pkt,
                                         request, reply,
                                         client_key, encrypting_key, send_pa,
-                                        get_entry_data, ap->plugin_context,
-                                        pa_context))) {
+                                        get_entry_data, ap->moddata,
+                                        *modreq_ptr))) {
             goto cleanup;
         }
 
@@ -1320,9 +1235,8 @@
 static krb5_error_code
 get_enc_ts(krb5_context context, krb5_kdc_req *request,
            krb5_db_entry *client, krb5_db_entry *server,
-           preauth_get_entry_data_proc get_entry_data_proc,
-           void *pa_system_context,
-           krb5_pa_data *data)
+           krb5_kdcpreauth_get_data_fn get_entry_data_proc,
+           krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
 {
     struct kdc_request_state *state = request->kdc_state;
     if (state->armor_key)
@@ -1333,12 +1247,11 @@
 
 static krb5_error_code
 verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
-                     krb5_data *req_pkt,
-                     krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
-                     krb5_pa_data *pa,
-                     preauth_get_entry_data_proc ets_get_entry_data,
-                     void *pa_system_context,
-                     void **pa_request_context,
+                     krb5_data *req_pkt, krb5_kdc_req *request,
+                     krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa,
+                     krb5_kdcpreauth_get_data_fn ets_get_entry_data,
+                     krb5_kdcpreauth_moddata moddata,
+                     krb5_kdcpreauth_modreq *modreq_out,
                      krb5_data **e_data,
                      krb5_authdata ***authz_data)
 {
@@ -1580,9 +1493,8 @@
 static krb5_error_code
 get_etype_info(krb5_context context, krb5_kdc_req *request,
                krb5_db_entry *client, krb5_db_entry *server,
-               preauth_get_entry_data_proc etype_get_entry_data,
-               void *pa_system_context,
-               krb5_pa_data *pa_data)
+               krb5_kdcpreauth_get_data_fn etype_get_entry_data,
+               krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data)
 {
     int i;
     for (i=0;  i < request->nktypes; i++) {
@@ -1597,9 +1509,8 @@
 static krb5_error_code
 get_etype_info2(krb5_context context, krb5_kdc_req *request,
                 krb5_db_entry *client, krb5_db_entry *server,
-                preauth_get_entry_data_proc etype_get_entry_data,
-                void *pa_system_context,
-                krb5_pa_data *pa_data)
+                krb5_kdcpreauth_get_data_fn etype_get_entry_data,
+                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data)
 {
     return etype_info_helper( context, request, client, server, pa_data, 1);
 }
@@ -1689,9 +1600,9 @@
                    krb5_key_data *client_key,
                    krb5_keyblock *encrypting_key,
                    krb5_pa_data **send_pa,
-                   preauth_get_entry_data_proc etype_get_entry_data,
-                   void *pa_system_context,
-                   void **pa_request_context)
+                   krb5_kdcpreauth_get_data_fn etype_get_entry_data,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq modreq)
 {
     return etype_info_as_rep_helper(context, padata, client, request, reply,
                                     client_key, encrypting_key, send_pa, 1);
@@ -1706,9 +1617,9 @@
                   krb5_key_data *client_key,
                   krb5_keyblock *encrypting_key,
                   krb5_pa_data **send_pa,
-                  preauth_get_entry_data_proc etypeget_entry_data,
-                  void *pa_system_context,
-                  void **pa_request_context)
+                  krb5_kdcpreauth_get_data_fn etypeget_entry_data,
+                  krb5_kdcpreauth_moddata moddata,
+                  krb5_kdcpreauth_modreq modreq)
 {
     return etype_info_as_rep_helper(context, padata, client, request, reply,
                                     client_key, encrypting_key, send_pa, 0);
@@ -1716,12 +1627,13 @@
 
 static krb5_error_code
 return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
-               krb5_db_entry *client, krb5_data *req_pkt, krb5_kdc_req *request,
-               krb5_kdc_rep *reply, krb5_key_data *client_key,
-               krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
-               preauth_get_entry_data_proc etype_get_entry_data,
-               void *pa_system_context,
-               void **pa_request_context)
+               krb5_db_entry *client, krb5_data *req_pkt,
+               krb5_kdc_req *request, krb5_kdc_rep *reply,
+               krb5_key_data *client_key, krb5_keyblock *encrypting_key,
+               krb5_pa_data **send_pa,
+               krb5_kdcpreauth_get_data_fn etype_get_entry_data,
+               krb5_kdcpreauth_moddata moddata,
+               krb5_kdcpreauth_modreq modreq)
 {
     krb5_error_code     retval;
     krb5_pa_data *      padata;

Modified: trunk/src/kdc/kdc_util.h
===================================================================
--- trunk/src/kdc/kdc_util.h	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/kdc/kdc_util.h	2011-06-17 13:44:33 UTC (rev 24970)
@@ -170,9 +170,9 @@
                        krb5_db_entry *client,
                        krb5_db_entry *server,
                        krb5_data *e_data);
-krb5_error_code
+void
 load_preauth_plugins(krb5_context context);
-krb5_error_code
+void
 unload_preauth_plugins(krb5_context context);
 
 krb5_error_code
@@ -189,8 +189,8 @@
                krb5_key_data *client_key, krb5_keyblock *encrypting_key,
                void **padata_context);
 
-krb5_error_code
-free_padata_context (krb5_context context, void **padata_context);
+void
+free_padata_context(krb5_context context, void *padata_context);
 
 krb5_pa_data *
 find_pa_data (krb5_pa_data **padata, krb5_preauthtype pa_type);

Modified: trunk/src/lib/krb5/krb/copy_ctx.c
===================================================================
--- trunk/src/lib/krb5/krb/copy_ctx.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/copy_ctx.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -79,9 +79,6 @@
     nctx->prompt_types = NULL;
     nctx->os_context.default_ccname = NULL;
 
-    memset(&nctx->preauth_plugins, 0, sizeof(nctx->preauth_plugins));
-    nctx->preauth_context = NULL;
-
     memset(&nctx->libkrb5_plugins, 0, sizeof(nctx->libkrb5_plugins));
     nctx->vtbl = NULL;
     nctx->locate_fptrs = NULL;

Modified: trunk/src/lib/krb5/krb/get_in_tkt.c
===================================================================
--- trunk/src/lib/krb5/krb/get_in_tkt.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/get_in_tkt.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -705,7 +705,7 @@
     code = krb5int_fast_make_state(context, &ctx->fast_state);
     if (code != 0)
         goto cleanup;
-    ctx->get_data_rock.fast_state = ctx->fast_state;
+    ctx->preauth_rock.fast_state = ctx->fast_state;
     krb5_preauth_request_context_init(context);
     if (ctx->encoded_request_body) {
         krb5_free_data(context, ctx->encoded_request_body);
@@ -837,8 +837,8 @@
 
     opte = ctx->opte;
 
-    ctx->get_data_rock.magic = CLIENT_ROCK_MAGIC;
-    ctx->get_data_rock.etype = &ctx->etype;
+    ctx->preauth_rock.magic = CLIENT_ROCK_MAGIC;
+    ctx->preauth_rock.etype = &ctx->etype;
 
     /* Initialise request parameters as per krb5_get_init_creds() */
     ctx->request->kdc_options = context->kdc_default_options;
@@ -1116,7 +1116,7 @@
                                ctx->prompter_data,
                                ctx->gak_fct,
                                ctx->gak_data,
-                               &ctx->get_data_rock,
+                               &ctx->preauth_rock,
                                ctx->opte);
         if (code != 0)
             goto cleanup;
@@ -1141,7 +1141,7 @@
                                             ctx->prompter_data,
                                             ctx->gak_fct,
                                             ctx->gak_data,
-                                            &ctx->get_data_rock,
+                                            &ctx->preauth_rock,
                                             ctx->opte);
         } else {
             /* No preauth supplied, so can't query the plugins. */
@@ -1373,7 +1373,7 @@
                            ctx->prompter_data,
                            ctx->gak_fct,
                            ctx->gak_data,
-                           &ctx->get_data_rock,
+                           &ctx->preauth_rock,
                            ctx->opte);
     if (code != 0)
         goto cleanup;

Modified: trunk/src/lib/krb5/krb/gic_opt_set_pa.c
===================================================================
--- trunk/src/lib/krb5/krb/gic_opt_set_pa.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/gic_opt_set_pa.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -97,50 +97,3 @@
     retval = krb5_preauth_supply_preauth_data(context, opte, attr, value);
     return retval;
 }
-
-/*
- * Give all the preauth plugins a look at the preauth option which
- * has just been set
- */
-krb5_error_code
-krb5_preauth_supply_preauth_data(krb5_context context,
-                                 krb5_gic_opt_ext *opte,
-                                 const char *attr,
-                                 const char *value)
-{
-    krb5_error_code retval = 0;
-    int i;
-    void *pctx;
-    const char *emsg = NULL;
-
-    if (context->preauth_context == NULL)
-        krb5_init_preauth_context(context);
-    if (context->preauth_context == NULL) {
-        retval = EINVAL;
-        krb5int_set_error(&context->err, retval,
-                          _("Unable to initialize preauth context"));
-        return retval;
-    }
-
-    /*
-     * Go down the list of preauth modules, and supply them with the
-     * attribute/value pair.
-     */
-    for (i = 0; i < context->preauth_context->n_modules; i++) {
-        if (context->preauth_context->modules[i].client_supply_gic_opts == NULL)
-            continue;
-        pctx = context->preauth_context->modules[i].plugin_context;
-        retval = (*context->preauth_context->modules[i].client_supply_gic_opts)
-            (context, pctx,
-             (krb5_get_init_creds_opt *)opte, attr, value);
-        if (retval) {
-            emsg = krb5_get_error_message(context, retval);
-            krb5int_set_error(&context->err, retval,
-                              _("Preauth plugin %s: %s"),
-                              context->preauth_context->modules[i].name, emsg);
-            krb5_free_error_message(context, emsg);
-            break;
-        }
-    }
-    return retval;
-}

Modified: trunk/src/lib/krb5/krb/init_creds_ctx.h
===================================================================
--- trunk/src/lib/krb5/krb/init_creds_ctx.h	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/init_creds_ctx.h	2011-06-17 13:44:33 UTC (rev 24970)
@@ -29,7 +29,7 @@
     krb5_data s2kparams;
     krb5_keyblock as_key;
     krb5_enctype etype;
-    krb5_preauth_client_rock get_data_rock;
+    struct krb5_clpreauth_rock_st preauth_rock;
     krb5_boolean enc_pa_rep_permitted;
     krb5_boolean have_restarted;
     krb5_boolean sent_nontrivial_preauth;

Modified: trunk/src/lib/krb5/krb/plugin.c
===================================================================
--- trunk/src/lib/krb5/krb/plugin.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/plugin.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -28,7 +28,9 @@
 
 const char *interface_names[PLUGIN_NUM_INTERFACES] = {
     "pwqual",
-    "kadm5_hook"
+    "kadm5_hook",
+    "clpreauth",
+    "kdcpreauth"
 };
 
 /* Return the context's interface structure for id, or NULL if invalid. */

Modified: trunk/src/lib/krb5/krb/preauth2.c
===================================================================
--- trunk/src/lib/krb5/krb/preauth2.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/krb/preauth2.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -44,13 +44,41 @@
 #include <unistd.h>
 #endif
 
-#if TARGET_OS_MAC
-static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR,
-                                 LIBDIR "/krb5/plugins/preauth",
-                                 NULL };
-#else
-static const char *objdirs[] = { LIBDIR "/krb5/plugins/preauth", NULL };
-#endif
+/* This structure lets us keep track of all of the modules which are loaded,
+ * turning the list of modules and their lists of implemented preauth types
+ * into a single list which we can walk easily. */
+struct krb5_preauth_context_st {
+    int n_modules;
+    struct krb5_preauth_context_module_st {
+        /* Which of the possibly more than one preauth types which the
+         * module supports we're using at this point in the list. */
+        krb5_preauthtype pa_type;
+        /* Encryption types which the client claims to support -- we
+         * copy them directly into the krb5_kdc_req structure during
+         * krb5_preauth_prepare_request(). */
+        krb5_enctype *enctypes;
+        /* The plugin's module data and a function to clear it. */
+        krb5_clpreauth_moddata moddata;
+        krb5_clpreauth_fini_fn client_fini;
+        /* The module's table, and some of its members, copied here for
+         * convenience when we populated the list. */
+        const char *name;
+        int flags, use_count;
+        krb5_clpreauth_process_fn client_process;
+        krb5_clpreauth_tryagain_fn client_tryagain;
+        krb5_clpreauth_supply_gic_opts_fn client_supply_gic_opts;
+        krb5_clpreauth_request_init_fn client_req_init;
+        krb5_clpreauth_request_fini_fn client_req_fini;
+        /* The per-request context which the client_req_init() function
+         * might allocate, which we'll need to clean up later by
+         * calling the client_req_fini() function. */
+        krb5_clpreauth_modreq modreq;
+        /* A pointer to the request_context pointer.  All modules within
+         * a plugin will point at the request_context of the first
+         * module within the plugin. */
+        krb5_clpreauth_modreq *modreq_p;
+    } *modules;
+};
 
 typedef krb5_error_code (*pa_function)(krb5_context,
                                        krb5_kdc_req *request,
@@ -70,27 +98,6 @@
     int flags;
 } pa_types_t;
 
-/* Open plugin directories for preauth modules. */
-static krb5_error_code
-open_preauth_plugin_dirs(krb5_context ctx)
-{
-    static const char *path[] = {
-        KRB5_CONF_LIBDEFAULTS, KRB5_CONF_PREAUTH_MODULE_DIR, NULL,
-    };
-    char **profpath = NULL;
-    const char **dirs;
-    krb5_error_code ret;
-
-    ret = profile_get_values(ctx->profile, path, &profpath);
-    if (ret != 0 && ret != PROF_NO_RELATION)
-        return ret;
-    dirs = (profpath != NULL) ? (const char **) profpath : objdirs;
-    ret = krb5int_open_plugin_dirs(dirs, NULL, &ctx->preauth_plugins,
-                                   &ctx->err);
-    profile_free_list(profpath);
-    return ret;
-}
-
 /* Create the per-krb5_context context. This means loading the modules
  * if we haven't done that yet (applications which never obtain initial
  * credentials should never hit this routine), breaking up the module's
@@ -99,101 +106,88 @@
 void KRB5_CALLCONV
 krb5_init_preauth_context(krb5_context kcontext)
 {
-    int n_modules, n_tables, i, j, k;
-    void **tables;
-    struct krb5plugin_preauth_client_ftable_v1 *table;
+    int n_tables, n_modules, i, count;
+    krb5_plugin_initvt_fn *plugins = NULL, *pl;
+    struct krb5_clpreauth_vtable_st *vtables = NULL, *vt;
+    struct krb5_preauth_context_module_st *mod;
     krb5_preauth_context *context = NULL;
-    void *plugin_context;
-    krb5_preauthtype pa_type;
-    void **rcpp;
+    krb5_clpreauth_moddata moddata;
+    krb5_preauthtype pa_type, *pat;
+    krb5_boolean first;
+    krb5_clpreauth_modreq *rcpp;
 
     /* Only do this once for each krb5_context */
     if (kcontext->preauth_context != NULL)
         return;
 
-    /* load the plugins for the current context */
-    if (PLUGIN_DIR_OPEN(&kcontext->preauth_plugins) == 0) {
-        if (open_preauth_plugin_dirs(kcontext) != 0)
-            return;
-    }
+    /* Auto-register pkinit and encrypted challenge if possible. */
+    k5_plugin_register_dyn(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "pkinit",
+                           "preauth");
+    k5_plugin_register_dyn(kcontext, PLUGIN_INTERFACE_CLPREAUTH,
+                           "encrypted_challenge", "preauth");
 
-    /* pull out the module function tables for all of the modules */
-    tables = NULL;
-    if (krb5int_get_plugin_dir_data(&kcontext->preauth_plugins,
-                                    "preauthentication_client_1",
-                                    &tables,
-                                    &kcontext->err) != 0) {
+    /* Get all available clpreauth vtables. */
+    if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins))
         return;
+    for (count = 0; plugins[count] != NULL; count++);
+    vtables = calloc(count, sizeof(*vtables));
+    if (vtables == NULL)
+        goto cleanup;
+    for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
+        if ((*pl)(kcontext, 1, 1, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
+            n_tables++;
     }
-    if (tables == NULL) {
-        return;
-    }
 
-    /* count how many modules we ended up loading, and how many preauth
-     * types we may claim to support as a result */
+    /* Count how many modules we ended up loading, and how many preauth
+     * types we may claim to support as a result. */
     n_modules = 0;
-    for (n_tables = 0;
-         (tables != NULL) && (tables[n_tables] != NULL);
-         n_tables++) {
-        table = tables[n_tables];
-        if ((table->pa_type_list != NULL) && (table->process != NULL)) {
-            for (j = 0; table->pa_type_list[j] > 0; j++) {
-                n_modules++;
-            }
-        }
+    for (i = 0; i < n_tables; i++) {
+        for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
+        n_modules += count;
     }
 
-    /* allocate the space we need */
+    /* Allocate the space we need. */
     context = malloc(sizeof(*context));
-    if (context == NULL) {
-        krb5int_free_plugin_dir_data(tables);
-        return;
-    }
-    context->modules = calloc(n_modules, sizeof(context->modules[0]));
-    if (context->modules == NULL) {
-        krb5int_free_plugin_dir_data(tables);
-        free(context);
-        return;
-    }
-    context->n_modules = n_modules;
+    if (context == NULL)
+        goto cleanup;
+    context->modules = calloc(n_modules, sizeof(*context->modules));
+    if (context->modules == NULL)
+        goto cleanup;
 
     /* fill in the structure */
-    k = 0;
+    n_modules = 0;
     for (i = 0; i < n_tables; i++) {
-        table = tables[i];
-        if ((table->pa_type_list != NULL) && (table->process != NULL)) {
-            plugin_context = NULL;
-            if ((table->init != NULL) &&
-                ((*table->init)(kcontext, &plugin_context) != 0)) {
+        vt = &vtables[i];
+        if ((vt->pa_type_list != NULL) && (vt->process != NULL)) {
+            moddata = NULL;
+            if (vt->init != NULL && vt->init(kcontext, &moddata) != 0) {
 #ifdef DEBUG
-                fprintf (stderr, "init err, skipping module \"%s\"\n",
-                         table->name);
+                fprintf(stderr, "init err, skipping module \"%s\"\n",
+                        vt->name);
 #endif
                 continue;
             }
 
             rcpp = NULL;
-            for (j = 0; table->pa_type_list[j] > 0; j++) {
-                pa_type = table->pa_type_list[j];
-                context->modules[k].pa_type = pa_type;
-                context->modules[k].enctypes = table->enctype_list;
-                context->modules[k].plugin_context = plugin_context;
+            for (pat = vt->pa_type_list, first = TRUE; *pat > 0;
+                 pat++, first = FALSE) {
+                pa_type = *pat;
+                mod = &context->modules[n_modules];
+                mod->pa_type = pa_type;
+                mod->enctypes = vt->enctype_list;
+                mod->moddata = moddata;
                 /* Only call client_fini once per plugin */
-                if (j == 0)
-                    context->modules[k].client_fini = table->fini;
+                if (first)
+                    mod->client_fini = vt->fini;
                 else
-                    context->modules[k].client_fini = NULL;
-                context->modules[k].ftable = table;
-                context->modules[k].name = table->name;
-                context->modules[k].flags = (*table->flags)(kcontext, pa_type);
-                context->modules[k].use_count = 0;
-                context->modules[k].client_process = table->process;
-                context->modules[k].client_tryagain = table->tryagain;
-                if (j == 0)
-                    context->modules[k].client_supply_gic_opts = table->gic_opts;
-                else
-                    context->modules[k].client_supply_gic_opts = NULL;
-                context->modules[k].request_context = NULL;
+                    mod->client_fini = NULL;
+                mod->name = vt->name;
+                mod->flags = (*vt->flags)(kcontext, pa_type);
+                mod->use_count = 0;
+                mod->client_process = vt->process;
+                mod->client_tryagain = vt->tryagain;
+                mod->client_supply_gic_opts = first ? vt->gic_opts : NULL;
+                mod->modreq = NULL;
                 /*
                  * Only call request_init and request_fini once per plugin.
                  * Only the first module within each plugin will ever
@@ -202,29 +196,35 @@
                  * to that entry's request_context.  That way all the
                  * modules within the plugin share the same request_context
                  */
-                if (j == 0) {
-                    context->modules[k].client_req_init = table->request_init;
-                    context->modules[k].client_req_fini = table->request_fini;
-                    rcpp = &context->modules[k].request_context;
+                if (first) {
+                    mod->client_req_init = vt->request_init;
+                    mod->client_req_fini = vt->request_fini;
+                    rcpp = &mod->modreq;
                 } else {
-                    context->modules[k].client_req_init = NULL;
-                    context->modules[k].client_req_fini = NULL;
+                    mod->client_req_init = NULL;
+                    mod->client_req_fini = NULL;
                 }
-                context->modules[k].request_context_pp = rcpp;
+                mod->modreq_p = rcpp;
 #ifdef DEBUG
-                fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n",
-                         context->modules[k].name,
-                         context->modules[k].pa_type,
-                         context->modules[k].flags);
+                fprintf(stderr, "init module \"%s\", pa_type %d, flag %d\n",
+                        mod->name, mod->pa_type, mod->flags);
 #endif
-                k++;
+                n_modules++;
             }
         }
     }
-    krb5int_free_plugin_dir_data(tables);
+    context->n_modules = n_modules;
 
-    /* return the result */
+    /* Place the constructed preauth context into the krb5 context. */
     kcontext->preauth_context = context;
+    context = NULL;
+
+cleanup:
+    if (context)
+        free(context->modules);
+    free(context);
+    k5_plugin_free_modules(kcontext, plugins);
+    free(vtables);
 }
 
 /* Zero the use counts for the modules herein.  Usually used before we
@@ -249,23 +249,19 @@
 krb5_free_preauth_context(krb5_context context)
 {
     int i;
-    void *pctx;
-    if (context && context->preauth_context != NULL) {
-        for (i = 0; i < context->preauth_context->n_modules; i++) {
-            pctx = context->preauth_context->modules[i].plugin_context;
-            if (context->preauth_context->modules[i].client_fini != NULL) {
-                (*context->preauth_context->modules[i].client_fini)(context, pctx);
-            }
-            memset(&context->preauth_context->modules[i], 0,
-                   sizeof(context->preauth_context->modules[i]));
-        }
-        if (context->preauth_context->modules != NULL) {
-            free(context->preauth_context->modules);
-            context->preauth_context->modules = NULL;
-        }
-        free(context->preauth_context);
-        context->preauth_context = NULL;
+    struct krb5_preauth_context_module_st *mod;
+
+    if (context == NULL || context->preauth_context == NULL)
+        return;
+    for (i = 0; i < context->preauth_context->n_modules; i++) {
+        mod = &context->preauth_context->modules[i];
+        if (mod->client_fini != NULL)
+            mod->client_fini(context, mod->moddata);
+        zap(mod, sizeof(*mod));
     }
+    free(context->preauth_context->modules);
+    free(context->preauth_context);
+    context->preauth_context = NULL;
 }
 
 /* Initialize the per-AS-REQ context. This means calling the client_req_init
@@ -274,19 +270,16 @@
 krb5_preauth_request_context_init(krb5_context context)
 {
     int i;
-    void *rctx, *pctx;
+    struct krb5_preauth_context_module_st *mod;
 
-    /* Limit this to only one attempt per context? */
     if (context->preauth_context == NULL)
         krb5_init_preauth_context(context);
-    if (context->preauth_context != NULL) {
-        for (i = 0; i < context->preauth_context->n_modules; i++) {
-            pctx = context->preauth_context->modules[i].plugin_context;
-            if (context->preauth_context->modules[i].client_req_init != NULL) {
-                rctx = context->preauth_context->modules[i].request_context_pp;
-                (*context->preauth_context->modules[i].client_req_init) (context, pctx, rctx);
-            }
-        }
+    if (context->preauth_context == NULL)
+        return;
+    for (i = 0; i < context->preauth_context->n_modules; i++) {
+        mod = &context->preauth_context->modules[i];
+        if (mod->client_req_init != NULL)
+            mod->client_req_init(context, mod->moddata, mod->modreq_p);
     }
 }
 
@@ -296,17 +289,16 @@
 krb5_preauth_request_context_fini(krb5_context context)
 {
     int i;
-    void *rctx, *pctx;
-    if (context->preauth_context != NULL) {
-        for (i = 0; i < context->preauth_context->n_modules; i++) {
-            pctx = context->preauth_context->modules[i].plugin_context;
-            rctx = context->preauth_context->modules[i].request_context;
-            if (rctx != NULL) {
-                if (context->preauth_context->modules[i].client_req_fini != NULL) {
-                    (*context->preauth_context->modules[i].client_req_fini)(context, pctx, rctx);
-                }
-                context->preauth_context->modules[i].request_context = NULL;
-            }
+    struct krb5_preauth_context_module_st *mod;
+
+    if (context->preauth_context == NULL)
+        return;
+    for (i = 0; i < context->preauth_context->n_modules; i++) {
+        mod = &context->preauth_context->modules[i];
+        if (mod->modreq != NULL) {
+            if (mod->client_req_fini != NULL)
+                mod->client_req_fini(context, mod->moddata, mod->modreq);
+            mod->modreq = NULL;
         }
     }
 }
@@ -390,10 +382,8 @@
  */
 
 static krb5_error_code
-client_data_proc(krb5_context kcontext,
-                 krb5_preauth_client_rock *rock,
-                 krb5_int32 request_type,
-                 krb5_data **retdata)
+client_data_proc(krb5_context kcontext, krb5_clpreauth_rock rock,
+                 krb5_int32 request_type, krb5_data **retdata)
 {
     krb5_data *ret;
     krb5_error_code retval;
@@ -405,7 +395,7 @@
         return EINVAL;
 
     switch (request_type) {
-    case krb5plugin_preauth_client_get_etype:
+    case krb5_clpreauth_get_etype:
     {
         krb5_enctype *eptr;
         ret = malloc(sizeof(krb5_data));
@@ -424,7 +414,7 @@
         return 0;
     }
     break;
-    case krb5plugin_preauth_client_free_etype:
+    case krb5_clpreauth_free_etype:
         ret = *retdata;
         if (ret == NULL)
             return 0;
@@ -433,7 +423,7 @@
         free(ret);
         return 0;
         break;
-    case krb5plugin_preauth_client_fast_armor: {
+    case krb5_clpreauth_fast_armor: {
         krb5_keyblock *key = NULL;
         ret = calloc(1, sizeof(krb5_data));
         if (ret == NULL)
@@ -455,7 +445,7 @@
             free(ret);
         return retval;
     }
-    case krb5plugin_preauth_client_free_fast_armor:
+    case krb5_clpreauth_free_fast_armor:
         ret = *retdata;
         if (ret) {
             if (ret->data)
@@ -508,11 +498,11 @@
                     krb5_pa_data *in_padata,
                     krb5_prompter_fct prompter,
                     void *prompter_data,
-                    preauth_get_as_key_proc gak_fct,
+                    krb5_clpreauth_get_as_key_fn gak_fct,
                     krb5_data *salt,
                     krb5_data *s2kparams,
                     void *gak_data,
-                    krb5_preauth_client_rock *get_data_rock,
+                    krb5_clpreauth_rock preauth_rock,
                     krb5_keyblock *as_key,
                     krb5_pa_data ***out_pa_list,
                     int *out_pa_list_size,
@@ -523,7 +513,7 @@
     int i;
     krb5_pa_data **out_pa_data;
     krb5_error_code ret;
-    struct _krb5_preauth_context_module *module;
+    struct krb5_preauth_context_module_st *module;
 
     if (kcontext->preauth_context == NULL) {
         return ENOENT;
@@ -551,19 +541,14 @@
         fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
                 module->name, module->pa_type, module->flags);
 #endif
-        ret = module->client_process(kcontext,
-                                     module->plugin_context,
-                                     *module->request_context_pp,
+        ret = module->client_process(kcontext, module->moddata,
+                                     *module->modreq_p,
                                      (krb5_get_init_creds_opt *)opte,
-                                     client_data_proc,
-                                     get_data_rock,
-                                     request,
-                                     encoded_request_body,
-                                     encoded_previous_request,
-                                     in_padata,
-                                     prompter, prompter_data,
-                                     gak_fct, gak_data, salt, s2kparams,
-                                     as_key,
+                                     client_data_proc, preauth_rock,
+                                     request, encoded_request_body,
+                                     encoded_previous_request, in_padata,
+                                     prompter, prompter_data, gak_fct,
+                                     gak_data, salt, s2kparams, as_key,
                                      &out_pa_data);
         TRACE_PREAUTH_PROCESS(kcontext, module->name, module->pa_type,
                               module->flags, ret);
@@ -1517,13 +1502,13 @@
                          krb5_keyblock *as_key,
                          krb5_prompter_fct prompter, void *prompter_data,
                          krb5_gic_get_as_key_fct gak_fct, void *gak_data,
-                         krb5_preauth_client_rock *get_data_rock,
+                         krb5_clpreauth_rock preauth_rock,
                          krb5_gic_opt_ext *opte)
 {
     krb5_error_code ret;
     krb5_pa_data **out_padata;
     krb5_preauth_context *context;
-    struct _krb5_preauth_context_module *module;
+    struct krb5_preauth_context_module_st *module;
     int i, j;
     int out_pa_list_size = 0;
 
@@ -1548,12 +1533,11 @@
             if (module->client_tryagain == NULL) {
                 continue;
             }
-            if ((*module->client_tryagain)(kcontext,
-                                           module->plugin_context,
-                                           *module->request_context_pp,
+            if ((*module->client_tryagain)(kcontext, module->moddata,
+                                           *module->modreq_p,
                                            (krb5_get_init_creds_opt *)opte,
                                            client_data_proc,
-                                           get_data_rock,
+                                           preauth_rock,
                                            request,
                                            encoded_request_body,
                                            encoded_previous_request,
@@ -1589,8 +1573,7 @@
                 krb5_keyblock *as_key,
                 krb5_prompter_fct prompter, void *prompter_data,
                 krb5_gic_get_as_key_fct gak_fct, void *gak_data,
-                krb5_preauth_client_rock *get_data_rock,
-                krb5_gic_opt_ext *opte)
+                krb5_clpreauth_rock preauth_rock, krb5_gic_opt_ext *opte)
 {
     unsigned int h;
     int i, j, out_pa_list_size;
@@ -1769,7 +1752,7 @@
                                               gak_fct,
                                               salt, s2kparams,
                                               gak_data,
-                                              get_data_rock,
+                                              preauth_rock,
                                               as_key,
                                               &out_pa_list,
                                               &out_pa_list_size,
@@ -1803,3 +1786,47 @@
         krb5_free_etype_info(context, etype_info);
     return (ret);
 }
+
+/*
+ * Give all the preauth plugins a look at the preauth option which
+ * has just been set
+ */
+krb5_error_code
+krb5_preauth_supply_preauth_data(krb5_context context, krb5_gic_opt_ext *opte,
+                                 const char *attr, const char *value)
+{
+    krb5_error_code retval = 0;
+    int i;
+    struct krb5_preauth_context_module_st *mod;
+    const char *emsg = NULL;
+
+    if (context->preauth_context == NULL)
+        krb5_init_preauth_context(context);
+    if (context->preauth_context == NULL) {
+        retval = EINVAL;
+        krb5_set_error_message(context, retval,
+                               _("Unable to initialize preauth context"));
+        return retval;
+    }
+
+    /*
+     * Go down the list of preauth modules, and supply them with the
+     * attribute/value pair.
+     */
+    for (i = 0; i < context->preauth_context->n_modules; i++) {
+        mod = &context->preauth_context->modules[i];
+        if (mod->client_supply_gic_opts == NULL)
+            continue;
+        retval = mod->client_supply_gic_opts(context, mod->moddata,
+                                             (krb5_get_init_creds_opt *)opte,
+                                             attr, value);
+        if (retval) {
+            emsg = krb5_get_error_message(context, retval);
+            krb5_set_error_message(context, retval, _("Preauth plugin %s: %s"),
+                                   mod->name, emsg);
+            krb5_free_error_message(context, emsg);
+            break;
+        }
+    }
+    return retval;
+}

Modified: trunk/src/lib/krb5/libkrb5.exports
===================================================================
--- trunk/src/lib/krb5/libkrb5.exports	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/libkrb5.exports	2011-06-17 13:44:33 UTC (rev 24970)
@@ -114,6 +114,7 @@
 k5_plugin_load
 k5_plugin_load_all
 k5_plugin_register
+k5_plugin_register_dyn
 krb524_convert_creds_kdc
 krb524_init_ets
 krb5_425_conv_principal

Modified: trunk/src/lib/krb5/os/init_os_ctx.c
===================================================================
--- trunk/src/lib/krb5/os/init_os_ctx.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/lib/krb5/os/init_os_ctx.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -376,7 +376,6 @@
 
     ctx->vtbl = 0;
     PLUGIN_DIR_INIT(&ctx->libkrb5_plugins);
-    PLUGIN_DIR_INIT(&ctx->preauth_plugins);
     ctx->preauth_context = NULL;
 
     retval = os_init_paths(ctx, kdc);
@@ -477,7 +476,6 @@
         krb5_free_preauth_context(ctx);
         ctx->preauth_context = NULL;
     }
-    krb5int_close_plugin_dirs (&ctx->preauth_plugins);
     krb5int_close_plugin_dirs (&ctx->libkrb5_plugins);
 
 #ifdef _WIN32

Modified: trunk/src/plugins/preauth/cksum_body/cksum_body.exports
===================================================================
--- trunk/src/plugins/preauth/cksum_body/cksum_body.exports	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/cksum_body/cksum_body.exports	2011-06-17 13:44:33 UTC (rev 24970)
@@ -1,2 +1,2 @@
-preauthentication_client_1
-preauthentication_server_1
+clpreauth_cksum_body_initvt
+kdcpreauth_cksum_body_initvt

Modified: trunk/src/plugins/preauth/cksum_body/cksum_body_main.c
===================================================================
--- trunk/src/plugins/preauth/cksum_body/cksum_body_main.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/cksum_body/cksum_body_main.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -80,18 +80,18 @@
 
 static krb5_error_code
 client_process(krb5_context kcontext,
-               void *client_plugin_context,
-               void *client_request_context,
+               krb5_clpreauth_moddata moddata,
+               krb5_clpreauth_modreq modreq,
                krb5_get_init_creds_opt *opt,
-               preauth_get_client_data_proc client_get_data_proc,
-               struct _krb5_preauth_client_rock *rock,
+               krb5_clpreauth_get_data_fn client_get_data_proc,
+               krb5_clpreauth_rock rock,
                krb5_kdc_req *request,
                krb5_data *encoded_request_body,
                krb5_data *encoded_previous_request,
                krb5_pa_data *pa_data,
                krb5_prompter_fct prompter,
                void *prompter_data,
-               preauth_get_as_key_proc gak_fct,
+               krb5_clpreauth_get_as_key_fn gak_fct,
                void *gak_data,
                krb5_data *salt, krb5_data *s2kparams,
                krb5_keyblock *as_key,
@@ -229,7 +229,7 @@
 
 static krb5_error_code
 client_gic_opt(krb5_context kcontext,
-               void *plugin_context,
+               krb5_clpreauth_moddata moddata,
                krb5_get_init_creds_opt *opt,
                const char *attr,
                const char *value)
@@ -243,7 +243,8 @@
 
 /* Initialize and tear down the server-side module, and do stat tracking. */
 static krb5_error_code
-server_init(krb5_context kcontext, void **module_context, const char **realmnames)
+server_init(krb5_context kcontext, krb5_kdcpreauth_moddata *moddata_out,
+            const char **realmnames)
 {
     struct server_stats *stats;
     stats = malloc(sizeof(struct server_stats));
@@ -251,14 +252,14 @@
         return ENOMEM;
     stats->successes = 0;
     stats->failures = 0;
-    *module_context = stats;
+    *moddata_out = (krb5_kdcpreauth_moddata)stats;
     return 0;
 }
 static void
-server_fini(krb5_context kcontext, void *module_context)
+server_fini(krb5_context kcontext, krb5_kdcpreauth_moddata moddata)
 {
     struct server_stats *stats;
-    stats = module_context;
+    stats = (struct server_stats *)moddata;
     if (stats != NULL) {
 #ifdef DEBUG
         fprintf(stderr, "Total: %d clients failed, %d succeeded.\n",
@@ -275,8 +276,8 @@
                  krb5_kdc_req *request,
                  struct _krb5_db_entry_new *client,
                  struct _krb5_db_entry_new *server,
-                 preauth_get_entry_data_proc server_get_entry_data,
-                 void *pa_module_context,
+                 krb5_kdcpreauth_get_data_fn server_get_entry_data,
+                 krb5_kdcpreauth_moddata moddata,
                  krb5_pa_data *data)
 {
     krb5_data *key_data;
@@ -287,7 +288,7 @@
     /* Retrieve the client's keys. */
     key_data = NULL;
     if ((*server_get_entry_data)(kcontext, request, client,
-                                 krb5plugin_preauth_keys, &key_data) != 0) {
+                                 krb5_kdcpreauth_keys, &key_data) != 0) {
 #ifdef DEBUG
         fprintf(stderr, "Error retrieving client keys.\n");
 #endif
@@ -335,9 +336,9 @@
               krb5_kdc_req *request,
               krb5_enc_tkt_part *enc_tkt_reply,
               krb5_pa_data *data,
-              preauth_get_entry_data_proc server_get_entry_data,
-              void *pa_module_context,
-              void **pa_request_context,
+              krb5_kdcpreauth_get_data_fn server_get_entry_data,
+              krb5_kdcpreauth_moddata moddata,
+              krb5_kdcpreauth_modreq *modreq_out,
               krb5_data **e_data,
               krb5_authdata ***authz_data)
 {
@@ -356,7 +357,7 @@
     test_svr_req_ctx *svr_req_ctx;
     krb5_authdata **my_authz_data = NULL;
 
-    stats = pa_module_context;
+    stats = (struct server_stats *)moddata;
 
 #ifdef DEBUG
     fprintf(stderr, "cksum_body: server_verify\n");
@@ -392,7 +393,7 @@
     /* Pull up the client's keys. */
     key_data = NULL;
     if ((*server_get_entry_data)(kcontext, request, client,
-                                 krb5plugin_preauth_keys, &key_data) != 0) {
+                                 krb5_kdcpreauth_keys, &key_data) != 0) {
 #ifdef DEBUG
         fprintf(stderr, "Error retrieving client keys.\n");
 #endif
@@ -449,7 +450,7 @@
      * will probably work if it's us on both ends, though. */
     req_body = NULL;
     if ((*server_get_entry_data)(kcontext, request, client,
-                                 krb5plugin_preauth_request_body,
+                                 krb5_kdcpreauth_request_body,
                                  &req_body) != 0) {
         krb5_free_keyblock(kcontext, key);
         stats->failures++;
@@ -572,7 +573,7 @@
                 svr_req_ctx);
 #endif
     }
-    *pa_request_context = svr_req_ctx;
+    *modreq_out = (krb5_kdcpreauth_modreq)svr_req_ctx;
 
     /* Note that preauthentication succeeded. */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
@@ -591,9 +592,9 @@
               struct _krb5_key_data *client_key,
               krb5_keyblock *encrypting_key,
               krb5_pa_data **send_pa,
-              preauth_get_entry_data_proc server_get_entry_data,
-              void *pa_module_context,
-              void **pa_request_context)
+              krb5_kdcpreauth_get_data_fn server_get_entry_data,
+              krb5_kdcpreauth_moddata moddata,
+              krb5_kdcpreauth_modreq modreq)
 {
     /* We don't need to send data back on the return trip. */
     *send_pa = NULL;
@@ -601,34 +602,32 @@
 }
 
 /* Test server request context freeing */
-static krb5_error_code
-server_free_reqctx(krb5_context kcontext,
-                   void *pa_module_context,
-                   void **pa_request_context)
+static void
+server_free_modreq(krb5_context kcontext,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq modreq)
 {
     test_svr_req_ctx *svr_req_ctx;
 #ifdef DEBUG
-    fprintf(stderr, "server_free_reqctx: entered!\n");
+    fprintf(stderr, "server_free_modreq: entered!\n");
 #endif
-    if (pa_request_context == NULL)
-        return 0;
+    if (modreq == NULL)
+        return;
 
-    svr_req_ctx = *pa_request_context;
+    svr_req_ctx = (test_svr_req_ctx *)modreq;
     if (svr_req_ctx == NULL)
-        return 0;
+        return;
 
     if (svr_req_ctx->value1 != 111111 || svr_req_ctx->value2 != 222222) {
-        fprintf(stderr, "server_free_reqctx: got invalid req context "
+        fprintf(stderr, "server_free_modreq: got invalid req context "
                 "at %p with values %d and %d\n",
                 svr_req_ctx, svr_req_ctx->value1, svr_req_ctx->value2);
-        return EINVAL;
+        return;
     }
 #ifdef DEBUG
-    fprintf(stderr, "server_free_reqctx: freeing context at %p\n", svr_req_ctx);
+    fprintf(stderr, "server_free_modreq: freeing context at %p\n", svr_req_ctx);
 #endif
     free(svr_req_ctx);
-    *pa_request_context = NULL;
-    return 0;
 }
 
 static int
@@ -644,28 +643,47 @@
     KRB5_PADATA_CKSUM_BODY_REQ, 0,
 };
 
-struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = {
-    "cksum_body",                           /* name */
-    &supported_client_pa_types[0],          /* pa_type_list */
-    NULL,                                   /* enctype_list */
-    NULL,                                   /* plugin init function */
-    NULL,                                   /* plugin fini function */
-    client_get_flags,                       /* get flags function */
-    NULL,                                   /* request init function */
-    NULL,                                   /* request fini function */
-    client_process,                         /* process function */
-    NULL,                                   /* try_again function */
-    client_gic_opt                          /* get init creds opt function */
-};
+krb5_error_code
+clpreauth_cksum_body_initvt(krb5_context context, int maj_ver,
+                            int min_ver, krb5_plugin_vtable vtable);
+krb5_error_code
+kdcpreauth_cksum_body_initvt(krb5_context context, int maj_ver,
+                             int min_ver, krb5_plugin_vtable vtable);
 
-struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
-    "cksum_body",
-    &supported_server_pa_types[0],
-    server_init,
-    server_fini,
-    server_get_flags,
-    server_get_edata,
-    server_verify,
-    server_return,
-    server_free_reqctx
-};
+krb5_error_code
+clpreauth_cksum_body_initvt(krb5_context context, int maj_ver,
+                            int min_ver, krb5_plugin_vtable vtable)
+{
+    krb5_clpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_clpreauth_vtable)vtable;
+    vt->name = "cksum_body";
+    vt->pa_type_list = supported_client_pa_types;
+    vt->flags = client_get_flags;
+    vt->process = client_process;
+    vt->gic_opts = client_gic_opt;
+    return 0;
+}
+
+krb5_error_code
+kdcpreauth_cksum_body_initvt(krb5_context context, int maj_ver,
+                             int min_ver, krb5_plugin_vtable vtable)
+{
+    krb5_kdcpreauth_vtable vt;
+
+    if (maj_ver != -1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_kdcpreauth_vtable)vtable;
+    vt->name = "cksum_body";
+    vt->pa_type_list = supported_server_pa_types;
+    vt->init = server_init;
+    vt->fini = server_fini;
+    vt->flags = server_get_flags;
+    vt->edata = server_get_edata;
+    vt->verify = server_verify;
+    vt->return_padata = server_return;
+    vt->free_modreq = server_free_modreq;
+    return 0;
+}

Modified: trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports
===================================================================
--- trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge.exports	2011-06-17 13:44:33 UTC (rev 24970)
@@ -1,2 +1,2 @@
-preauthentication_client_1
-preauthentication_server_1
+clpreauth_encrypted_challenge_initvt
+kdcpreauth_encrypted_challenge_initvt

Modified: trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c
===================================================================
--- trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -41,14 +41,14 @@
 }
 
 static krb5_error_code
-process_preauth(krb5_context context, void *plugin_context,
-                void *request_context, krb5_get_init_creds_opt *opt,
-                preauth_get_client_data_proc get_data_proc,
-                struct _krb5_preauth_client_rock *rock, krb5_kdc_req *request,
+process_preauth(krb5_context context, krb5_clpreauth_moddata moddata,
+                krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
+                krb5_clpreauth_get_data_fn get_data_proc,
+                krb5_clpreauth_rock rock, krb5_kdc_req *request,
                 krb5_data *encoded_request_body,
                 krb5_data *encoded_previous_request, krb5_pa_data *padata,
                 krb5_prompter_fct prompter, void *prompter_data,
-                preauth_get_as_key_proc gak_fct, void *gak_data,
+                krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data,
                 krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key,
                 krb5_pa_data ***out_padata)
 {
@@ -63,7 +63,8 @@
     retval = fast_get_armor_key(context, get_data_proc, rock, &armor_key);
     if (retval || armor_key == NULL)
         return 0;
-    retval = get_data_proc(context, rock, krb5plugin_preauth_client_get_etype, &etype_data);
+    retval = get_data_proc(context, rock, krb5_clpreauth_get_etype,
+                           &etype_data);
     if (retval == 0) {
         enctype = *((krb5_enctype *)etype_data->data);
         if (as_key->length == 0 ||as_key->enctype != enctype)
@@ -163,8 +164,7 @@
     if (armor_key)
         krb5_free_keyblock(context, armor_key);
     if (etype_data != NULL)
-        get_data_proc(context, rock, krb5plugin_preauth_client_free_etype,
-                      &etype_data);
+        get_data_proc(context, rock, krb5_clpreauth_free_etype, &etype_data);
     return retval;
 }
 
@@ -173,12 +173,13 @@
 kdc_include_padata(krb5_context context, krb5_kdc_req *request,
                    struct _krb5_db_entry_new *client,
                    struct _krb5_db_entry_new *server,
-                   preauth_get_entry_data_proc get_entry_proc,
-                   void *pa_module_context, krb5_pa_data *data)
+                   krb5_kdcpreauth_get_data_fn get_data_proc,
+                   krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
 {
     krb5_error_code retval = 0;
     krb5_keyblock *armor_key = NULL;
-    retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key);
+    retval = fast_kdc_get_armor_key(context, get_data_proc, request, client,
+                                    &armor_key);
     if (retval)
         return retval;
     if (armor_key == 0)
@@ -191,8 +192,9 @@
 kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
                    krb5_data *req_pkt, krb5_kdc_req *request,
                    krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,
-                   preauth_get_entry_data_proc get_entry_proc,
-                   void *pa_module_context, void **pa_request_context,
+                   krb5_kdcpreauth_get_data_fn get_entry_proc,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq *modreq_out,
                    krb5_data **e_data, krb5_authdata ***authz_data)
 {
     krb5_error_code retval = 0;
@@ -205,6 +207,7 @@
     krb5_keyblock *client_keys = NULL;
     krb5_data *client_data = NULL;
     krb5_keyblock *challenge_key = NULL;
+    krb5_keyblock *kdc_challenge_key;
     int i = 0;
 
     plain.data = NULL;
@@ -228,7 +231,7 @@
     }
     if (retval == 0)
         retval = get_entry_proc(context, request, client,
-                                krb5plugin_preauth_keys, &client_data);
+                                krb5_kdcpreauth_keys, &client_data);
     if (retval == 0) {
         client_keys = (krb5_keyblock *) client_data->data;
         for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) {
@@ -273,9 +276,10 @@
              * considered this a success, so the return value is ignored.
              */
             fast_kdc_replace_reply_key(context, get_entry_proc, request);
-            krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor",
-                                 &client_keys[i], "challengelongterm",
-                                 (krb5_keyblock **) pa_request_context);
+            if (krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor",
+                                     &client_keys[i], "challengelongterm",
+                                     &kdc_challenge_key) == 0)
+                *modreq_out = (krb5_kdcpreauth_modreq)kdc_challenge_key;
         } else { /*skew*/
             retval = KRB5KRB_AP_ERR_SKEW;
         }
@@ -302,11 +306,12 @@
                    krb5_kdc_req *request, krb5_kdc_rep *reply,
                    struct _krb5_key_data *client_keys,
                    krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
-                   preauth_get_entry_data_proc get_entry_proc,
-                   void *pa_module_context, void **pa_request_context)
+                   krb5_kdcpreauth_get_data_fn get_entry_proc,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq modreq)
 {
     krb5_error_code retval = 0;
-    krb5_keyblock *challenge_key = *pa_request_context;
+    krb5_keyblock *challenge_key = (krb5_keyblock *)modreq;
     krb5_pa_enc_ts ts;
     krb5_data *plain = NULL;
     krb5_enc_data enc;
@@ -318,8 +323,6 @@
         return 0;
     if (challenge_key == NULL)
         return 0;
-    * pa_request_context = NULL; /*this function will free the
-                                  * challenge key*/
     enc.ciphertext.data = NULL; /* In case of error pass through */
 
     retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
@@ -355,37 +358,45 @@
     return retval;
 }
 
-static int
-kdc_preauth_flags(krb5_context context, krb5_preauthtype patype)
+krb5_preauthtype supported_pa_types[] = {
+    KRB5_PADATA_ENCRYPTED_CHALLENGE, 0};
+
+krb5_error_code
+kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
+                                      int min_ver, krb5_plugin_vtable vtable);
+krb5_error_code
+clpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
+                                     int min_ver, krb5_plugin_vtable vtable);
+
+krb5_error_code
+kdcpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
+                                      int min_ver, krb5_plugin_vtable vtable)
 {
+    krb5_kdcpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_kdcpreauth_vtable)vtable;
+    vt->name = "encrypted_challenge";
+    vt->pa_type_list = supported_pa_types;
+    vt->edata = kdc_include_padata;
+    vt->verify = kdc_verify_preauth;
+    vt->return_padata = kdc_return_preauth;
     return 0;
 }
 
-krb5_preauthtype supported_pa_types[] = {
-    KRB5_PADATA_ENCRYPTED_CHALLENGE, 0};
+krb5_error_code
+clpreauth_encrypted_challenge_initvt(krb5_context context, int maj_ver,
+                                     int min_ver, krb5_plugin_vtable vtable)
+{
+    krb5_clpreauth_vtable vt;
 
-struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
-    "Encrypted challenge",
-    &supported_pa_types[0],
-    NULL,
-    NULL,
-    kdc_preauth_flags,
-    kdc_include_padata,
-    kdc_verify_preauth,
-    kdc_return_preauth,
-    NULL
-};
-
-struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = {
-    "Encrypted Challenge",                /* name */
-    &supported_pa_types[0],        /* pa_type_list */
-    NULL,                    /* enctype_list */
-    NULL,                    /* plugin init function */
-    NULL,                    /* plugin fini function */
-    preauth_flags,                /* get flags function */
-    NULL,                    /* request init function */
-    NULL,                    /* request fini function */
-    process_preauth,                /* process function */
-    NULL,                    /* try_again function */
-    NULL                /* get init creds opt function */
-};
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_clpreauth_vtable)vtable;
+    vt->name = "encrypted_challenge";
+    vt->pa_type_list = supported_pa_types;
+    vt->flags = preauth_flags;
+    vt->process = process_preauth;
+    return 0;
+}

Modified: trunk/src/plugins/preauth/fast_factor.h
===================================================================
--- trunk/src/plugins/preauth/fast_factor.h	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/fast_factor.h	2011-06-17 13:44:33 UTC (rev 24970)
@@ -5,38 +5,36 @@
  * Returns failure if the client library does not support FAST.
  */
 static inline krb5_error_code
-fast_get_armor_key(krb5_context context, preauth_get_client_data_proc get_data,
-                   struct _krb5_preauth_client_rock *rock,
-                   krb5_keyblock **armor_key)
+fast_get_armor_key(krb5_context context, krb5_clpreauth_get_data_fn get_data,
+                   krb5_clpreauth_rock rock, krb5_keyblock **armor_key)
 {
     krb5_error_code retval = 0;
     krb5_data *data;
-    retval = get_data(context, rock, krb5plugin_preauth_client_fast_armor, &data);
+    retval = get_data(context, rock, krb5_clpreauth_fast_armor, &data);
     if (retval == 0) {
         *armor_key = (krb5_keyblock *) data->data;
         data->data = NULL;
-        get_data(context, rock, krb5plugin_preauth_client_free_fast_armor,
-                 &data);
+        get_data(context, rock, krb5_clpreauth_free_fast_armor, &data);
     }
     return retval;
 }
 
 static inline krb5_error_code
 fast_kdc_get_armor_key(krb5_context context,
-                       preauth_get_entry_data_proc get_entry,
+                       krb5_kdcpreauth_get_data_fn get_entry,
                        krb5_kdc_req *request,
                        struct _krb5_db_entry_new *client,
                        krb5_keyblock **armor_key)
 {
     krb5_error_code retval;
     krb5_data *data;
-    retval = get_entry(context, request, client,  krb5plugin_preauth_fast_armor,
+    retval = get_entry(context, request, client, krb5_kdcpreauth_fast_armor,
                        &data);
     if (retval == 0) {
         *armor_key = (krb5_keyblock *) data->data;
         data->data = NULL;
         get_entry(context, request, client,
-                  krb5plugin_preauth_free_fast_armor, &data);
+                  krb5_kdcpreauth_free_fast_armor, &data);
     }
     return retval;
 }
@@ -45,7 +43,7 @@
 
 static inline krb5_error_code
 fast_kdc_replace_reply_key(krb5_context context,
-                           preauth_get_entry_data_proc get_data,
+                           krb5_kdcpreauth_get_data_fn get_data,
                            krb5_kdc_req *request)
 {
     return 0;
@@ -53,8 +51,8 @@
 
 static inline krb5_error_code
 fast_set_kdc_verified(krb5_context context,
-                      preauth_get_client_data_proc get_data,
-                      struct _krb5_preauth_client_rock *rock)
+                      krb5_clpreauth_get_data_fn get_data,
+                      krb5_clpreauth_rock rock)
 {
     return 0;
 }

Modified: trunk/src/plugins/preauth/pkinit/pkinit.exports
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit.exports	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/pkinit/pkinit.exports	2011-06-17 13:44:33 UTC (rev 24970)
@@ -1,2 +1,2 @@
-preauthentication_client_1
-preauthentication_server_1
+clpreauth_pkinit_initvt
+kdcpreauth_pkinit_initvt

Modified: trunk/src/plugins/preauth/pkinit/pkinit_clnt.c
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_clnt.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/pkinit/pkinit_clnt.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -71,7 +71,8 @@
                     krb5_kdc_req *request, const krb5_data *as_rep,
                     krb5_keyblock *key_block, krb5_enctype etype, krb5_data *);
 
-static void pkinit_client_plugin_fini(krb5_context context, void *blob);
+static void pkinit_client_plugin_fini(krb5_context context,
+                                      krb5_clpreauth_moddata moddata);
 
 static krb5_error_code
 pa_pkinit_gen_req(krb5_context context,
@@ -975,31 +976,25 @@
 }
 
 static krb5_error_code
-pkinit_client_process(krb5_context context,
-                      void *plugin_context,
-                      void *request_context,
+pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
+                      krb5_clpreauth_modreq modreq,
                       krb5_get_init_creds_opt *gic_opt,
-                      preauth_get_client_data_proc get_data_proc,
-                      struct _krb5_preauth_client_rock *rock,
-                      krb5_kdc_req *request,
+                      krb5_clpreauth_get_data_fn get_data_proc,
+                      krb5_clpreauth_rock rock, krb5_kdc_req *request,
                       krb5_data *encoded_request_body,
                       krb5_data *encoded_previous_request,
                       krb5_pa_data *in_padata,
-                      krb5_prompter_fct prompter,
-                      void *prompter_data,
-                      preauth_get_as_key_proc gak_fct,
-                      void *gak_data,
-                      krb5_data *salt,
-                      krb5_data *s2kparams,
-                      krb5_keyblock *as_key,
-                      krb5_pa_data ***out_padata)
+                      krb5_prompter_fct prompter, void *prompter_data,
+                      krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data,
+                      krb5_data *salt, krb5_data *s2kparams,
+                      krb5_keyblock *as_key, krb5_pa_data ***out_padata)
 {
     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
     krb5_enctype enctype = -1;
     krb5_data *cdata = NULL;
     int processing_request = 0;
-    pkinit_context plgctx = (pkinit_context)plugin_context;
-    pkinit_req_context reqctx = (pkinit_req_context)request_context;
+    pkinit_context plgctx = (pkinit_context)moddata;
+    pkinit_req_context reqctx = (pkinit_req_context)modreq;
     krb5_keyblock *armor_key = NULL;
 
     pkiDebug("pkinit_client_process %p %p %p %p\n",
@@ -1061,16 +1056,15 @@
         /*
          * Get the enctype of the reply.
          */
-        retval = (*get_data_proc)(context, rock,
-                                  krb5plugin_preauth_client_get_etype, &cdata);
+        retval = (*get_data_proc)(context, rock, krb5_clpreauth_get_etype,
+                                  &cdata);
         if (retval) {
             pkiDebug("get_data_proc returned %d (%s)\n",
                      retval, error_message(retval));
             return retval;
         }
         enctype = *((krb5_enctype *)cdata->data);
-        (*get_data_proc)(context, rock,
-                         krb5plugin_preauth_client_free_etype, &cdata);
+        (*get_data_proc)(context, rock, krb5_clpreauth_free_etype, &cdata);
         retval = pa_pkinit_parse_rep(context, plgctx, reqctx, request,
                                      in_padata, enctype, as_key,
                                      encoded_previous_request);
@@ -1082,29 +1076,22 @@
 }
 
 static krb5_error_code
-pkinit_client_tryagain(krb5_context context,
-                       void *plugin_context,
-                       void *request_context,
+pkinit_client_tryagain(krb5_context context, krb5_clpreauth_moddata moddata,
+                       krb5_clpreauth_modreq modreq,
                        krb5_get_init_creds_opt *gic_opt,
-                       preauth_get_client_data_proc get_data_proc,
-                       struct _krb5_preauth_client_rock *rock,
-                       krb5_kdc_req *request,
+                       krb5_clpreauth_get_data_fn get_data_proc,
+                       krb5_clpreauth_rock rock, krb5_kdc_req *request,
                        krb5_data *encoded_request_body,
                        krb5_data *encoded_previous_request,
-                       krb5_pa_data *in_padata,
-                       krb5_error *err_reply,
-                       krb5_prompter_fct prompter,
-                       void *prompter_data,
-                       preauth_get_as_key_proc gak_fct,
-                       void *gak_data,
-                       krb5_data *salt,
-                       krb5_data *s2kparams,
-                       krb5_keyblock *as_key,
-                       krb5_pa_data ***out_padata)
+                       krb5_pa_data *in_padata, krb5_error *err_reply,
+                       krb5_prompter_fct prompter, void *prompter_data,
+                       krb5_clpreauth_get_as_key_fn gak_fct, void *gak_data,
+                       krb5_data *salt, krb5_data *s2kparams,
+                       krb5_keyblock *as_key, krb5_pa_data ***out_padata)
 {
     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
-    pkinit_context plgctx = (pkinit_context)plugin_context;
-    pkinit_req_context reqctx = (pkinit_req_context)request_context;
+    pkinit_context plgctx = (pkinit_context)moddata;
+    pkinit_req_context reqctx = (pkinit_req_context)modreq;
     krb5_typed_data **typed_data = NULL;
     krb5_data scratch;
     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
@@ -1202,14 +1189,14 @@
 
 static void
 pkinit_client_req_init(krb5_context context,
-                       void *plugin_context,
-                       void **request_context)
+                       krb5_clpreauth_moddata moddata,
+                       krb5_clpreauth_modreq *modreq_out)
 {
     krb5_error_code retval = ENOMEM;
     pkinit_req_context reqctx = NULL;
-    pkinit_context plgctx = plugin_context;
+    pkinit_context plgctx = (pkinit_context)moddata;
 
-    *request_context = NULL;
+    *modreq_out = NULL;
 
     reqctx = malloc(sizeof(*reqctx));
     if (reqctx == NULL)
@@ -1244,7 +1231,7 @@
     if (retval)
         goto cleanup;
 
-    *request_context = (void *) reqctx;
+    *modreq_out = (krb5_clpreauth_modreq)reqctx;
     pkiDebug("%s: returning reqctx at %p\n", __FUNCTION__, reqctx);
 
 cleanup:
@@ -1264,11 +1251,10 @@
 }
 
 static void
-pkinit_client_req_fini(krb5_context context,
-                       void *plugin_context,
-                       void *request_context)
+pkinit_client_req_fini(krb5_context context, krb5_clpreauth_moddata moddata,
+                       krb5_clpreauth_modreq modreq)
 {
-    pkinit_req_context reqctx = request_context;
+    pkinit_req_context reqctx = (pkinit_req_context)modreq;
 
     pkiDebug("%s: received reqctx at %p\n", __FUNCTION__, reqctx);
     if (reqctx == NULL)
@@ -1295,7 +1281,8 @@
 }
 
 static int
-pkinit_client_plugin_init(krb5_context context, void **blob)
+pkinit_client_plugin_init(krb5_context context,
+                          krb5_clpreauth_moddata *moddata_out)
 {
     krb5_error_code retval = ENOMEM;
     pkinit_context ctx = NULL;
@@ -1325,21 +1312,21 @@
     if (retval)
         goto errout;
 
-    *blob = ctx;
+    *moddata_out = (krb5_clpreauth_moddata)ctx;
 
     pkiDebug("%s: returning plgctx at %p\n", __FUNCTION__, ctx);
 
 errout:
     if (retval)
-        pkinit_client_plugin_fini(context, ctx);
+        pkinit_client_plugin_fini(context, (krb5_clpreauth_moddata)ctx);
 
     return retval;
 }
 
 static void
-pkinit_client_plugin_fini(krb5_context context, void *blob)
+pkinit_client_plugin_fini(krb5_context context, krb5_clpreauth_moddata moddata)
 {
-    pkinit_context ctx = blob;
+    pkinit_context ctx = (pkinit_context)moddata;
 
     if (ctx == NULL || ctx->magic != PKINIT_CTX_MAGIC) {
         pkiDebug("pkinit_lib_fini: got bad plgctx (%p)!\n", ctx);
@@ -1425,14 +1412,13 @@
 }
 
 static krb5_error_code
-pkinit_client_gic_opt(krb5_context context,
-                      void *plugin_context,
+pkinit_client_gic_opt(krb5_context context, krb5_clpreauth_moddata moddata,
                       krb5_get_init_creds_opt *gic_opt,
                       const char *attr,
                       const char *value)
 {
     krb5_error_code retval;
-    pkinit_context plgctx = plugin_context;
+    pkinit_context plgctx = (pkinit_context)moddata;
 
     pkiDebug("(pkinit) received '%s' = '%s'\n", attr, value);
     retval = handle_gic_opt(context, plgctx, attr, value);
@@ -1442,20 +1428,28 @@
     return 0;
 }
 
-/* Only necessary for static plugin linking support. */
-#include "k5-plugin.h"
+krb5_error_code
+clpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
+                        krb5_plugin_vtable vtable);
 
-struct krb5plugin_preauth_client_ftable_v1
-PLUGIN_SYMBOL_NAME(krb5_preauth, preauthentication_client_1) = {
-    "pkinit",                   /* name */
-    supported_client_pa_types,  /* pa_type_list */
-    NULL,                       /* enctype_list */
-    pkinit_client_plugin_init,  /* (*init) */
-    pkinit_client_plugin_fini,  /* (*fini) */
-    pkinit_client_get_flags,    /* (*flags) */
-    pkinit_client_req_init,     /* (*client_req_init) */
-    pkinit_client_req_fini,     /* (*client_req_fini) */
-    pkinit_client_process,      /* (*process) */
-    pkinit_client_tryagain,     /* (*tryagain) */
-    pkinit_client_gic_opt       /* (*gic_opt) */
-};
+krb5_error_code
+clpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
+                        krb5_plugin_vtable vtable)
+{
+    krb5_clpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_clpreauth_vtable)vtable;
+    vt->name = "pkinit";
+    vt->pa_type_list = supported_client_pa_types;
+    vt->init = pkinit_client_plugin_init;
+    vt->fini = pkinit_client_plugin_fini;
+    vt->flags = pkinit_client_get_flags;
+    vt->request_init = pkinit_client_req_init;
+    vt->request_fini = pkinit_client_req_fini;
+    vt->process = pkinit_client_process;
+    vt->tryagain = pkinit_client_tryagain;
+    vt->gic_opts = pkinit_client_gic_opt;
+    return 0;
+}

Modified: trunk/src/plugins/preauth/pkinit/pkinit_srv.c
===================================================================
--- trunk/src/plugins/preauth/pkinit/pkinit_srv.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/pkinit/pkinit_srv.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -50,10 +50,12 @@
                                 pkinit_kdc_context plgctx);
 
 static void
-pkinit_server_plugin_fini(krb5_context context, void *blob);
+pkinit_server_plugin_fini(krb5_context context,
+                          krb5_kdcpreauth_moddata moddata);
 
 static pkinit_kdc_context
-pkinit_find_realm_context(krb5_context context, void *pa_plugin_context,
+pkinit_find_realm_context(krb5_context context,
+                          krb5_kdcpreauth_moddata moddata,
                           krb5_principal princ);
 
 static krb5_error_code
@@ -97,12 +99,12 @@
 
 static krb5_error_code
 pkinit_server_get_edata(krb5_context context,
-                        krb5_kdc_req * request,
-                        struct _krb5_db_entry_new * client,
-                        struct _krb5_db_entry_new * server,
-                        preauth_get_entry_data_proc server_get_entry_data,
-                        void *pa_plugin_context,
-                        krb5_pa_data * data)
+                        krb5_kdc_req *request,
+                        struct _krb5_db_entry_new *client,
+                        struct _krb5_db_entry_new *server,
+                        krb5_kdcpreauth_get_data_fn server_get_entry_data,
+                        krb5_kdcpreauth_moddata moddata,
+                        krb5_pa_data *data)
 {
     krb5_error_code retval = 0;
     pkinit_kdc_context plgctx = NULL;
@@ -123,8 +125,7 @@
      * If we don't have a realm context for the given realm,
      * don't tell the client that we support pkinit!
      */
-    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
-                                       request->server);
+    plgctx = pkinit_find_realm_context(context, moddata, request->server);
     if (plgctx == NULL)
         retval = EINVAL;
 
@@ -292,9 +293,9 @@
                             krb5_kdc_req * request,
                             krb5_enc_tkt_part * enc_tkt_reply,
                             krb5_pa_data * data,
-                            preauth_get_entry_data_proc server_get_entry_data,
-                            void *pa_plugin_context,
-                            void **pa_request_context,
+                            krb5_kdcpreauth_get_data_fn server_get_entry_data,
+                            krb5_kdcpreauth_moddata moddata,
+                            krb5_kdcpreauth_modreq *modreq_out,
                             krb5_data **e_data,
                             krb5_authdata ***authz_data)
 {
@@ -328,11 +329,10 @@
         return EINVAL;
     }
 
-    if (pa_plugin_context == NULL || e_data == NULL)
+    if (moddata == NULL || e_data == NULL)
         return EINVAL;
 
-    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
-                                       request->server);
+    plgctx = pkinit_find_realm_context(context, moddata, request->server);
     if (plgctx == NULL)
         return 0;
 
@@ -562,7 +562,7 @@
     }
     /* remember to set the PREAUTH flag in the reply */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
-    *pa_request_context = reqctx;
+    *modreq_out = (krb5_kdcpreauth_modreq)reqctx;
     reqctx = NULL;
 
 cleanup:
@@ -668,9 +668,9 @@
                             struct _krb5_key_data * client_key,
                             krb5_keyblock * encrypting_key,
                             krb5_pa_data ** send_pa,
-                            preauth_get_entry_data_proc server_get_entry_data,
-                            void *pa_plugin_context,
-                            void **pa_request_context)
+                            krb5_kdcpreauth_get_data_fn server_get_entry_data,
+                            krb5_kdcpreauth_moddata moddata,
+                            krb5_kdcpreauth_modreq modreq)
 {
     krb5_error_code retval = 0;
     krb5_data scratch = {0, 0, NULL};
@@ -708,20 +708,19 @@
     if (padata->length <= 0 || padata->contents == NULL)
         return 0;
 
-    if (pa_request_context == NULL || *pa_request_context == NULL) {
+    if (modreq == NULL) {
         pkiDebug("missing request context \n");
         return EINVAL;
     }
 
-    plgctx = pkinit_find_realm_context(context, pa_plugin_context,
-                                       request->server);
+    plgctx = pkinit_find_realm_context(context, moddata, request->server);
     if (plgctx == NULL) {
         pkiDebug("Unable to locate correct realm context\n");
         return ENOENT;
     }
 
     pkiDebug("pkinit_return_padata: entered!\n");
-    reqctx = (pkinit_kdc_req_context)*pa_request_context;
+    reqctx = (pkinit_kdc_req_context)modreq;
 
     if (encrypting_key->contents) {
         free(encrypting_key->contents);
@@ -1169,13 +1168,14 @@
 }
 
 static pkinit_kdc_context
-pkinit_find_realm_context(krb5_context context, void *pa_plugin_context,
+pkinit_find_realm_context(krb5_context context,
+                          krb5_kdcpreauth_moddata moddata,
                           krb5_principal princ)
 {
     int i;
-    pkinit_kdc_context *realm_contexts = pa_plugin_context;
+    pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
 
-    if (pa_plugin_context == NULL)
+    if (moddata == NULL)
         return NULL;
 
     for (i = 0; realm_contexts[i] != NULL; i++) {
@@ -1254,7 +1254,8 @@
 }
 
 static int
-pkinit_server_plugin_init(krb5_context context, void **blob,
+pkinit_server_plugin_init(krb5_context context,
+                          krb5_kdcpreauth_moddata *moddata_out,
                           const char **realmnames)
 {
     krb5_error_code retval = ENOMEM;
@@ -1289,13 +1290,15 @@
         goto errout;
     }
 
-    *blob = realm_contexts;
+    *moddata_out = (krb5_kdcpreauth_moddata)realm_contexts;
     retval = 0;
     pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts);
 
 errout:
-    if (retval)
-        pkinit_server_plugin_fini(context, realm_contexts);
+    if (retval) {
+        pkinit_server_plugin_fini(context,
+                                  (krb5_kdcpreauth_moddata)realm_contexts);
+    }
 
     return retval;
 }
@@ -1316,9 +1319,10 @@
 }
 
 static void
-pkinit_server_plugin_fini(krb5_context context, void *blob)
+pkinit_server_plugin_fini(krb5_context context,
+                          krb5_kdcpreauth_moddata moddata)
 {
-    pkinit_kdc_context *realm_contexts = blob;
+    pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata;
     int i;
 
     if (realm_contexts == NULL)
@@ -1379,18 +1383,26 @@
     free(reqctx);
 }
 
-/* Only necessary for static plugin linking support. */
-#include "k5-plugin.h"
+krb5_error_code
+kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
+                         krb5_plugin_vtable vtable);
 
-struct krb5plugin_preauth_server_ftable_v1
-PLUGIN_SYMBOL_NAME(krb5_pkinit, preauthentication_server_1) = {
-    "pkinit",                   /* name */
-    supported_server_pa_types,  /* pa_type_list */
-    pkinit_server_plugin_init,  /* (*init_proc) */
-    pkinit_server_plugin_fini,  /* (*fini_proc) */
-    pkinit_server_get_flags,    /* (*flags_proc) */
-    pkinit_server_get_edata,    /* (*edata_proc) */
-    pkinit_server_verify_padata,/* (*verify_proc) */
-    pkinit_server_return_padata,/* (*return_proc) */
-    NULL,                       /* (*freepa_reqcontext_proc) */
-};
+krb5_error_code
+kdcpreauth_pkinit_initvt(krb5_context context, int maj_ver, int min_ver,
+                         krb5_plugin_vtable vtable)
+{
+    krb5_kdcpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_kdcpreauth_vtable)vtable;
+    vt->name = "pkinit";
+    vt->pa_type_list = supported_server_pa_types;
+    vt->init = pkinit_server_plugin_init;
+    vt->fini = pkinit_server_plugin_fini;
+    vt->flags = pkinit_server_get_flags;
+    vt->edata = pkinit_server_get_edata;
+    vt->verify = pkinit_server_verify_padata;
+    vt->return_padata = pkinit_server_return_padata;
+    return 0;
+}

Modified: trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -116,8 +116,8 @@
 kdc_include_padata(krb5_context context, krb5_kdc_req *request,
                    struct _krb5_db_entry_new *client,
                    struct _krb5_db_entry_new *server,
-                   preauth_get_entry_data_proc get_entry_proc,
-                   void *pa_module_context, krb5_pa_data *pa_data)
+                   krb5_kdcpreauth_get_data_fn get_entry_proc,
+                   krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data)
 {
     krb5_error_code retval;
     krb5_data *client_keys_data = NULL;
@@ -138,7 +138,7 @@
     if (retval)
         return retval;
     retval = get_entry_proc(context, request, client,
-                            krb5plugin_preauth_keys, &client_keys_data);
+                            krb5_kdcpreauth_keys, &client_keys_data);
     if (retval)
         goto cleanup;
     client_key = (krb5_keyblock *) client_keys_data->data;
@@ -206,8 +206,9 @@
 kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
                    krb5_data *req_pkt, krb5_kdc_req *request,
                    krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa_data,
-                   preauth_get_entry_data_proc get_entry_proc,
-                   void *pa_module_context, void **opaque,
+                   krb5_kdcpreauth_get_data_fn get_entry_proc,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq *modreq_out,
                    krb5_data **e_data, krb5_authdata ***authz_data)
 {
     krb5_error_code retval, saved_retval = 0;
@@ -294,14 +295,23 @@
 krb5_preauthtype supported_pa_types[] = {
     KRB5_PADATA_SAM_RESPONSE_2, 0};
 
-struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
-    "SAM2",
-    &supported_pa_types[0],
-    NULL,
-    NULL,
-    kdc_preauth_flags,
-    kdc_include_padata,
-    kdc_verify_preauth,
-    NULL,
-    NULL
-};
+krb5_error_code
+kdcpreauth_securid_sam2_initvt(krb5_context context, int maj_ver, int min_ver,
+                               krb5_plugin_vtable vtable);
+
+krb5_error_code
+kdcpreauth_securid_sam2_initvt(krb5_context context, int maj_ver, int min_ver,
+                               krb5_plugin_vtable vtable)
+{
+    krb5_kdcpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_kdcpreauth_vtable)vtable;
+    vt->name = "securid_sam2";
+    vt->pa_type_list = supported_pa_types;
+    vt->flags = kdc_preauth_flags;
+    vt->edata = kdc_include_padata;
+    vt->verify = kdc_verify_preauth;
+    return 0;
+}

Modified: trunk/src/plugins/preauth/wpse/wpse.exports
===================================================================
--- trunk/src/plugins/preauth/wpse/wpse.exports	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/wpse/wpse.exports	2011-06-17 13:44:33 UTC (rev 24970)
@@ -1,2 +1,2 @@
-preauthentication_client_1
-preauthentication_server_1
+clpreauth_wpse_initvt
+kdcpreauth_wpse_initvt

Modified: trunk/src/plugins/preauth/wpse/wpse_main.c
===================================================================
--- trunk/src/plugins/preauth/wpse/wpse_main.c	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/plugins/preauth/wpse/wpse_main.c	2011-06-17 13:44:33 UTC (rev 24970)
@@ -59,7 +59,7 @@
 }
 
 static krb5_error_code
-client_init(krb5_context kcontext, void **ctx)
+client_init(krb5_context kcontext, krb5_clpreauth_moddata *moddata_out)
 {
     int *pctx;
 
@@ -67,16 +67,16 @@
     if (pctx == NULL)
         return ENOMEM;
     *pctx = 0;
-    *ctx = pctx;
+    *moddata_out = (krb5_clpreauth_moddata)pctx;
     return 0;
 }
 
 static void
-client_fini(krb5_context kcontext, void *ctx)
+client_fini(krb5_context kcontext, krb5_clpreauth_moddata moddata)
 {
     int *pctx;
 
-    pctx = ctx;
+    pctx = (int *)moddata;
     if (pctx) {
 #ifdef DEBUG
         fprintf(stderr, "wpse module called total of %d times\n", *pctx);
@@ -87,18 +87,18 @@
 
 static krb5_error_code
 client_process(krb5_context kcontext,
-               void *plugin_context,
-               void *request_context,
+               krb5_clpreauth_moddata moddata,
+               krb5_clpreauth_modreq modreq,
                krb5_get_init_creds_opt *opt,
-               preauth_get_client_data_proc client_get_data_proc,
-               struct _krb5_preauth_client_rock *rock,
+               krb5_clpreauth_get_data_fn client_get_data_proc,
+               krb5_clpreauth_rock rock,
                krb5_kdc_req *request,
                krb5_data *encoded_request_body,
                krb5_data *encoded_previous_request,
                krb5_pa_data *pa_data,
                krb5_prompter_fct prompter,
                void *prompter_data,
-               preauth_get_as_key_proc gak_fct,
+               krb5_clpreauth_get_as_key_fn gak_fct,
                void *gak_data,
                krb5_data *salt, krb5_data *s2kparams,
                krb5_keyblock *as_key,
@@ -115,7 +115,7 @@
             pa_data->length, pa_data->pa_type);
 #endif
 
-    pctx = plugin_context;
+    pctx = (int *)moddata;
     if (pctx) {
         (*pctx)++;
     }
@@ -176,11 +176,12 @@
 } wpse_req_ctx;
 
 static void
-client_req_init(krb5_context kcontext, void *plugin_context, void **req_context_p)
+client_req_init(krb5_context kcontext, krb5_clpreauth_moddata moddata,
+                krb5_clpreauth_modreq *modreq_out)
 {
     wpse_req_ctx *ctx;
 
-    *req_context_p = NULL;
+    *modreq_out = NULL;
 
     /* Allocate a request context. Useful for verifying that we do in fact
      * do per-request cleanup. */
@@ -190,13 +191,14 @@
     ctx->magic = WPSE_MAGIC;
     ctx->value = 0xc0dec0de;
 
-    *req_context_p = ctx;
+    *modreq_out = (krb5_clpreauth_modreq)ctx;
 }
 
 static void
-client_req_cleanup(krb5_context kcontext, void *plugin_context, void *req_context)
+client_req_cleanup(krb5_context kcontext, krb5_clpreauth_moddata moddata,
+                   krb5_clpreauth_modreq modreq)
 {
-    wpse_req_ctx *ctx = (wpse_req_ctx *)req_context;
+    wpse_req_ctx *ctx = (wpse_req_ctx *)modreq;
 
     if (ctx) {
 #ifdef DEBUG
@@ -217,7 +219,7 @@
 
 static krb5_error_code
 client_gic_opt(krb5_context kcontext,
-               void *plugin_context,
+               krb5_clpreauth_moddata moddata,
                krb5_get_init_creds_opt *opt,
                const char *attr,
                const char *value)
@@ -231,15 +233,12 @@
 
 
 /* Free state. */
-static krb5_error_code
-server_free_pa_request_context(krb5_context kcontext, void *plugin_context,
-                               void **request_context)
+static void
+server_free_modreq(krb5_context kcontext,
+                   krb5_kdcpreauth_moddata moddata,
+                   krb5_kdcpreauth_modreq modreq)
 {
-    if (*request_context != NULL) {
-        free(*request_context);
-        *request_context = NULL;
-    }
-    return 0;
+    free(modreq);
 }
 
 /* Obtain and return any preauthentication data (which is destined for the
@@ -249,8 +248,8 @@
                  krb5_kdc_req *request,
                  struct _krb5_db_entry_new *client,
                  struct _krb5_db_entry_new *server,
-                 preauth_get_entry_data_proc server_get_entry_data,
-                 void *pa_module_context,
+                 krb5_kdcpreauth_get_data_fn server_get_entry_data,
+                 krb5_kdcpreauth_moddata moddata,
                  krb5_pa_data *data)
 {
     /* Return zero bytes of data. */
@@ -267,9 +266,9 @@
               krb5_kdc_req *request,
               krb5_enc_tkt_part *enc_tkt_reply,
               krb5_pa_data *data,
-              preauth_get_entry_data_proc server_get_entry_data,
-              void *pa_module_context,
-              void **pa_request_context,
+              krb5_kdcpreauth_get_data_fn server_get_entry_data,
+              krb5_kdcpreauth_moddata moddata,
+              krb5_kdcpreauth_modreq *modreq_out,
               krb5_data **e_data,
               krb5_authdata ***authz_data)
 {
@@ -292,8 +291,7 @@
     enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
     /* Allocate a context. Useful for verifying that we do in fact do
      * per-request cleanup. */
-    if (*pa_request_context == NULL)
-        *pa_request_context = malloc(4);
+    *modreq_out = malloc(4);
 
     /*
      * Return some junk authorization data just to exercise the
@@ -373,9 +371,8 @@
               struct _krb5_key_data *client_key,
               krb5_keyblock *encrypting_key,
               krb5_pa_data **send_pa,
-              preauth_get_entry_data_proc server_get_entry_data,
-              void *pa_module_context,
-              void **pa_request_context)
+              krb5_kdcpreauth_get_data_fn server_get_entry_data,
+              krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
 {
     /* This module does a couple of dumb things.  It tags its reply with
      * the same type as the initial challenge (expecting the client to sort
@@ -447,28 +444,49 @@
 static krb5_preauthtype supported_client_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0};
 static krb5_preauthtype supported_server_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0};
 
-struct krb5plugin_preauth_client_ftable_v1 preauthentication_client_1 = {
-    "wpse",                                 /* name */
-    &supported_client_pa_types[0],          /* pa_type_list */
-    NULL,                                   /* enctype_list */
-    client_init,                            /* plugin init function */
-    client_fini,                            /* plugin fini function */
-    client_get_flags,                       /* get flags function */
-    client_req_init,                        /* request init function */
-    client_req_cleanup,                     /* request fini function */
-    client_process,                         /* process function */
-    NULL,                                   /* try_again function */
-    client_gic_opt                          /* get init creds opts function */
-};
+krb5_error_code
+clpreauth_wpse_initvt(krb5_context context, int maj_ver,
+                      int min_ver, krb5_plugin_vtable vtable);
+krb5_error_code
+kdcpreauth_wpse_initvt(krb5_context context, int maj_ver,
+                       int min_ver, krb5_plugin_vtable vtable);
 
-struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
-    "wpse",
-    &supported_server_pa_types[0],
-    NULL,
-    NULL,
-    server_get_flags,
-    server_get_edata,
-    server_verify,
-    server_return,
-    server_free_pa_request_context,
-};
+krb5_error_code
+clpreauth_wpse_initvt(krb5_context context, int maj_ver,
+                      int min_ver, krb5_plugin_vtable vtable)
+{
+    krb5_clpreauth_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_clpreauth_vtable)vtable;
+    vt->name = "wpse";
+    vt->pa_type_list = supported_client_pa_types;
+    vt->init = client_init;
+    vt->fini = client_fini;
+    vt->flags = client_get_flags;
+    vt->request_init = client_req_init;
+    vt->request_fini = client_req_cleanup;
+    vt->process = client_process;
+    vt->gic_opts = client_gic_opt;
+    return 0;
+}
+
+krb5_error_code
+kdcpreauth_wpse_initvt(krb5_context context, int maj_ver,
+                       int min_ver, krb5_plugin_vtable vtable)
+{
+    krb5_kdcpreauth_vtable vt;
+
+    if (maj_ver != -1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+    vt = (krb5_kdcpreauth_vtable)vtable;
+    vt->name = "wpse";
+    vt->pa_type_list = supported_server_pa_types;
+    vt->flags = server_get_flags;
+    vt->edata = server_get_edata;
+    vt->verify = server_verify;
+    vt->return_padata = server_return;
+    vt->free_modreq = server_free_modreq;
+    return 0;
+}

Modified: trunk/src/tests/dejagnu/Makefile.in
===================================================================
--- trunk/src/tests/dejagnu/Makefile.in	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/tests/dejagnu/Makefile.in	2011-06-17 13:44:33 UTC (rev 24970)
@@ -41,6 +41,6 @@
 	echo "set runvarlist [list `cat runenv.vals | tr '\n' ' '`]" | \
 		sed -e 's%=\.%='`pwd`'/.%g' > site.exp
 	echo "set KRB5_DB_MODULE_DIR {$(KRB5_DB_MODULE_DIR)}" >> site.exp
-	echo "set KRB5_PA_MODULE_DIR {$(KRB5_PA_MODULE_DIR)}" >> site.exp
+	echo "set MODULE_DIR {$(MODULE_DIR)}" >> site.exp
 	echo "set PRIOCNTL_HACK @PRIOCNTL_HACK@" >> site.exp
 

Modified: trunk/src/tests/dejagnu/config/default.exp
===================================================================
--- trunk/src/tests/dejagnu/config/default.exp	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/tests/dejagnu/config/default.exp	2011-06-17 13:44:33 UTC (rev 24970)
@@ -918,7 +918,7 @@
     global mode
     global portbase
     global KRB5_DB_MODULE_DIR
-    global KRB5_PA_MODULE_DIR
+    global MODULE_DIR
     global srcdir
 
     set pkinit_certs [findfile "[pwd]/$srcdir/pkinit-certs" "[pwd]/$srcdir/pkinit-certs" "$srcdir/pkinit-certs"]
@@ -950,7 +950,7 @@
 	if { $mode == "tcp" } {
 	    puts $conffile "	udp_preference_limit = 1"
 	}
-	puts $conffile "	preauth_module_dir = $tmppwd/../../../util/fakedest$KRB5_PA_MODULE_DIR"
+	puts $conffile "	plugin_base_dir = $tmppwd/../../../util/fakedest$MODULE_DIR"
 	puts $conffile ""
 	puts $conffile "\[realms\]"
 	puts $conffile "	$REALMNAME = \{"

Modified: trunk/src/tests/dejagnu/krb-standalone/standalone.exp
===================================================================
--- trunk/src/tests/dejagnu/krb-standalone/standalone.exp	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/tests/dejagnu/krb-standalone/standalone.exp	2011-06-17 13:44:33 UTC (rev 24970)
@@ -139,7 +139,7 @@
     global portbase
     global mode
     global tmppwd
-    global KRB5_PA_MODULE_DIR
+    global MODULE_DIR
 
     setup_kerberos_env kdc
 
@@ -235,7 +235,7 @@
     }
 
     # If we have anonymous  then test it
-    if [file exists "$tmppwd/../../../util/fakedest$KRB5_PA_MODULE_DIR/pkinit.so" ] {
+    if [file exists "$tmppwd/../../../util/fakedest$MODULE_DIR/preauth/pkinit.so" ] {
 	kinit_anonymous "WELLKNOWN/ANONYMOUS"
     }
 

Modified: trunk/src/util/k5test.py
===================================================================
--- trunk/src/util/k5test.py	2011-06-17 13:44:26 UTC (rev 24969)
+++ trunk/src/util/k5test.py	2011-06-17 13:44:33 UTC (rev 24970)
@@ -915,7 +915,7 @@
         'libdefaults' : {
             'default_realm' : '$realm',
             'dns_lookup_kdc' : 'false',
-            'preauth_module_dir' : '$plugins/preauth'
+            'plugin_base_dir' : '$plugins'
         },
         'realms' : {
             '$realm' : {




More information about the cvs-krb5 mailing list