Make kdcpreauth verify respond via callback
authorGreg Hudson <ghudson@mit.edu>
Mon, 3 Oct 2011 19:14:05 +0000 (19:14 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 3 Oct 2011 19:14:05 +0000 (19:14 +0000)
From npmccallum@redhat.com with changes.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25294 dc483132-0cff-0310-8789-dd5450dbe970

src/include/krb5/preauth_plugin.h
src/kdc/kdc_preauth.c
src/kdc/kdc_preauth_ec.c
src/plugins/preauth/cksum_body/cksum_body_main.c
src/plugins/preauth/pkinit/pkinit_srv.c
src/plugins/preauth/securid_sam2/securid_sam2_main.c
src/plugins/preauth/wpse/wpse_main.c

index d376098b375d83853bb16623609982ec75f2710e..c620d6cdb4b3868636370ecc2fb750ff080317ba 100644 (file)
@@ -419,7 +419,13 @@ typedef krb5_error_code
  * per-request module data for consumption by the return_fn or free_modreq_fn
  * below.
  */
-typedef krb5_error_code
+typedef void
+(*krb5_kdcpreauth_verify_respond_fn)(void *arg, krb5_error_code code,
+                                     krb5_kdcpreauth_modreq modreq,
+                                     krb5_data *e_data,
+                                     krb5_authdata **authz_data);
+
+typedef void
 (*krb5_kdcpreauth_verify_fn)(krb5_context context,
                              struct _krb5_db_entry_new *client,
                              krb5_data *req_pkt, krb5_kdc_req *request,
@@ -427,9 +433,8 @@ typedef krb5_error_code
                              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);
+                             krb5_kdcpreauth_verify_respond_fn respond,
+                             void *arg);
 
 /*
  * Optional: generate preauthentication response data to send to the client as
index 5e1312656e8e1b466490164def857df38b445f20..ec10e170e586a79aa8cfa3064bbc8a280e181f48 100644 (file)
@@ -104,14 +104,14 @@ typedef struct preauth_system_st {
     krb5_kdcpreauth_free_modreq_fn free_modreq;
 } preauth_system;
 
-static krb5_error_code
+static void
 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);
+                     krb5_kdcpreauth_verify_respond_fn respond,
+                     void *arg);
 
 static krb5_error_code
 get_enc_ts(krb5_context context, krb5_kdc_req *request,
@@ -933,161 +933,79 @@ add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
     return 0;
 }
 
-/*
- * This routine is called to verify the preauthentication information
- * for a V5 request.
- *
- * Returns 0 if the pre-authentication is valid, non-zero to indicate
- * an error code of some sort.
- */
+struct padata_state {
+    kdc_preauth_respond_fn respond;
+    void *arg;
+    kdc_realm_t *realm;
 
-void
-check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
-              krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
-              void **padata_context, krb5_data *e_data,
-              kdc_preauth_respond_fn respond, void *arg)
-{
-    krb5_error_code retval = 0;
-    krb5_pa_data **padata;
-    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;
-    int use_saved_retval = 0;
-    const char *emsg;
-    krb5_authdata **tmp_authz_data = NULL;
+    krb5_pa_data **padata;
+    int pa_found;
+    krb5_context context;
+    krb5_db_entry *client;
+    krb5_data *req_pkt;
+    krb5_kdc_req *request;
+    krb5_enc_tkt_part *enc_tkt_reply;
+    void **padata_context;
+    krb5_data *e_data;
 
-    if (request->padata == 0) {
-        (*respond)(arg, 0);
-        return;
-    }
+    preauth_system *pa_sys;
+    krb5_data *pa_e_data;
+    int pa_ok;
+    krb5_error_code saved_code;
+};
 
