[PATCH 1/2] make get_preauth_hint_list() respond via a callback

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


---
 src/kdc/do_as_req.c   |  126 +++++++++++++++++++++++++++++-------------------
 src/kdc/kdc_preauth.c |    9 ++-
 src/kdc/kdc_util.h    |    3 +-
 3 files changed, 84 insertions(+), 54 deletions(-)

diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 8419a8c..94db2e9 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -124,6 +124,8 @@ struct as_req_state {
     char *sname, *cname;
     void *pa_context;
     const krb5_fulladdr *from;
+
+    krb5_error_code code;
 };
 
 static void
@@ -147,20 +149,6 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
     if (errcode)
         goto egress;
 
-    /*
-     * Final check before handing out ticket: If the client requires
-     * preauthentication, verify that the proper kind of
-     * preauthentication was carried out.
-     */
-    state->status = missing_required_preauth(state->client,
-                                            state->server,
-                                            &state->enc_tkt_reply);
-    if (state->status) {
-        errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
-        get_preauth_hint_list(state->request, &state->rock, &state->e_data);
-        goto egress;
-    }
-
     if ((errcode = validate_forwardable(state->request, *state->client,
                                         *state->server, state->kdc_time,
                                         &state->status))) {
@@ -418,21 +406,59 @@ egress:
 }
 
 static void
+finish_missing_required_preauth(void *data)
+{
+    struct as_req_state *state = (struct as_req_state *)data;
+
+    finish_process_as_req(state, state->code);
+}
+
+static void
+check_missing_required_preauth(void *data)
+{
+    struct as_req_state *state = (struct as_req_state *)data;
+
+    if (state->code == 0) {
+            /*
+             * Final check before handing out ticket: If the client requires
+             * preauthentication, verify that the proper kind of
+             * preauthentication was carried out.
+             */
+            state->status = missing_required_preauth(state->client,
+                                                    state->server,
+                                                    &state->enc_tkt_reply);
+            if (state->status) {
+                state->code = KRB5KDC_ERR_PREAUTH_REQUIRED;
+                get_preauth_hint_list(state->request, &state->rock,
+                                      &state->e_data,
+                                      finish_missing_required_preauth, state);
+                return;
+            }
+    }
+
+    finish_missing_required_preauth(state);
+}
+
+
+static void
 finish_preauth(void *arg, krb5_error_code errcode)
 {
     struct as_req_state *state = arg;
 
+    state->code = errcode;
     if (errcode) {
-        if (errcode == KRB5KDC_ERR_PREAUTH_FAILED)
-            get_preauth_hint_list(state->request, &state->rock,
-                                  &state->e_data);
-
         state->status = "PREAUTH_FAILED";
         if (vague_errors)
-            errcode = KRB5KRB_ERR_GENERIC;
+            state->code = KRB5KRB_ERR_GENERIC;
+
+        if (errcode == KRB5KDC_ERR_PREAUTH_FAILED) {
+            get_preauth_hint_list(state->request, &state->rock, &state->e_data,
+                                  check_missing_required_preauth, state);
+            return;
+        }
     }
 
-    finish_process_as_req(state, errcode);
+    check_missing_required_preauth(state);
 }
 
 /*ARGSUSED*/
