Implementing preauthentication using loadable modules

Nalin Dahyabhai nalin at redhat.com
Wed Oct 4 13:59:35 EDT 2006


On Tue, Oct 03, 2006 at 03:09:09PM -0400, Sam Hartman wrote:
> Hi.  I committed your October 2 patch.

Great!

> I definitely think we'd like to support splitting out the server
> functionality from the client functionality.  We should also discuss
> whether a minor version number would be useful in the struct.

I'm attaching a suggested patch to do the split.  The bulk of it is due
to renames of the types and callback names (removing "client_" from
the names of members of the client structure, likewise for the server
bits) -- it can be smaller if we don't want to bother with that.

What would new minor version numbers designate?  I can imagine that if
the interface were extended by adding new items to the end of one
structure or another, that the routines which load the modules could use
the minor version number to determine where the structure provided by
the module "ends".

In the short term, would those functions need to be modified to reject
modules which implement a newer minor version than they support, or do
we force modules which implement newer minor versions to still work
correctly if the newer members are ignored?

Nalin
-------------- next part --------------
Index: src/plugins/preauth/cksum_body/cksum_body.exports
===================================================================
--- src/plugins/preauth/cksum_body/cksum_body.exports	(revision 18642)
+++ src/plugins/preauth/cksum_body/cksum_body.exports	(working copy)
@@ -1 +1,2 @@
-preauthentication0
+preauthentication_client_0
+preauthentication_server_0
Index: src/plugins/preauth/cksum_body/src/cksum_body.c
===================================================================
--- src/plugins/preauth/cksum_body/src/cksum_body.c	(revision 18642)
+++ src/plugins/preauth/cksum_body/src/cksum_body.c	(working copy)
@@ -468,10 +468,9 @@
     KRB5_PADATA_CKSUM_BODY_REQ, 0,
 };
 