-    if (make_padata_context(context, padata_context) != 0) {
-        (*respond)(arg, KRB5KRB_ERR_GENERIC);
-        return;
-    }
+static void
+finish_check_padata(struct padata_state *state, krb5_error_code code)
+{
+    kdc_preauth_respond_fn oldrespond;
+    void *oldarg;
 
-#ifdef DEBUG
-    krb5_klog_syslog (LOG_DEBUG, "checking padata");
-#endif
-    for (padata = request->padata; *padata; padata++) {
-#ifdef DEBUG
-        krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type);
-#endif
-        if (find_pa_system((*padata)->pa_type, &pa_sys))
-            continue;
-        if (find_modreq(pa_sys, *padata_context, &modreq_ptr))
-            continue;
-#ifdef DEBUG
-        krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name);
-#endif
-        if (pa_sys->verify_padata == 0)
-            continue;
-        pa_found++;
-        retval = pa_sys->verify_padata(context, client, req_pkt, request,
-                                       enc_tkt_reply, *padata,
-                                       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",
-                              pa_sys->name, emsg);
-            krb5_free_error_message (context, emsg);
-            /* Ignore authorization data returned from modules that fail */
-            if (tmp_authz_data != NULL) {
-                krb5_free_authdata(context, tmp_authz_data);
-                tmp_authz_data = NULL;
-            }
-            if (pa_sys->flags & PA_REQUIRED) {
-                /* free up any previous edata we might have been saving */
-                if (pa_e_data != NULL)
-                    krb5_free_data(context, pa_e_data);
-                pa_e_data = tmp_e_data;
-                tmp_e_data = NULL;
-                use_saved_retval = 0; /* Make sure we use the current retval */
-                pa_ok = 0;
-                break;
-            }
-            /*
-             * We'll return edata from either the first PA_REQUIRED module
-             * that fails, or the first non-PA_REQUIRED module that fails.
-             * Hang on to edata from the first non-PA_REQUIRED module.
-             * If we've already got one saved, simply discard this one.
-             */
-            if (tmp_e_data != NULL) {
-                if (pa_e_data == NULL) {
-                    /* save the first error code and e-data */
-                    pa_e_data = tmp_e_data;
-                    tmp_e_data = NULL;
-                    saved_retval = retval;
-                    use_saved_retval = 1;
-                } else {
-                    /* discard this extra e-data from non-PA_REQUIRED module */
-                    krb5_free_data(context, tmp_e_data);
-                    tmp_e_data = NULL;
-                }
-            }
-        } else {
-#ifdef DEBUG
-            krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
-#endif
-            /* Ignore any edata returned on success */
-            if (tmp_e_data != NULL) {
-                krb5_free_data(context, tmp_e_data);
-                tmp_e_data = NULL;
-            }
-            /* Add any authorization data to the ticket */
-            if (tmp_authz_data != NULL) {
-                add_authorization_data(enc_tkt_reply, tmp_authz_data);
-                free(tmp_authz_data);
-                tmp_authz_data = NULL;
-            }
-            pa_ok = 1;
-            if (pa_sys->flags & PA_SUFFICIENT)
-                break;
-        }
-    }
+    assert(state);
+    oldrespond = state->respond;
+    oldarg = state->arg;
 
     /* Don't bother copying and returning e-data on success */
