[PATCH 2/2] make kdcpreauth get edata respond via callback

Nathaniel McCallum npmccallum at redhat.com
Thu Oct 13 18:57:38 EDT 2011


---
 src/include/krb5/preauth_plugin.h                |    8 +-
 src/kdc/kdc_preauth.c                            |  216 +++++++++++++++-------
 src/kdc/kdc_preauth_ec.c                         |    8 +-
 src/kdc/kdc_preauth_encts.c                      |    5 +-
 src/plugins/preauth/cksum_body/cksum_body_main.c |   11 +-
 src/plugins/preauth/pkinit/pkinit_srv.c          |   14 +-
 src/plugins/preauth/wpse/wpse_main.c             |    8 +-
 7 files changed, 181 insertions(+), 89 deletions(-)

diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index e618edd..d64434f 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -427,12 +427,16 @@ typedef int
  * 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
+typedef void
+(*krb5_kdcpreauth_edata_respond_fn)(void *arg, krb5_error_code error_code);
+typedef void
 (*krb5_kdcpreauth_edata_fn)(krb5_context context, krb5_kdc_req *request,
                             krb5_kdcpreauth_callbacks cb,
                             krb5_kdcpreauth_rock rock,
                             krb5_kdcpreauth_moddata moddata,
-                            krb5_pa_data *pa_out);
+                            krb5_pa_data *pa_out,
+                            krb5_kdcpreauth_edata_respond_fn respond,
+                            void *arg);
 
 /*
  * Responder for krb5_kdcpreauth_verify_fn.  Invoke with the arg parameter
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 04a2be6..57b79a5 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -111,20 +111,23 @@ verify_enc_timestamp(krb5_context, krb5_data *req_pkt, krb5_kdc_req *request,
                      krb5_kdcpreauth_moddata moddata,
                      krb5_kdcpreauth_verify_respond_fn respond, void *arg);
 
-static krb5_error_code
+static void
 get_enc_ts(krb5_context context, krb5_kdc_req *request,
            krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-           krb5_kdcpreauth_moddata modata, krb5_pa_data *data);
+           krb5_kdcpreauth_moddata modata, krb5_pa_data *data,
+           krb5_kdcpreauth_edata_respond_fn respond, void *arg);
 
-static krb5_error_code
+static void
 get_etype_info(krb5_context context, krb5_kdc_req *request,
                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-               krb5_kdcpreauth_moddata moddata, krb5_pa_data *data);
+               krb5_kdcpreauth_moddata moddata, krb5_pa_data *data,
+               krb5_kdcpreauth_edata_respond_fn respond, void *arg);
 
-static krb5_error_code
+static void
 get_etype_info2(krb5_context context, krb5_kdc_req *request,
                 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data);
+                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data,
+                krb5_kdcpreauth_edata_respond_fn respond, void *arg);
 
 static krb5_error_code
 etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
@@ -767,67 +770,137 @@ const char *missing_required_preauth(krb5_db_entry *client,
     return 0;
 }
 
+struct preauth_hint_list_state {
+    void (*respond)(void *arg);
+    void *arg;
+    kdc_realm_t *realm;
+
+    krb5_kdcpreauth_rock rock;
+    krb5_kdc_req *request;
+    krb5_pa_data ***e_data_out;
+
+    int hw_only;
+    preauth_system *ap;
+    krb5_pa_data **pa_data, **pa;
+};
+
+static void
+preauth_hint_list_finish(struct preauth_hint_list_state *arg,
+                         krb5_error_code code)
+{
+    void (*oldrespond)(void *arg) = arg->respond;
+    void *oldarg = arg->arg;
+
+    if (!code) {
+        if (arg->pa_data[0] == 0) {
+            krb5_klog_syslog(LOG_INFO,
+                             _("%spreauth required but hint list is empty"),
+                             arg->hw_only ? "hw" : "");
+        }
+        /*
+         * If we fail to get the cookie it is probably
+         * still reasonable to continue with the response
+         */
+        kdc_preauth_get_cookie(arg->rock->rstate, arg->pa);
+
+        *arg->e_data_out = arg->pa_data;
+        arg->pa_data = NULL;
+    }
+
+    krb5_free_pa_data(kdc_context, arg->pa_data);
+    free(arg);
+    (*oldrespond)(oldarg);
+}
+
+static void
+preauth_hint_list_next(struct preauth_hint_list_state *arg);
+
+static void
+finish_get_edata(void *arg, krb5_error_code code)
+{
+    struct preauth_hint_list_state *state = arg;
+
+    kdc_active_realm = state->realm;
+    if (code) {
+        /* just failed on this type, continue */
+        free(*state->pa);
+        *state->pa = 0;
+    } else
+        state->pa++;
+
+    state->ap++;
+    preauth_hint_list_next(state);
+}
+
+static void
+preauth_hint_list_next(struct preauth_hint_list_state *arg)
+{
+    if (arg->ap->type == -1) {
+        preauth_hint_list_finish(arg, 0);
+        return;
+    }
+
+    if (arg->hw_only && !(arg->ap->flags & PA_HARDWARE))
+        goto next;
+    if (arg->ap->flags & PA_PSEUDO)
+        goto next;
+
+    *arg->pa = malloc(sizeof(krb5_pa_data));
+    if (!*arg->pa) {
+        preauth_hint_list_finish(arg, ENOMEM);
+        return;
+    }
+
+    memset(*arg->pa, 0, sizeof(krb5_pa_data));
+    (*arg->pa)->magic = KV5M_PA_DATA;
+    (*arg->pa)->pa_type = arg->ap->type;
+    if (arg->ap->get_edata) {
+        arg->ap->get_edata(kdc_context, arg->request, &callbacks, arg->rock,
+                           arg->ap->moddata, *arg->pa, finish_get_edata, arg);
+        return;
+    }
+    arg->pa++;
+
+next:
+    arg->ap++;
+    preauth_hint_list_next(arg);
+}
+
 void
 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
                       krb5_pa_data ***e_data_out,
                       void (*respond)(void *arg), void *arg)
 {
-    int hw_only;
-    preauth_system *ap;
-    krb5_pa_data **pa_data, **pa;
-    krb5_error_code retval;
+    struct preauth_hint_list_state *state;
 
     *e_data_out = NULL;
 
-    hw_only = isflagset(rock->client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
-    /* Allocate two extra entries for the cookie and the terminator. */
-    pa_data = calloc(n_preauth_systems + 2, sizeof(krb5_pa_data *));
-    if (pa_data == 0) {
+    /* Allocate our state. */
+    state = malloc(sizeof(*state));
+    if (!state) {
         (*respond)(arg);
         return;
     }
-    pa = pa_data;
+    state->hw_only = isflagset(rock->client->attributes,
+                                  KRB5_KDB_REQUIRES_HW_AUTH);
+    state->respond = respond;
+    state->arg = arg;
+    state->request = request;
+    state->rock = rock;
+    state->realm = kdc_active_realm;
+    state->e_data_out = e_data_out;
 
-    for (ap = preauth_systems; ap->type != -1; ap++) {
-        if (hw_only && !(ap->flags & PA_HARDWARE))
-            continue;
-        if (ap->flags & PA_PSEUDO)
-            continue;
-        *pa = malloc(sizeof(krb5_pa_data));
-        if (*pa == 0)
-            goto errout;
-        memset(*pa, 0, sizeof(krb5_pa_data));
-        (*pa)->magic = KV5M_PA_DATA;
-        (*pa)->pa_type = ap->type;
-        if (ap->get_edata) {
-            retval = ap->get_edata(kdc_context, request, &callbacks, rock,
-                                   ap->moddata, *pa);
-            if (retval) {
-                /* just failed on this type, continue */
-                free(*pa);
-                *pa = 0;
-                continue;
-            }
-        }
-        pa++;
-    }
-    if (pa_data[0] == 0) {
-        krb5_klog_syslog(LOG_INFO,
-                         _("%spreauth required but hint list is empty"),
-                         hw_only ? "hw" : "");
+    /* Allocate two extra entries for the cookie and the terminator. */
+    state->pa_data = calloc(n_preauth_systems + 2, sizeof(krb5_pa_data *));
+    if (!state->pa_data) {
+        free(state);
+        (*respond)(arg);
+        return;
     }
-    /*
-     * If we fail to get the cookie it is probably
-     * still reasonable to continue with the response
-     */
-    kdc_preauth_get_cookie(rock->rstate, pa);
-
-    *e_data_out = pa_data;
-    pa_data = NULL;
 
-errout:
-    krb5_free_pa_data(kdc_context, pa_data);
-    (*respond)(arg);
+    state->pa = state->pa_data;
+    state->ap = preauth_systems;
+    preauth_hint_list_next(state);
 }
 
 /*
@@ -978,7 +1051,7 @@ finish_check_padata(struct padata_state *state, krb5_error_code code)
 }
 
 static void
-next_padata(struct padata_state *state);
+next_padata(struct padata_state *arg);
 
 static void
 finish_verify_padata(void *arg, krb5_error_code code,
@@ -1268,14 +1341,13 @@ request_contains_enctype(krb5_context context,  const krb5_kdc_req *request,
     return 0;
 }
 
-static krb5_error_code
+static void
 get_enc_ts(krb5_context context, krb5_kdc_req *request,
            krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-           krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
+           krb5_kdcpreauth_moddata moddata, krb5_pa_data *data,
+           krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
-    if (rock->rstate->armor_key != NULL)
-        return ENOENT;
-    return 0;
+    (*respond)(arg, rock->rstate->armor_key ? ENOENT : 0);
 }
 
 
@@ -1523,27 +1595,33 @@ cleanup:
     return retval;
 }
 
-static krb5_error_code
+static void
 get_etype_info(krb5_context context, krb5_kdc_req *request,
                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-               krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data)
+               krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data,
+               krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
     int i;
     for (i=0;  i < request->nktypes; i++) {
-        if (enctype_requires_etype_info_2(request->ktype[i]))
-            return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will
-                                                        * skip this
-                                                        * type*/
+        if (enctype_requires_etype_info_2(request->ktype[i])) {
+            /* Caller will skip this type. */
+            (*respond)(arg, KRB5KDC_ERR_PADATA_TYPE_NOSUPP);
+            return;
+        }
     }
-    return etype_info_helper(context, request, rock->client, pa_data, 0);
+
+    (*respond)(arg, etype_info_helper(context, request, rock->client,
+                                      pa_data, 0));
 }
 
-static krb5_error_code
+static void
 get_etype_info2(krb5_context context, krb5_kdc_req *request,
                 krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data)
+                krb5_kdcpreauth_moddata moddata, krb5_pa_data *pa_data,
+                krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
-    return etype_info_helper(context, request, rock->client, pa_data, 1);
+    (*respond)(arg, etype_info_helper(context, request, rock->client,
+                                      pa_data, 1));
 }
 
 static krb5_error_code
diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c
index e5f5d6e..3ca56cf 100644
--- a/src/kdc/kdc_preauth_ec.c
+++ b/src/kdc/kdc_preauth_ec.c
@@ -33,14 +33,14 @@
 #include <krb5/preauth_plugin.h>
 #include "kdc_util.h"
 
-static krb5_error_code
+static void
 ec_edata(krb5_context context, krb5_kdc_req *request,
          krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-         krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
+         krb5_kdcpreauth_moddata moddata, krb5_pa_data *data,
+         krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
     krb5_keyblock *armor_key = cb->fast_armor(context, rock);
-
-    return (armor_key == NULL) ? ENOENT : 0;
+    (*respond)(arg, (armor_key == NULL) ? ENOENT : 0);
 }
 
 static void
diff --git a/src/kdc/kdc_preauth_encts.c b/src/kdc/kdc_preauth_encts.c
index 48626d9..2c120f0 100644
--- a/src/kdc/kdc_preauth_encts.c
+++ b/src/kdc/kdc_preauth_encts.c
@@ -31,11 +31,12 @@
 static krb5_error_code
 enc_ts_get(krb5_context context, krb5_kdc_req *request,
 	   krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-	   krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
+	   krb5_kdcpreauth_moddata moddata, krb5_pa_data *data,
+           krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
     krb5_keyblock *armor_key = cb->fast_armor(context, rock);
 
-    return (armor_key != NULL) ? ENOENT : 0;
+    (*respond)(arg, (armor_key != NULL) ? ENOENT : 0);
 }
 
 static void