@@ -440,7 +466,6 @@ void
 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
                const krb5_fulladdr *from, loop_respond_fn respond, void *arg)
 {
-    krb5_error_code errcode;
     krb5_timestamp rtime;
     unsigned int s_flags = 0;
     krb5_principal_data client_princ;
@@ -476,6 +501,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     state->pa_context = NULL;
     state->from = from;
     memset(&state->rock, 0, sizeof(state->rock));
+    state->code = 0;
 
 #if APPLE_PKINIT
     asReqDebug("process_as_req top realm %s name %s\n",
@@ -484,23 +510,23 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 
     if (state->request->msg_type != KRB5_AS_REQ) {
         state->status = "msg_type mismatch";
-        errcode = KRB5_BADMSGTYPE;
+        state->code = KRB5_BADMSGTYPE;
         goto errout;
     }
-    errcode = kdc_make_rstate(&state->rstate);
-    if (errcode != 0) {
+    state->code = kdc_make_rstate(&state->rstate);
+    if (state->code != 0) {
         state->status = "constructing state";
         goto errout;
     }
     if (fetch_asn1_field((unsigned char *) req_pkt->data,
                          1, 4, &encoded_req_body) != 0) {
-        errcode = ASN1_BAD_ID;
+        state->code = ASN1_BAD_ID;
         state->status = "Finding req_body";
         goto errout;
     }
-    errcode = kdc_find_fast(&state->request, &encoded_req_body,
+    state->code = kdc_find_fast(&state->request, &encoded_req_body,
                             NULL /*TGS key*/, NULL, state->rstate);
-    if (errcode) {
+    if (state->code) {
         state->status = "error decoding FAST";
         goto errout;
     }
@@ -508,10 +534,10 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     state->rock.rstate = state->rstate;
     if (!state->request->client) {
         state->status = "NULL_CLIENT";
-        errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+        state->code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
         goto errout;
     }
-    if ((errcode = krb5_unparse_name(kdc_context,
+    if ((state->code = krb5_unparse_name(kdc_context,
                                      state->request->client,
                                      &state->cname))) {
         state->status = "UNPARSING_CLIENT";
@@ -520,10 +546,10 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     limit_string(state->cname);
     if (!state->request->server) {
         state->status = "NULL_SERVER";
-        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+        state->code = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
         goto errout;
     }
-    if ((errcode = krb5_unparse_name(kdc_context,
+    if ((state->code = krb5_unparse_name(kdc_context,
                                      state->request->server,
                                      &state->sname))) {
         state->status = "UNPARSING_SERVER";
@@ -549,16 +575,16 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     if (include_pac_p(kdc_context, state->request)) {
         setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
     }
-    errcode = krb5_db_get_principal(kdc_context, state->request->client,
+    state->code = krb5_db_get_principal(kdc_context, state->request->client,
                                     state->c_flags, &state->client);
-    if (errcode == KRB5_KDB_NOENTRY) {
+    if (state->code == KRB5_KDB_NOENTRY) {
         state->status = "CLIENT_NOT_FOUND";
         if (vague_errors)
-            errcode = KRB5KRB_ERR_GENERIC;
+            state->code = KRB5KRB_ERR_GENERIC;
         else
-            errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+            state->code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
         goto errout;
-    } else if (errcode) {
+    } else if (state->code) {
         state->status = "LOOKING_UP_CLIENT";
         goto errout;
     }
@@ -571,7 +597,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     if (!is_local_principal(state->client->princ)) {
         /* Entry is a referral to another realm */
         state->status = "REFERRAL";
-        errcode = KRB5KDC_ERR_WRONG_REALM;
+        state->code = KRB5KDC_ERR_WRONG_REALM;
         goto errout;
     }
 
@@ -592,29 +618,29 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
         setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
     }
-    errcode = krb5_db_get_principal(kdc_context, state->request->server,
+    state->code = krb5_db_get_principal(kdc_context, state->request->server,
                                     s_flags, &state->server);
-    if (errcode == KRB5_KDB_NOENTRY) {
+    if (state->code == KRB5_KDB_NOENTRY) {
         state->status = "SERVER_NOT_FOUND";
-        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+        state->code = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
         goto errout;
-    } else if (errcode) {
+    } else if (state->code) {
         state->status = "LOOKING_UP_SERVER";
         goto errout;
     }
 
-    if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
+    if ((state->code = krb5_timeofday(kdc_context, &state->kdc_time))) {
         state->status = "TIMEOFDAY";
         goto errout;
     }
     state->authtime = state->kdc_time; /* for audit_as_request() */
 
-    if ((errcode = validate_as_request(state->request, *state->client,
+    if ((state->code = validate_as_request(state->request, *state->client,
                                        *state->server, state->kdc_time,
                                        &state->status, &state->e_data))) {
         if (!state->status)
             state->status = "UNKNOWN_REASON";
-        errcode += ERROR_TABLE_BASE_krb5;
+        state->code += ERROR_TABLE_BASE_krb5;
         goto errout;
     }
 
@@ -626,11 +652,11 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
                                              state->request->ktype)) == 0) {
         /* unsupported ktype */
         state->status = "BAD_ENCRYPTION_TYPE";
-        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+        state->code = KRB5KDC_ERR_ETYPE_NOSUPP;
         goto errout;
     }
 
-    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
+    if ((state->code = krb5_c_make_random_key(kdc_context, useenctype,
                                           &state->session_key))) {
         state->status = "RANDOM_KEY_FAILED";
         goto errout;
@@ -736,16 +762,16 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
         if (!krb5_principal_compare_any_realm(kdc_context,
                                               state->request->client,
                                               krb5_anonymous_principal())) {
-            errcode = KRB5KDC_ERR_BADOPTION;
+            state->code = KRB5KDC_ERR_BADOPTION;
             state->status = "Anonymous requested but anonymous "
                               "principal not used.";
             goto errout;
         }
         setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
         krb5_free_principal(kdc_context, state->request->client);
-        errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
+        state->code = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
                                       &state->request->client);
-        if (errcode) {
+        if (state->code) {
             state->status = "Copying anonymous principal";
             goto errout;
         }
@@ -765,7 +791,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     }
 
 errout:
-    finish_process_as_req(state, errcode);
+    check_missing_required_preauth(state);
 }
 
 static krb5_error_code
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index bdcc71b..04a2be6 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -769,7 +769,8 @@ const char *missing_required_preauth(krb5_db_entry *client,
 
 void
 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
-                      krb5_pa_data ***e_data_out)
+                      krb5_pa_data ***e_data_out,
+                      void (*respond)(void *arg), void *arg)
 {
     int hw_only;
     preauth_system *ap;
@@ -781,8 +782,10 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
     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)
+    if (pa_data == 0) {
+        (*respond)(arg);
         return;
+    }
     pa = pa_data;
 
     for (ap = preauth_systems; ap->type != -1; ap++) {
@@ -824,7 +827,7 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
 
 errout:
     krb5_free_pa_data(kdc_context, pa_data);
-    return;
+    (*respond)(arg);
 }
 
 /*
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index e33f606..20390fc 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -168,7 +168,8 @@ missing_required_preauth (krb5_db_entry *client,
                           krb5_enc_tkt_part *enc_tkt_reply);
 void
 get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
-                      krb5_pa_data ***e_data_out);
+                      krb5_pa_data ***e_data_out,
+                      void (*respond)(void *arg), void *arg);
 void
 load_preauth_plugins(krb5_context context);
 void
-- 
1.7.6.4




More information about the krbdev mailing list