-    if (pa_ok && pa_e_data != NULL) {
-        krb5_free_data(context, pa_e_data);
-        pa_e_data = NULL;
+    if (state->pa_ok && state->pa_e_data != NULL) {
+        krb5_free_data(state->context, state->pa_e_data);
+        state->pa_e_data = NULL;
     }
+
     /* Return any e-data from the preauth that caused us to exit the loop */
-    if (pa_e_data != NULL) {
-        e_data->data = malloc(pa_e_data->length);
-        if (e_data->data == NULL) {
-            krb5_free_data(context, pa_e_data);
-            (*respond)(arg, KRB5KRB_ERR_GENERIC);
+    if (state->pa_e_data != NULL) {
+        state->e_data->data = malloc(state->pa_e_data->length);
+        if (state->e_data->data == NULL) {
+            krb5_free_data(state->context, state->pa_e_data);
+            free(state);
+            (*oldrespond)(oldarg, KRB5KRB_ERR_GENERIC);
             return;
         }
-        memcpy(e_data->data, pa_e_data->data, pa_e_data->length);
-        e_data->length = pa_e_data->length;
-        krb5_free_data(context, pa_e_data);
-        pa_e_data = NULL;
-        if (use_saved_retval != 0)
-            retval = saved_retval;
+        memcpy(state->e_data->data, state->pa_e_data->data,
+               state->pa_e_data->length);
+        state->e_data->length = state->pa_e_data->length;
+        krb5_free_data(state->context, state->pa_e_data);
+        state->pa_e_data = NULL;
     }
 
-    if (pa_ok) {
-        (*respond)(arg, 0);
+    if (state->pa_ok) {
+        free(state);
+        (*oldrespond)(oldarg, 0);
         return;
     }
 
     /* pa system was not found; we may return PREAUTH_REQUIRED later,
        but we did not actually fail to verify the pre-auth. */
-    if (!pa_found) {
-        (*respond)(arg, 0);
+    if (!state->pa_found) {
+        free(state);
+        (*oldrespond)(oldarg, 0);
         return;
     }
-
+    free(state);
 
     /* The following switch statement allows us
      * to return some preauth system errors back to the client.
      */
-    switch(retval) {
+    switch(code) {
     case 0: /* in case of PA-PAC-REQUEST with no PA-ENC-TIMESTAMP */
     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
     case KRB5KRB_AP_ERR_SKEW:
@@ -1111,17 +1029,183 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
     case KRB5KDC_ERR_CERTIFICATE_MISMATCH:
     case KRB5KDC_ERR_KDC_NOT_TRUSTED:
     case KRB5KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
-        /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
+        /* This value is shared with
+         *     KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
         /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
     case KRB5KDC_ERR_DISCARD:
         /* pkinit alg-agility */
     case KRB5KDC_ERR_NO_ACCEPTABLE_KDF:
-        (*respond)(arg, retval);
+        (*oldrespond)(oldarg, code);
         return;
     default:
-        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED);
+        (*oldrespond)(oldarg, KRB5KDC_ERR_PREAUTH_FAILED);
+        return;
+    }
+}
+
+static void
+next_padata(struct padata_state *state);
+
+static void
+finish_verify_padata(void *arg, krb5_error_code code,
+                     krb5_kdcpreauth_modreq modreq, krb5_data *e_data,
+                     krb5_authdata **authz_data)
+{
+    struct padata_state *state = arg;
+    const char *emsg;
+
+    assert(state);
+    kdc_active_realm = state->realm; /* Restore the realm. */
+    *state->modreq_ptr = modreq;
+
+    if (code) {
+        emsg = krb5_get_error_message(state->context, code);
+        krb5_klog_syslog(LOG_INFO, "preauth (%s) verify failure: %s",
+                         state->pa_sys->name, emsg);
+        krb5_free_error_message(state->context, emsg);
+
+        /* Ignore authorization data returned from modules that fail */
+        if (authz_data != NULL) {
+            krb5_free_authdata(state->context, authz_data);
+            authz_data = NULL;
+        }
+
+        /*
+         * We'll return edata from either the first PA_REQUIRED module
+         * that fails, or the first non-PA_REQUIRED module that fails.
+         * Hang on to edata from the first non-PA_REQUIRED module.
+         * If we've already got one saved, simply discard this one.
+         */
+        if (state->pa_sys->flags & PA_REQUIRED) {
+            /* free up any previous edata we might have been saving */
+            if (state->pa_e_data != NULL)
+                krb5_free_data(state->context, state->pa_e_data);
+            state->pa_e_data = e_data;
+
+            /* Make sure we use the current retval */
+            state->pa_ok = 0;
+            finish_check_padata(state, code);
+            return;
+        } else if (state->pa_e_data == NULL) {
+            /* save the first error code and e-data */
+            state->pa_e_data = e_data;
+            state->saved_code = code;
+        } else if (e_data != NULL) {
+            /* discard this extra e-data from non-PA_REQUIRED module */
+            krb5_free_data(state->context, e_data);
+        }
+    } else {
+#ifdef DEBUG
+        krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
+#endif
+
+        /* Ignore any edata returned on success */
+        if (e_data != NULL)
+            krb5_free_data(state->context, e_data);
+
+        /* Add any authorization data to the ticket */
+        if (authz_data != NULL) {
+            add_authorization_data(state->enc_tkt_reply, authz_data);
+            free(authz_data);
+        }
+
+        state->pa_ok = 1;
+        if (state->pa_sys->flags & PA_SUFFICIENT) {
+            finish_check_padata(state, state->saved_code);
+            return;
+        }
+    }
+
+    next_padata(state);
+}
+
+static void
+next_padata(struct padata_state *state)
+{
+    assert(state);
+    if (!state->padata)
+        state->padata = state->request->padata;
+    else
+        state->padata++;
+
+    if (!*state->padata) {
+        finish_check_padata(state, state->saved_code);
+        return;
+    }
+
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*state->padata)->pa_type);
+#endif
+    if (find_pa_system((*state->padata)->pa_type, &state->pa_sys))
+        goto next;
+    if (find_modreq(state->pa_sys, *state->padata_context, &state->modreq_ptr))
+        goto next;
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", state->pa_sys->name);
+#endif
+    if (state->pa_sys->verify_padata == 0)
+        goto next;
+
+    state->pa_found++;
+    state->pa_sys->verify_padata(state->context, state->client,
+                                 state->req_pkt, state->request,
+                                 state->enc_tkt_reply, *state->padata,
+                                 get_entry_data, state->pa_sys->moddata,
+                                 finish_verify_padata, state);
+    return;
+
+next:
+    next_padata(state);
+}
+
+/*
+ * This routine is called to verify the preauthentication information
+ * for a V5 request.
+ *
+ * Returns 0 if the pre-authentication is valid, non-zero to indicate
+ * an error code of some sort.
+ */
+
+void
+check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
+              krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
+              void **padata_context, krb5_data *e_data,
+              kdc_preauth_respond_fn respond, void *arg)
+{
+    struct padata_state *state;
+
+    if (request->padata == 0) {
+        (*respond)(arg, 0);
+        return;
+    }
+
+    if (make_padata_context(context, padata_context) != 0) {
+        (*respond)(arg, KRB5KRB_ERR_GENERIC);
+        return;
+    }
+
+    state = malloc(sizeof(*state));
+    if (!state) {
+        (*respond)(arg, ENOMEM);
         return;
     }
+    memset(state, 0, sizeof(*state));
+    state->respond = respond;
+    state->arg = arg;
+    state->context = context;
+    state->client = client;
+    state->req_pkt = req_pkt;
+    state->request = request;
+    state->enc_tkt_reply = enc_tkt_reply;
+    state->padata_context = padata_context;
+    state->e_data = e_data;
+    state->realm = kdc_active_realm;
+
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, "checking padata");
+#endif
+
+    next_padata(state);
 }
 
 /*
@@ -1259,15 +1343,14 @@ get_enc_ts(krb5_context context, krb5_kdc_req *request,
 }
 
 
-static krb5_error_code
+static void
 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,
                      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)
+                     krb5_kdcpreauth_verify_respond_fn respond,
+                     void *arg)
 {
     krb5_pa_enc_ts *            pa_enc = 0;
     krb5_error_code             retval;
@@ -1347,7 +1430,7 @@ cleanup:
     if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0)
         retval = decrypt_err;
 
-    return retval;
+    (*respond)(arg, retval, NULL, NULL, NULL);
 }
 
 static krb5_error_code
index 02446ad3be6be47ca1d9038c00d69ba02d2d81db..24b6675078981ea41bd20aa03dd0bdf09216d007 100644 (file)
@@ -53,14 +53,14 @@ kdc_include_padata(krb5_context context, krb5_kdc_req *request,
     return 0;
 }
 
-static krb5_error_code
+static void
 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,
                    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_kdcpreauth_verify_respond_fn respond,
+                   void *arg)
 {
     krb5_error_code retval = 0;
     krb5_timestamp now;
@@ -72,6 +72,7 @@ kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
     krb5_data *client_data = NULL;
     krb5_keyblock *challenge_key = NULL;
     krb5_keyblock *kdc_challenge_key;
+    krb5_kdcpreauth_modreq modreq = NULL;
     int i = 0;
 
     plain.data = NULL;
@@ -141,7 +142,7 @@ kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
             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;
+                modreq = (krb5_kdcpreauth_modreq)kdc_challenge_key;
         } else { /*skew*/
             retval = KRB5KRB_AP_ERR_SKEW;
         }