diff --git a/src/plugins/preauth/cksum_body/cksum_body_main.c b/src/plugins/preauth/cksum_body/cksum_body_main.c
index da2643f..5ea2dca 100644
--- a/src/plugins/preauth/cksum_body/cksum_body_main.c
+++ b/src/plugins/preauth/cksum_body/cksum_body_main.c
@@ -274,7 +274,8 @@ server_fini(krb5_context kcontext, krb5_kdcpreauth_moddata moddata)
 static krb5_error_code
 server_get_edata(krb5_context kcontext, krb5_kdc_req *request,
                  krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
-                 krb5_kdcpreauth_moddata moddata, krb5_pa_data *data)
+                 krb5_kdcpreauth_moddata moddata, krb5_pa_data *data,
+                 krb5_kdcpreauth_edata_respond_fn respond, void *arg)
 {
     krb5_keyblock *keys;
     krb5_int32 *enctypes, enctype;
@@ -285,7 +286,8 @@ server_get_edata(krb5_context kcontext, krb5_kdc_req *request,
 #ifdef DEBUG
         fprintf(stderr, "Error retrieving client keys.\n");
 #endif
-        return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+        (*respond)(arg, KRB5KDC_ERR_PADATA_TYPE_NOSUPP);
+        return;
     }
 
     /* Count which types of keys we've got. */
@@ -295,7 +297,8 @@ server_get_edata(krb5_context kcontext, krb5_kdc_req *request,
     enctypes = malloc((unsigned)i * 4);
     if (enctypes == NULL) {
         cb->free_keys(kcontext, rock, keys);
-        return ENOMEM;
+        (*respond)(arg, ENOMEM);
+        return;
     }
 #ifdef DEBUG
     fprintf(stderr, "Supported enctypes = {");
@@ -314,7 +317,7 @@ server_get_edata(krb5_context kcontext, krb5_kdc_req *request,
     data->length = (i * 4);
     data->contents = (unsigned char *) enctypes;
     cb->free_keys(kcontext, rock, keys);
-    return 0;
+    (*respond)(arg, 0);
 }
 
 /* Verify a request from a client. */
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index d209f9e..bb52b25 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -95,13 +95,15 @@ cleanup:
     return retval;
 }
 
-static krb5_error_code
+static void
 pkinit_server_get_edata(krb5_context context,
                         krb5_kdc_req *request,
                         krb5_kdcpreauth_callbacks cb,
                         krb5_kdcpreauth_rock rock,
                         krb5_kdcpreauth_moddata moddata,
-                        krb5_pa_data *data)
+                        krb5_pa_data *data,
+                        krb5_kdcpreauth_edata_respond_fn respond,
+                        void *arg)
 {
     krb5_error_code retval = 0;
     pkinit_kdc_context plgctx = NULL;
@@ -111,8 +113,10 @@ pkinit_server_get_edata(krb5_context context,
 
     /* Remove (along with armor_key) when FAST PKINIT is settled. */
     /* Don't advertise PKINIT if the client used FAST. */
-    if (armor_key != NULL)
-        return EINVAL;
+    if (armor_key != NULL) {
+        (*respond)(arg, EINVAL);
+        return;
+    }
 
     /*
      * If we don't have a realm context for the given realm,
@@ -122,7 +126,7 @@ pkinit_server_get_edata(krb5_context context,
     if (plgctx == NULL)
         retval = EINVAL;
 
-    return retval;
+    (*respond)(arg, retval);
 }
 
 static krb5_error_code
diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c
index 4da2c2f..f281536 100644
--- a/src/plugins/preauth/wpse/wpse_main.c
+++ b/src/plugins/preauth/wpse/wpse_main.c
@@ -243,18 +243,20 @@ server_free_modreq(krb5_context kcontext,
 
 /* Obtain and return any preauthentication data (which is destined for the
  * client) which matches type data->pa_type. */
-static krb5_error_code
+static void
 server_get_edata(krb5_context kcontext,
                  krb5_kdc_req *request,
                  krb5_kdcpreauth_callbacks cb,
                  krb5_kdcpreauth_rock rock,
                  krb5_kdcpreauth_moddata moddata,
-                 krb5_pa_data *data)
+                 krb5_pa_data *data,
+                 krb5_kdcpreauth_edata_respond_fn respond,
+                 void *arg)
 {
     /* Return zero bytes of data. */
     data->length = 0;
     data->contents = NULL;
-    return 0;
+    (*respond)(arg, 0);
 }
 
 /* Verify a request from a client. */
-- 
1.7.6.4




More information about the krbdev mailing list