-struct krb5plugin_preauth_ftable_v0 preauthentication0 = {
+struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
     "cksum_body",
     &supported_client_pa_types[0],
-    &supported_server_pa_types[0],
     NULL,
     NULL,
     NULL,
@@ -479,6 +478,11 @@
     NULL,
     client_process,
     NULL,
+};
+
+struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {
+    "cksum_body",
+    &supported_server_pa_types[0],
     server_init,
     server_fini,
     server_get_flags,
Index: src/plugins/preauth/wpse/wpse.exports
===================================================================
--- src/plugins/preauth/wpse/wpse.exports	(revision 18642)
+++ src/plugins/preauth/wpse/wpse.exports	(working copy)
@@ -1 +1,2 @@
-preauthentication0
+preauthentication_client_0
+preauthentication_server_0
Index: src/plugins/preauth/wpse/src/wpse.c
===================================================================
--- src/plugins/preauth/wpse/src/wpse.c	(revision 18642)
+++ src/plugins/preauth/wpse/src/wpse.c	(working copy)
@@ -316,10 +316,9 @@
 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_ftable_v0 preauthentication0 = {
+struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = {
     "wpse",
     &supported_client_pa_types[0],
-    &supported_server_pa_types[0],
     NULL,
     client_init,
     client_fini,
@@ -327,6 +326,11 @@
     client_cleanup,
     client_process,
     NULL,
+};
+
+struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = {
+    "wpse",
+    &supported_server_pa_types[0],
     NULL,
     NULL,
     server_get_flags,
Index: src/include/krb5/preauth_plugin.h
===================================================================
--- src/include/krb5/preauth_plugin.h	(revision 18642)
+++ src/include/krb5/preauth_plugin.h	(working copy)
@@ -140,40 +140,37 @@
 			   void *gak_data);
 
 /*
- * The function table / structure which a preauth module must export as
- * "preauthentication0".  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.
+ * 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.
  */
-typedef struct krb5plugin_preauth_ftable_v0 {
+typedef struct krb5plugin_preauth_client_ftable_v0 {
     /* Not-usually-visible name. */
     char *name;
 
-    /* Pointer to zero-terminated lists of pa_types which this module can
+    /* Pointer to zero-terminated list of pa_types which this module can
      * provide services for. */
-    krb5_preauthtype *client_pa_type_list;
-    krb5_preauthtype *server_pa_type_list;
+    krb5_preauthtype *pa_type_list;
 
     /* Pointer to zero-terminated list of enc_types which this module claims
      * to add support for. */
-    krb5_enctype *client_enctype_list;
+    krb5_enctype *enctype_list;
 
     /* Per-module initialization/cleanup.  The init function is called
      * by libkrb5 when the module is loaded, and the fini function is
      * called before the module is unloaded.  Both are optional and
      * may be called multiple times in case the module is used in
      * multiple contexts.*/
-    krb5_error_code (*client_init)(krb5_context, krb5_preauthtype, void **);
-    void (*client_fini)(krb5_context, krb5_preauthtype, void *);
+    krb5_error_code (*init)(krb5_context, krb5_preauthtype, void **);
+    void (*fini)(krb5_context, krb5_preauthtype, void *);
     /* 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. */
-    int (*client_flags)(krb5_context, krb5_preauthtype);
+    int (*flags)(krb5_context, krb5_preauthtype);
     /* Clean up a client context.  Can be NULL. */
-    void (*client_cleanup)(krb5_context context, void *module_context,
-			   void **request_context);
+    void (*cleanup)(krb5_context context, void *module_context,
+		    void **request_context);
     /* 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
@@ -182,39 +179,55 @@
      * 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. */
-    krb5_error_code (*client_process)(krb5_context context,
-				      void *module_context,
-				      void **request_context,
-				      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_data *salt, krb5_data *s2kparams,
-				      void *gak_data,
-				      krb5_keyblock *as_key,
-				      krb5_pa_data **out_pa_data);
+    krb5_error_code (*process)(krb5_context context,
+			       void *module_context,
+			       void **request_context,
+			       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_data *salt, krb5_data *s2kparams,
+			       void *gak_data,
+			       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. */
-    krb5_error_code (*client_tryagain)(krb5_context context,
-				       void *module_context,
-				       void **request_context,
-				       krb5_kdc_req *request,
-				       krb5_data *encoded_request_body,
-				       krb5_error *error,
-				       krb5_pa_data *in_pa_data,
-				       krb5_pa_data **out_pa_data);
+    krb5_error_code (*tryagain)(krb5_context context,
+				void *module_context,
+				void **request_context,
+				krb5_kdc_req *request,
+				krb5_data *encoded_request_body,
+				krb5_error *error,
+				krb5_pa_data *in_pa_data,
+				krb5_pa_data **out_pa_data);
+} krb5plugin_preauth_client_ftable_v0;
 
+/*
+ * 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_v0 {
+    /* Not-usually-visible name. */
+    char *name;
+
+    /* Pointer to zero-terminated list of pa_types which this module can
+     * provide services for. */
+    krb5_preauthtype *pa_type_list;
+
     /* Per-module initialization/cleanup.  The init function is called by the
      * KDC when the module is loaded, and the fini function is called before
      * the module is unloaded.  Both are optional. */
-    krb5_error_code (*server_init_proc)(krb5_context, krb5_preauthtype,
-				        void **);
-    void (*server_fini_proc)(krb5_context, krb5_preauthtype, void *);
+    krb5_error_code (*init_proc)(krb5_context, krb5_preauthtype, void **);
+    void (*fini_proc)(krb5_context, krb5_preauthtype, void *);
     /* 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
@@ -222,7 +235,7 @@
      * 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. */
-    int (*server_flags_proc)(krb5_context, krb5_preauthtype);
+    int (*flags_proc)(krb5_context, krb5_preauthtype);
     /* 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
@@ -231,47 +244,46 @@
      * 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. */
-    krb5_error_code (*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_error_code (*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);
     /* 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. */
-    krb5_error_code (*server_verify_proc)(krb5_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_error_code (*verify_proc)(krb5_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);
     /* 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". */
-    krb5_error_code (*server_return_proc)(krb5_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_error_code (*return_proc)(krb5_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);
     /* 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. */
-    krb5_error_code (*server_freepa_reqcontext_proc)(krb5_context,
-						     void *pa_module_context,
-						     void **request_pa_context);
-} krb5plugin_preauth_ftable_v0;
-
+    krb5_error_code (*freepa_reqcontext_proc)(krb5_context,
+   					      void *pa_module_context,
+					      void **request_pa_context);
+} krb5plugin_preauth_server_ftable_v0;
 #endif /* KRB5_PREAUTH_PLUGIN_H_INCLUDED */
Index: src/kdc/kdc_preauth.c
===================================================================
--- src/kdc/kdc_preauth.c	(revision 18642)
+++ src/kdc/kdc_preauth.c	(working copy)
@@ -299,7 +299,7 @@
 {
     struct errinfo err;
     void **preauth_plugins_ftables;
-    struct krb5plugin_preauth_ftable_v0 *ftable;
+    struct krb5plugin_preauth_server_ftable_v0 *ftable;
     int module_count, i, j, k;
     krb5_preauthtype pa_type;
     void *pa_sys_context;
@@ -317,7 +317,8 @@
     /* Get the method tables provided by the loaded plugins. */
     memset(&err, 0, sizeof(err));
     preauth_plugins_ftables = NULL;
-    if (krb5int_get_plugin_dir_data(&preauth_plugins, "preauthentication0",
+    if (krb5int_get_plugin_dir_data(&preauth_plugins,
+				    "preauthentication_server_0",
 				    &preauth_plugins_ftables, &err) != 0) {
 	return KRB5_PLUGIN_NO_HANDLE;
     }
@@ -328,15 +329,15 @@
     if (preauth_plugins_ftables != NULL) {
 	for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
 	    ftable = preauth_plugins_ftables[i];
-	    if ((ftable->server_flags_proc == NULL) &&
-		(ftable->server_edata_proc == NULL) &&
-		(ftable->server_verify_proc == NULL) &&
-		(ftable->server_return_proc == NULL)) {
+	    if ((ftable->flags_proc == NULL) &&
+		(ftable->edata_proc == NULL) &&
+		(ftable->verify_proc == NULL) &&
+		(ftable->return_proc == NULL)) {
 		continue;
 	    }
 	    for (j = 0;
-		 ftable->server_pa_type_list != NULL &&
-		 ftable->server_pa_type_list[j] > 0;
+		 ftable->pa_type_list != NULL &&
+		 ftable->pa_type_list[j] > 0;
 		 j++) {
 		module_count++;
 	    }
@@ -375,21 +376,21 @@
     if (preauth_plugins_ftables != NULL) {
 	for (i = 0; preauth_plugins_ftables[i] != NULL; i++) {
 	    ftable = preauth_plugins_ftables[i];
-	    if ((ftable->server_flags_proc == NULL) &&
-		(ftable->server_edata_proc == NULL) &&
-		(ftable->server_verify_proc == NULL) &&
-		(ftable->server_return_proc == NULL)) {
+	    if ((ftable->flags_proc == NULL) &&
+		(ftable->edata_proc == NULL) &&
+		(ftable->verify_proc == NULL) &&
+		(ftable->return_proc == NULL)) {
 		continue;
 	    }
 	    for (j = 0;
-		 ftable->server_pa_type_list != NULL &&
-		 ftable->server_pa_type_list[j] > 0;
+		 ftable->pa_type_list != NULL &&
+		 ftable->pa_type_list[j] > 0;
 		 j++) {
 		/* Try to initialize the module.  If it fails, we'll remove it
 		 * from the list of modules we'll be using. */
 		pa_sys_context = NULL;
-		server_init_proc = ftable->server_init_proc;
-		pa_type = ftable->server_pa_type_list[j];
+		server_init_proc = ftable->init_proc;
+		pa_type = ftable->pa_type_list[j];
 		if ((server_init_proc != NULL) &&
 		    ((*server_init_proc)(context, pa_type,
 					 &pa_sys_context) != 0)) {
@@ -397,18 +398,17 @@
 		    continue;
 		}
 		preauth_systems[k].name = ftable->name;
-		pa_type = ftable->server_pa_type_list[j];
+		pa_type = ftable->pa_type_list[j];
 		preauth_systems[k].type = pa_type;
-		preauth_systems[k].flags = ftable->server_flags_proc(context,
-								     pa_type);
+		preauth_systems[k].flags = ftable->flags_proc(context, pa_type);
 		preauth_systems[k].pa_sys_context = pa_sys_context;
 		preauth_systems[k].init = server_init_proc;
-		preauth_systems[k].fini = ftable->server_fini_proc;
-		preauth_systems[k].get_edata = ftable->server_edata_proc;
-		preauth_systems[k].verify_padata = ftable->server_verify_proc;
-		preauth_systems[k].return_padata = ftable->server_return_proc;
+		preauth_systems[k].fini = ftable->fini_proc;
+		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_request_context =
-		    ftable->server_freepa_reqcontext_proc;
+		    ftable->freepa_reqcontext_proc;
 		k++;
 	    }
 	}
Index: src/lib/krb5/krb/preauth2.c
===================================================================
--- src/lib/krb5/krb/preauth2.c	(revision 18642)
+++ src/lib/krb5/krb/preauth2.c	(working copy)
@@ -78,7 +78,7 @@
 			    void *module_context);
 	/* The module's table, and some of its members, copied here for
 	 * convenience when we populated the list. */
-	struct krb5plugin_preauth_ftable_v0 *ftable;
+	struct krb5plugin_preauth_client_ftable_v0 *ftable;
 	const char *name;
 	int flags, use_count;
 	krb5_error_code (*client_process)(krb5_context context,
@@ -124,7 +124,7 @@
 {
     int n_modules, n_tables, i, j, k;
     void **tables;
-    struct krb5plugin_preauth_ftable_v0 *table;
+    struct krb5plugin_preauth_client_ftable_v0 *table;
     krb5_preauth_context *context;
     void *module_context;
     krb5_preauthtype pa_type;
@@ -141,7 +141,7 @@
     /* pull out the module function tables for all of the modules */
     tables = NULL;
     if (krb5int_get_plugin_dir_data(&kcontext->preauth_plugins,
-				    "preauthentication0",
+				    "preauthentication_client_0",
 				    &tables,
 				    &kcontext->err) != 0) {
 	return;
@@ -157,9 +157,8 @@
          (tables != NULL) && (tables[n_tables] != NULL);
          n_tables++) {
 	table = tables[n_tables];
-	if ((table->client_pa_type_list != NULL) &&
-	    (table->client_process != NULL)) {
-	    for (j = 0; table->client_pa_type_list[j] > 0; j++) {
+	if ((table->pa_type_list != NULL) && (table->process != NULL)) {
+	    for (j = 0; table->pa_type_list[j] > 0; j++) {
 		n_modules++;
 	    }
 	}
@@ -182,14 +181,12 @@
     k = 0;
     for (i = 0; i < n_tables; i++) {
         table = tables[i];
-        if ((table->client_pa_type_list != NULL) &&
-            (table->client_process != NULL)) {
-            for (j = 0; table->client_pa_type_list[j] > 0; j++) {
-		pa_type = table->client_pa_type_list[j];
+        if ((table->pa_type_list != NULL) && (table->process != NULL)) {
+            for (j = 0; table->pa_type_list[j] > 0; j++) {
+		pa_type = table->pa_type_list[j];
 		module_context = NULL;
-		if ((table->client_init != NULL) &&
-		    ((*table->client_init)(kcontext, pa_type,
-		    			   &module_context) != 0)) {
+		if ((table->init != NULL) &&
+		    ((*table->init)(kcontext, pa_type, &module_context) != 0)) {
 #ifdef DEBUG
 			fprintf (stderr, "skip module \"%s\", pa_type %d\n",
 				 table->name, pa_type);
@@ -197,17 +194,16 @@
 			continue;
 		}
 		context->modules[k].pa_type = pa_type;
-		context->modules[k].enctypes = table->client_enctype_list;
+		context->modules[k].enctypes = table->enctype_list;
 		context->modules[k].module_context = module_context;
-		context->modules[k].client_fini = table->client_fini;
+		context->modules[k].client_fini = table->fini;
 		context->modules[k].ftable = table;
 		context->modules[k].name = table->name;
-		context->modules[k].flags = (*table->client_flags)(kcontext,
-								   pa_type);
+		context->modules[k].flags = (*table->flags)(kcontext, pa_type);
 		context->modules[k].use_count = 0;
-		context->modules[k].client_process = table->client_process;
-		context->modules[k].client_tryagain = table->client_tryagain;
-		context->modules[k].client_cleanup = table->client_cleanup;
+		context->modules[k].client_process = table->process;
+		context->modules[k].client_tryagain = table->tryagain;
+		context->modules[k].client_cleanup = table->cleanup;
 		context->modules[k].request_context = NULL;
 #ifdef DEBUG
 		fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n",


More information about the krbdev mailing list