@@ -159,7 +160,8 @@ kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
         krb5_free_enc_data(context, enc);
     if (ts)
         krb5_free_pa_enc_ts(context, ts);
-    return retval;
+
+    (*respond)(arg, retval, modreq, NULL, NULL);
 }
 
 static krb5_error_code
index e79b84a12ac2e59e9febf8a65c73597cb1f09bab..06ba14d5a96e5a6e60f801dafa48b82f17d0624d 100644 (file)
@@ -329,7 +329,7 @@ server_get_edata(krb5_context kcontext,
 }
 
 /* Verify a request from a client. */
-static krb5_error_code
+static void
 server_verify(krb5_context kcontext,
               struct _krb5_db_entry_new *client,
               krb5_data *req_pkt,
@@ -338,9 +338,8 @@ server_verify(krb5_context kcontext,
               krb5_pa_data *data,
               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)
+              krb5_kdcpreauth_verify_respond_fn respond,
+              void *arg)
 {
     krb5_int32 cksumtype;
     krb5_checksum checksum;
@@ -365,7 +364,8 @@ server_verify(krb5_context kcontext,
     /* Verify the preauth data.  Start with the checksum type. */
     if (data->length < 4) {
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
     }
     memcpy(&cksumtype, data->contents, 4);
     memset(&checksum, 0, sizeof(checksum));
@@ -379,14 +379,16 @@ server_verify(krb5_context kcontext,
                 "Is it supported?\n", checksum.checksum_type);
 #endif
         stats->failures++;
-        return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+        (*respond)(arg, KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, NULL);
+        return;
     }
     if (data->length - 4 != length) {
 #ifdef DEBUG
         fprintf(stderr, "Checksum size doesn't match client packet size.\n");
 #endif
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
     }
     checksum.length = length;
 
@@ -398,7 +400,8 @@ server_verify(krb5_context kcontext,
         fprintf(stderr, "Error retrieving client keys.\n");
 #endif
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
     }
 
     /* Find the key which would have been used to generate the checksum. */
@@ -429,7 +432,8 @@ server_verify(krb5_context kcontext,
             krb5_free_keyblock_contents(kcontext, &keys[i]);
         krb5_free_data(kcontext, key_data);
         stats->failures++;
-        return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+        (*respond)(arg, KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, NULL);
+        return;
     }
 
     /* Save a copy of the key. */
@@ -438,7 +442,8 @@ server_verify(krb5_context kcontext,
             krb5_free_keyblock_contents(kcontext, &keys[i]);
         krb5_free_data(kcontext, key_data);
         stats->failures++;
-        return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+        (*respond)(arg, KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, NULL);
+        return;
     }
     for (i = 0; keys[i].enctype != 0; i++)
         krb5_free_keyblock_contents(kcontext, &keys[i]);
@@ -454,7 +459,8 @@ server_verify(krb5_context kcontext,
                                  &req_body) != 0) {
         krb5_free_keyblock(kcontext, key);
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
     }
 
 #ifdef DEBUG
@@ -488,14 +494,15 @@ server_verify(krb5_context kcontext,
             test_edata->data = malloc(20);
             if (test_edata->data == NULL) {
                 free(test_edata);
+                test_edata = NULL;
             } else {
                 test_edata->length = 20;
                 memset(test_edata->data, 'F', 20); /* fill it with junk */
-                *e_data = test_edata;
             }
         }
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, test_edata, NULL);
+        return;
     }
 
     /*
@@ -527,13 +534,15 @@ server_verify(krb5_context kcontext,
         my_authz_data[0] = malloc(sizeof(krb5_authdata));
         if (my_authz_data[0] == NULL) {
             free(my_authz_data);
-            return ENOMEM;
+            (*respond)(arg, ENOMEM, NULL, NULL, NULL);
+            return;
         }
         my_authz_data[0]->contents = malloc(AD_ALLOC_SIZE);
         if (my_authz_data[0]->contents == NULL) {
             free(my_authz_data[0]);
             free(my_authz_data);
-            return ENOMEM;
+            (*respond)(arg, ENOMEM, NULL, NULL, NULL);
+            return;
         }
         memset(my_authz_data[0]->contents, '\0', AD_ALLOC_SIZE);
         my_authz_data[0]->magic = KV5M_AUTHDATA;
@@ -543,7 +552,6 @@ server_verify(krb5_context kcontext,
         snprintf(my_authz_data[0]->contents + sizeof(ad_header),
                  AD_ALLOC_SIZE - sizeof(ad_header),
                  "cksum authorization data: %d bytes worth!\n", AD_ALLOC_SIZE);
-        *authz_data = my_authz_data;
 #ifdef DEBUG
         fprintf(stderr, "Returning %d bytes of authorization data\n",
                 AD_ALLOC_SIZE);
@@ -556,10 +564,10 @@ server_verify(krb5_context kcontext,
         test_edata->data = malloc(20);
         if (test_edata->data == NULL) {
             free(test_edata);
+            test_edata = NULL;
         } else {
             test_edata->length = 20;
             memset(test_edata->data, 'S', 20); /* fill it with junk */
-            *e_data = test_edata;
         }
     }
 
@@ -573,12 +581,12 @@ server_verify(krb5_context kcontext,
                 svr_req_ctx);
 #endif
     }
-    *modreq_out = (krb5_kdcpreauth_modreq)svr_req_ctx;
 
     /* Note that preauthentication succeeded. */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
     stats->successes++;
-    return 0;
+    (*respond)(arg, 0, (krb5_kdcpreauth_modreq)svr_req_ctx, test_edata,
+               my_authz_data);
 }
 
 /* Create the response for a client. */
index c76359e7b64d4adcd713b89a27591b4866213ab9..1967ea65c89fb905437d38a25f3e722a704c33f5 100644 (file)
@@ -287,7 +287,7 @@ out:
     return retval;
 }
 
-static krb5_error_code
+static void
 pkinit_server_verify_padata(krb5_context context,
                             struct _krb5_db_entry_new * client,
                             krb5_data *req_pkt,
@@ -296,9 +296,8 @@ pkinit_server_verify_padata(krb5_context context,
                             krb5_pa_data * data,
                             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)
+                            krb5_kdcpreauth_verify_respond_fn respond,
+                            void *arg)
 {
     krb5_error_code retval = 0;
     krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
@@ -315,10 +314,14 @@ pkinit_server_verify_padata(krb5_context context,
     krb5_data k5data;
     int is_signed = 1;
     krb5_keyblock *armor_key;
+    krb5_data *e_data = NULL;
+    krb5_kdcpreauth_modreq modreq = NULL;
 
     pkiDebug("pkinit_verify_padata: entered!\n");
-    if (data == NULL || data->length <= 0 || data->contents == NULL)
-        return 0;
+    if (data == NULL || data->length <= 0 || data->contents == NULL) {
+        (*respond)(arg, 0, NULL, NULL, NULL);
+        return;
+    }
 
     /* Remove (along with armor_key) when FAST PKINIT is settled. */
     retval = fast_kdc_get_armor_key(context, server_get_entry_data, request,
@@ -326,15 +329,20 @@ pkinit_server_verify_padata(krb5_context context,
     if (retval == 0 && armor_key != NULL) {
         /* Don't allow PKINIT if the client used FAST. */
         krb5_free_keyblock(context, armor_key);
-        return EINVAL;
+        (*respond)(arg, EINVAL, NULL, NULL, NULL);
+        return;
     }
 
-    if (moddata == NULL || e_data == NULL)
-        return EINVAL;
+    if (moddata == NULL) {
+        (*respond)(arg, EINVAL, NULL, NULL, NULL);
+        return;
+    }
 
     plgctx = pkinit_find_realm_context(context, moddata, request->server);
-    if (plgctx == NULL)
-        return 0;
+    if (plgctx == NULL) {
+        (*respond)(arg, 0, NULL, NULL, NULL);
+        return;
+    }
 
 #ifdef DEBUG_ASN1
     print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
@@ -548,26 +556,16 @@ pkinit_server_verify_padata(krb5_context context,
         break;
     }
 
-    /*
-     * This code used to generate ad-initial-verified-cas authorization data.
-     * However that has been removed until the ad-kdc-issued discussion can
-     * happen in the working group.  Dec 2009
-     */
-    /* return authorization data to be included in the ticket */
-    switch ((int)data->pa_type) {
-    default:
-        *authz_data = NULL;
-    }
     /* remember to set the PREAUTH flag in the reply */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
-    *modreq_out = (krb5_kdcpreauth_modreq)reqctx;
+    modreq = (krb5_kdcpreauth_modreq)reqctx;
     reqctx = NULL;
 
 cleanup:
     if (retval && data->pa_type == KRB5_PADATA_PK_AS_REQ) {
         pkiDebug("pkinit_verify_padata failed: creating e-data\n");
         if (pkinit_create_edata(context, plgctx->cryptoctx, reqctx->cryptoctx,
-                                plgctx->idctx, plgctx->opts, retval, e_data))
+                                plgctx->idctx, plgctx->opts, retval, &e_data))
             pkiDebug("pkinit_create_edata failed\n");
     }
 
@@ -593,7 +591,7 @@ cleanup:
     if (auth_pack9 != NULL)
         free_krb5_auth_pack_draft9(context, &auth_pack9);
 
-    return retval;
+    (*respond)(arg, retval, modreq, e_data, NULL);
 }
 static krb5_error_code
 return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
index 0c420d22638d9863e34f636b2824339cd87201d8..700cd59f9cc1d21dfe5038eaf29f6fdf723ab4a3 100644 (file)
@@ -202,18 +202,18 @@ cleanup:
     return retval;
 }
 
-static krb5_error_code
+static void
 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,
                    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_kdcpreauth_verify_respond_fn respond,
+                   void *arg)
 {
     krb5_error_code retval, saved_retval = 0;
     krb5_sam_response_2 *sr2 = NULL;
-    krb5_data scratch, *scratch2;
+    krb5_data scratch, *scratch2, *e_data = NULL;
     char *client_name = NULL;
     krb5_sam_challenge_2 *out_sc2 = NULL;
 
@@ -276,7 +276,7 @@ cleanup:
             goto encode_error;
         pa_out.contents = (krb5_octet *) scratch2->data;
         pa_out.length = scratch2->length;
-        retval = encode_krb5_padata_sequence(pa_array, e_data);
+        retval = encode_krb5_padata_sequence(pa_array, &e_data);
         krb5_free_data(context, scratch2);
     }
 encode_error:
@@ -284,7 +284,8 @@ encode_error:
     free(client_name);
     if (retval == 0)
         retval = saved_retval;
-    return retval;
+
+    (*respond)(arg, retval, NULL, NULL, NULL);
 }
 
 
index 866286c1bc2b8ca0fd74c48b50dd064ecc03af11..3c10e14162eea8a5f51cd17e6ff0ab39e4ac443d 100644 (file)
@@ -259,7 +259,7 @@ server_get_edata(krb5_context kcontext,
 }
 
 /* Verify a request from a client. */
-static krb5_error_code
+static void
 server_verify(krb5_context kcontext,
               struct _krb5_db_entry_new *client,
               krb5_data *req_pkt,
@@ -268,30 +268,34 @@ server_verify(krb5_context kcontext,
               krb5_pa_data *data,
               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)
+              krb5_kdcpreauth_verify_respond_fn respond,
+              void *arg)
 {
     krb5_int32 nnonce;
     krb5_data *test_edata;
     krb5_authdata **my_authz_data;
+    krb5_kdcpreauth_modreq modreq;
 
 #ifdef DEBUG
     fprintf(stderr, "wpse: server_verify()!\n");
 #endif
     /* Verify the preauth data. */
-    if (data->length != 4)
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+    if (data->length != 4) {
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
+    }
     memcpy(&nnonce, data->contents, 4);
     nnonce = ntohl(nnonce);
-    if (memcmp(&nnonce, &request->nonce, 4) != 0)
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+    if (memcmp(&nnonce, &request->nonce, 4) != 0) {
+        (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
+        return;
+    }
     /* Note that preauthentication succeeded. */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
     enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
     /* Allocate a context. Useful for verifying that we do in fact do
      * per-request cleanup. */
-    *modreq_out = malloc(4);
+    modreq = malloc(4);
 
     /*
      * Return some junk authorization data just to exercise the
@@ -322,13 +326,15 @@ server_verify(krb5_context kcontext,
         my_authz_data[0] = malloc(sizeof(krb5_authdata));
         if (my_authz_data[0] == NULL) {
             free(my_authz_data);
-            return ENOMEM;
+            (*respond)(arg, ENOMEM, modreq, NULL, NULL);
+            return;
         }
         my_authz_data[0]->contents = malloc(AD_ALLOC_SIZE);
         if (my_authz_data[0]->contents == NULL) {
             free(my_authz_data[0]);
             free(my_authz_data);
-            return ENOMEM;
+            (*respond)(arg, ENOMEM, modreq, NULL, NULL);
+            return;
         }
         memset(my_authz_data[0]->contents, '\0', AD_ALLOC_SIZE);
         my_authz_data[0]->magic = KV5M_AUTHDATA;
@@ -338,7 +344,6 @@ server_verify(krb5_context kcontext,
         snprintf(my_authz_data[0]->contents + sizeof(ad_header),
                  AD_ALLOC_SIZE - sizeof(ad_header),
                  "wpse authorization data: %d bytes worth!\n", AD_ALLOC_SIZE);
-        *authz_data = my_authz_data;
 #ifdef DEBUG
         fprintf(stderr, "Returning %d bytes of authorization data\n",
                 AD_ALLOC_SIZE);
@@ -351,13 +356,14 @@ server_verify(krb5_context kcontext,
         test_edata->data = malloc(20);
         if (test_edata->data == NULL) {
             free(test_edata);
+            test_edata = NULL;
         } else {
             test_edata->length = 20;
             memset(test_edata->data, '#', 20); /* fill it with junk */
-            *e_data = test_edata;
         }
     }
-    return 0;
+
+    (*respond)(arg, 0, modreq, test_edata, my_authz_data);
 }
 
 /* Create the response for a client. */