[17161] in Kerberos_V5_Development

home help back first fref pref prev next nref lref last post

[PATCH] Plugin Interface Change

daemon@ATHENA.MIT.EDU (Nathaniel McCallum)
Wed Sep 14 10:31:00 2011

From: Nathaniel McCallum <npmccallum@redhat.com>
To: krbdev@mit.edu
Date: Tue, 13 Sep 2011 19:46:26 -0400
Content-Type: multipart/mixed; boundary="=-np5m4SEPiPtrzkJUNpDq"
Message-ID: <1315957588.28552.0.camel@localhost>
Mime-Version: 1.0
Errors-To: krbdev-bounces@mit.edu


--=-np5m4SEPiPtrzkJUNpDq
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

The following attached patches make it possible for preauth plugins to
perform verification asynchronously by inserting events into the main
loop which will call the responder upon completion. Every patch passed
make check before the rebase to trunk, but as I am still not able to get
trunk to build I have not tested against the most recent week or so in
trunk. As the rebase is clean, I am assuming that everything works (I
want to get the patches out for review ASAP).

The patches are also available via
https://github.com/npmccallum/krb5-anonsvn/tree/verto if you prefer that
route.

Nathaniel

--=-np5m4SEPiPtrzkJUNpDq
Content-Disposition: attachment;
	filename="0001-make-dispatch-respond-via-a-callback.patch"
Content-Type: text/x-patch;
	name="0001-make-dispatch-respond-via-a-callback.patch"; 
	charset="UTF-8"
Content-Transfer-Encoding: 7bit

>From 7c8c1f2733bd2ddccc703f5a8def00d3b8f63c9c Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccallum@redhat.com>
Date: Tue, 13 Sep 2011 17:58:29 -0400
Subject: [PATCH 1/4] make dispatch() respond via a callback

---
 src/include/net-server.h      |   16 ++-
 src/kadmin/server/schpw.c     |   15 +-
 src/kdc/dispatch.c            |   29 ++--
 src/kdc/kdc_util.h            |    5 +-
 src/lib/apputils/net-server.c |  323 ++++++++++++++++++++++++-----------------
 5 files changed, 224 insertions(+), 164 deletions(-)

diff --git a/src/include/net-server.h b/src/include/net-server.h
index b8414a1..6bfcfb3 100644
--- a/src/include/net-server.h
+++ b/src/include/net-server.h
@@ -62,12 +62,16 @@ void loop_free(verto_ctx *ctx);
  * to send back when the incoming message is bigger than
  * the main loop can accept.
  */
-krb5_error_code dispatch (void *handle,
-                          struct sockaddr *local_addr,
-                          const krb5_fulladdr *remote_addr,
-                          krb5_data *request,
-                          krb5_data **response,
-                          int is_tcp);
+typedef void (*krb5_responder)(krb5_error_code ec,
+                               krb5_data *response,
+                               void *misc);
+void dispatch (void *handle,
+               struct sockaddr *local_addr,
+               const krb5_fulladdr *remote_addr,
+               krb5_data *request,
+               krb5_responder respond,
+               void *misc,
+               int is_tcp);
 krb5_error_code make_toolong_error (void *handle, krb5_data **);
 
 /*
diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c
index 4f7f110..9a667e5 100644
--- a/src/kadmin/server/schpw.c
+++ b/src/kadmin/server/schpw.c
@@ -454,10 +454,10 @@ bailout:
 }
 
 /* Dispatch routine for set/change password */
-krb5_error_code
+void
 dispatch(void *handle,
          struct sockaddr *local_saddr, const krb5_fulladdr *remote_faddr,
-         krb5_data *request, krb5_data **response_out, int is_tcp)
+         krb5_data *request, krb5_responder respond, void *misc, int is_tcp)
 {
     krb5_error_code ret;
     krb5_keytab kt = NULL;
@@ -466,8 +466,6 @@ dispatch(void *handle,
     krb5_address **local_kaddrs = NULL, local_kaddr_buf;
     krb5_data *response = NULL;
 
-    *response_out = NULL;
-
     if (local_saddr == NULL) {
         ret = krb5_os_localaddr(server_handle->context, &local_kaddrs);
         if (ret != 0)
@@ -502,12 +500,13 @@ dispatch(void *handle,
     if (ret)
         goto cleanup;
 
-    *response_out = response;
-    response = NULL;
+    goto out;
 
 cleanup:
-    krb5_free_addresses(server_handle->context, local_kaddrs);
     krb5_free_data(server_handle->context, response);
+
+out:
+    krb5_free_addresses(server_handle->context, local_kaddrs);
     krb5_kt_close(server_handle->context, kt);
-    return ret;
+    (*respond)(ret, ret == 0 ? response : NULL, misc);
 }
diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c
index 5c21930..af76e94 100644
--- a/src/kdc/dispatch.c
+++ b/src/kdc/dispatch.c
@@ -36,25 +36,25 @@ static krb5_int32 last_usec = 0, last_os_random = 0;
 
 static krb5_error_code make_too_big_error (krb5_data **out);
 
-krb5_error_code
+void
 dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
-         krb5_data *pkt, krb5_data **response, int is_tcp)
+         krb5_data *pkt, krb5_responder respond, void *misc, int is_tcp)
 {
-
     krb5_error_code retval;
     krb5_kdc_req *as_req;
     krb5_int32 now, now_usec;
+    krb5_data *response;
 
     /* decode incoming packet, and dispatch */
 
 #ifndef NOCACHE
     /* try the replay lookaside buffer */
-    if (kdc_check_lookaside(pkt, response)) {
+    if (kdc_check_lookaside(pkt, &response)) {
         /* a hit! */
         const char *name = 0;
         char buf[46];
 
-        if (is_tcp == 0 && (*response)->length > max_dgram_reply_size)
+        if (is_tcp == 0 && response->length > max_dgram_reply_size)
             goto too_big_for_udp;
 
         name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
@@ -64,7 +64,8 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
         krb5_klog_syslog(LOG_INFO,
                          "DISPATCH: repeated (retransmitted?) request from %s, resending previous response",
                          name);
-        return 0;
+        (*respond)(0, response, misc);
+        return;
     }
 #endif
     retval = krb5_crypto_us_timeofday(&now, &now_usec);
@@ -89,7 +90,7 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
     /* try TGS_REQ first; they are more common! */
 
     if (krb5_is_tgs_req(pkt)) {
-        retval = process_tgs_req(pkt, from, response);
+        retval = process_tgs_req(pkt, from, &response);
     } else if (krb5_is_as_req(pkt)) {
         if (!(retval = decode_krb5_as_req(pkt, &as_req))) {
             /*
@@ -98,7 +99,7 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
              * process_as_req frees the request if it is called
              */
             if (!(retval = setup_server_realm(as_req->server))) {
-                retval = process_as_req(as_req, pkt, from, response);
+                retval = process_as_req(as_req, pkt, from, &response);
             }
             else            krb5_free_kdc_req(kdc_context, as_req);
         }
@@ -108,14 +109,14 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
 #ifndef NOCACHE
     /* put the response into the lookaside buffer */
     if (!retval)
-        kdc_insert_lookaside(pkt, *response);
+        kdc_insert_lookaside(pkt, response);
 #endif
 
-    if (is_tcp == 0 && *response != NULL &&
-        (*response)->length > max_dgram_reply_size) {
+    if (is_tcp == 0 && response != NULL &&
+        response->length > max_dgram_reply_size) {
     too_big_for_udp:
-        krb5_free_data(kdc_context, *response);
-        retval = make_too_big_error(response);
+        krb5_free_data(kdc_context, response);
+        retval = make_too_big_error(&response);
         if (retval) {
             krb5_klog_syslog(LOG_ERR,
                              "error constructing KRB_ERR_RESPONSE_TOO_BIG error: %s",
@@ -123,7 +124,7 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
         }
     }
 
-    return retval;
+    (*respond)(retval, retval == 0 ? response : NULL, misc);
 }
 
 static krb5_error_code
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index e2790e2..36093ad 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -129,12 +129,13 @@ process_tgs_req (krb5_data *,
                  const krb5_fulladdr *,
                  krb5_data ** );
 /* dispatch.c */
-krb5_error_code
+void
 dispatch (void *,
           struct sockaddr *,
           const krb5_fulladdr *,
           krb5_data *,
-          krb5_data **,
+          krb5_responder,
+          void *,
           int);
 
 krb5_error_code
diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c
index fc6d6e7..68d13d7 100644
--- a/src/lib/apputils/net-server.c
+++ b/src/lib/apputils/net-server.c
@@ -515,32 +515,6 @@ make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback,
 }
 
 static verto_ev *
-convert_event(verto_ctx *ctx, verto_ev *ev, verto_ev_flag flags,
-              verto_callback callback)
-{
-    struct connection *conn;
-    verto_ev *newev;
-    int sock;
-
-    conn = verto_get_private(ev);
-    sock = verto_get_fd(ev);
-    if (sock < 0)
-        return NULL;
-
-    newev = make_event(ctx, flags, callback, sock, conn, 1);
-
-    /* Delete the read event without closing the socket
-     * or freeing the connection struct. */
-    if (newev) {
-        verto_set_private(ev, NULL, NULL); /* Reset the destructor. */
-        remove_event_from_set(ev); /* Remove it from the set. */
-        verto_del(ev);
-    }
-
-    return newev;
-}
-
-static verto_ev *
 add_fd(struct socksetup *data, int sock, enum conn_type conntype,
        verto_ev_flag flags, verto_callback callback, int addevent)
 {
@@ -1544,34 +1518,97 @@ send_to_from(int s, void *buf, size_t len, int flags,
 #endif
 }
 
-static void
-process_packet(verto_ctx *ctx, verto_ev *ev)
-{
-    int cc;
-    socklen_t saddr_len, daddr_len;
+struct udp_dispatch_misc {
+    void *handle;
+    const char *prog;
+    int port_fd;
+    krb5_address addr;
     krb5_fulladdr faddr;
-    krb5_error_code retval;
+    socklen_t saddr_len, daddr_len;
     struct sockaddr_storage saddr, daddr;
-    krb5_address addr;
+    union aux_addressing_info auxaddr;
     krb5_data request;
-    krb5_data *response;
     char pktbuf[MAX_DGRAM_SIZE];
-    int port_fd;
-    union aux_addressing_info auxaddr;
+};
+
+static void
+process_packet_response(krb5_error_code ec, krb5_data *response, void *data)
+{
+    struct udp_dispatch_misc *misc = (struct udp_dispatch_misc*) data;
+    int cc;
+
+    if (ec)
+        com_err(misc->prog ? misc->prog : NULL, ec, _("while dispatching (udp)"));
+    if (ec || response == NULL || misc == NULL)
+        goto out;
+
+    cc = send_to_from(misc->port_fd, response->data,
+                      (socklen_t) response->length, 0,
+                      (struct sockaddr *)&misc->saddr, misc->saddr_len,
+                      (struct sockaddr *)&misc->daddr, misc->daddr_len,
+                      &misc->auxaddr);
+    if (cc == -1) {
+        /* Note that the local address (daddr*) has no port number
+         * info associated with it. */
+        char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
+        char daddrbuf[NI_MAXHOST];
+        int e = errno;
+
+        if (getnameinfo((struct sockaddr *)&misc->daddr, misc->daddr_len,
+                        daddrbuf, sizeof(daddrbuf), 0, 0,
+                        NI_NUMERICHOST) != 0) {
+            strlcpy(daddrbuf, "?", sizeof(daddrbuf));
+        }
+
+        if (getnameinfo((struct sockaddr *)&misc->saddr, misc->saddr_len,
+                        saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf),
+                        NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+            strlcpy(saddrbuf, "?", sizeof(saddrbuf));
+            strlcpy(sportbuf, "?", sizeof(sportbuf));
+        }
+
+        com_err(misc->prog, e, _("while sending reply to %s/%s from %s"),
+                saddrbuf, sportbuf, daddrbuf);
+        goto out;
+    }
+    if ((size_t)cc != response->length) {
+        com_err(misc->prog, 0, _("short reply write %d vs %d\n"),
+                response->length, cc);
+    }
+
+out:
+    krb5_free_data(get_context(misc->handle), response);
+    free(misc);
+    return;
+}
+
+static void
+process_packet(verto_ctx *ctx, verto_ev *ev)
+{
+    int cc;
     struct connection *conn;
+    struct udp_dispatch_misc *misc;
 
-    port_fd = verto_get_fd(ev);
     conn = verto_get_private(ev);
-    assert(port_fd >= 0);
-
-    response = NULL;
-    saddr_len = sizeof(saddr);
-    daddr_len = sizeof(daddr);
-    memset(&auxaddr, 0, sizeof(auxaddr));
-    cc = recv_from_to(port_fd, pktbuf, sizeof(pktbuf), 0,
-                      (struct sockaddr *)&saddr, &saddr_len,
-                      (struct sockaddr *)&daddr, &daddr_len,
-                      &auxaddr);
+
+    misc = malloc(sizeof(*misc));
+    if (!misc) {
+            com_err(conn->prog, ENOMEM, _("while dispatching (udp)"));
+            return;
+    }
+
+    misc->handle = conn->handle;
+    misc->prog = conn->prog;
+    misc->port_fd = verto_get_fd(ev);
+    assert(misc->port_fd >= 0);
+
+    misc->saddr_len = sizeof(misc->saddr);
+    misc->daddr_len = sizeof(misc->daddr);
+    memset(&misc->auxaddr, 0, sizeof(misc->auxaddr));
+    cc = recv_from_to(misc->port_fd, misc->pktbuf, sizeof(misc->pktbuf), 0,
+                      (struct sockaddr *)&misc->saddr, &misc->saddr_len,
+                      (struct sockaddr *)&misc->daddr, &misc->daddr_len,
+                      &misc->auxaddr);
     if (cc == -1) {
         if (errno != EINTR && errno != EAGAIN
             /*
@@ -1582,77 +1619,46 @@ process_packet(verto_ctx *ctx, verto_ev *ev)
             && errno != ECONNREFUSED
         )
             com_err(conn->prog, errno, _("while receiving from network"));
-        return;
+        goto error;
     }
     if (!cc)
-        return;         /* zero-length packet? */
+        goto error; /* zero-length packet? */
 
 #if 0
-    if (daddr_len > 0) {
+    if (misc->daddr_len > 0) {
         char addrbuf[100];
-        if (getnameinfo(ss2sa(&daddr), daddr_len, addrbuf, sizeof(addrbuf),
+        if (getnameinfo(ss2sa(&misc->daddr), misc->daddr_len,
+                        addrbuf, sizeof(addrbuf),
                         0, 0, NI_NUMERICHOST))
             strlcpy(addrbuf, "?", sizeof(addrbuf));
         com_err(conn->prog, 0, _("pktinfo says local addr is %s"), addrbuf);
     }
 #endif
 
-    if (daddr_len == 0 && conn->type == CONN_UDP) {
+    if (misc->daddr_len == 0 && conn->type == CONN_UDP) {
         /*
          * If the PKTINFO option isn't set, this socket should be bound to a
          * specific local address.  This info probably should've been saved in
          * our socket data structure at setup time.
          */
-        daddr_len = sizeof(daddr);
-        if (getsockname(port_fd, (struct sockaddr *)&daddr, &daddr_len) != 0)
-            daddr_len = 0;
+            misc->daddr_len = sizeof(misc->daddr);
+        if (getsockname(misc->port_fd, (struct sockaddr *)&misc->daddr,
+                        &misc->daddr_len) != 0)
+            misc->daddr_len = 0;
         /* On failure, keep going anyways. */
     }
 
-    request.length = cc;
-    request.data = pktbuf;
-    faddr.address = &addr;
-    init_addr(&faddr, ss2sa(&saddr));
+    misc->request.length = cc;
+    misc->request.data = misc->pktbuf;
+    misc->faddr.address = &misc->addr;
+    init_addr(&misc->faddr, ss2sa(&misc->saddr));
     /* This address is in net order. */
-    retval = dispatch(conn->handle, ss2sa(&daddr),
-                      &faddr, &request, &response, 0);
-    if (retval) {
-        com_err(conn->prog, retval, _("while dispatching (udp)"));
-        return;
-    }
-    if (response == NULL)
-        return;
-    cc = send_to_from(port_fd, response->data, (socklen_t) response->length, 0,
-                      (struct sockaddr *)&saddr, saddr_len,
-                      (struct sockaddr *)&daddr, daddr_len,
-                      &auxaddr);
-    if (cc == -1) {
-        /* Note that the local address (daddr*) has no port number
-         * info associated with it. */
-        char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
-        char daddrbuf[NI_MAXHOST];
-        int e = errno;
-        krb5_free_data(get_context(conn->handle), response);
-        if (getnameinfo((struct sockaddr *)&daddr, daddr_len,
-                        daddrbuf, sizeof(daddrbuf), 0, 0,
-                        NI_NUMERICHOST) != 0) {
-            strlcpy(daddrbuf, "?", sizeof(daddrbuf));
-        }
-        if (getnameinfo((struct sockaddr *)&saddr, saddr_len,
-                        saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf),
-                        NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-            strlcpy(saddrbuf, "?", sizeof(saddrbuf));
-            strlcpy(sportbuf, "?", sizeof(sportbuf));
-        }
-        com_err(conn->prog, e, _("while sending reply to %s/%s from %s"),
-                saddrbuf, sportbuf, daddrbuf);
-        return;
-    }
-    if ((size_t)cc != response->length) {
-        com_err(conn->prog, 0, _("short reply write %d vs %d\n"),
-                response->length, cc);
-    }
-    krb5_free_data(get_context(conn->handle), response);
+    dispatch(misc->handle, ss2sa(&misc->daddr), &misc->faddr,
+             &misc->request, process_packet_response, misc, 0);
+    return;
+
+error:
+    free(misc);
     return;
 }
 
@@ -1776,16 +1782,76 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
     SG_SET(&newconn->u.tcp.sgbuf[1], 0, 0);
 }
 
+struct tcp_dispatch_misc {
+    struct sockaddr_storage local_saddr;
+    struct connection *conn;
+    krb5_data request;
+    verto_ctx *ctx;
+    int sock;
+};
+
+static void
+process_tcp_response(krb5_error_code ec, krb5_data *response, void *data)
+{
+    struct tcp_dispatch_misc *misc = (struct tcp_dispatch_misc*) data;
+    verto_ev *ev;
+
+    assert(misc);
+    misc->conn->u.tcp.response = response;
+
+    if (ec)
+        com_err(misc->conn->prog, ec, _("while dispatching (tcp)"));
+    if (ec || !response)
+        goto kill_tcp_connection;
+
+    /* Queue outgoing response. */
+    store_32_be(response->length, misc->conn->u.tcp.lenbuf);
+    SG_SET(&misc->conn->u.tcp.sgbuf[1], response->data, response->length);
+    misc->conn->u.tcp.sgp = misc->conn->u.tcp.sgbuf;
+    misc->conn->u.tcp.sgnum = 2;
+
+    ev = make_event(misc->ctx, VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
+                    process_tcp_connection_write, misc->sock, misc->conn, 1);
+    if (ev)
+        goto out;
+
+kill_tcp_connection:
+    tcp_or_rpc_data_counter--;
+    free_connection(misc->conn);
+    close(misc->sock);
+
+out:
+    free(misc);
+}
+
+static struct tcp_dispatch_misc *
+make_tcp_misc(verto_ctx *ctx, verto_ev *ev)
+{
+    struct tcp_dispatch_misc *misc;
+
+    misc = malloc(sizeof(*misc));
+    if (!misc) {
+        krb5_klog_syslog(LOG_ERR, _("error allocating tcp dispatch private!"));
+        return NULL;
+    }
+    misc->conn = verto_get_private(ev);
+    misc->sock = verto_get_fd(ev);
+    misc->ctx = ctx;
+    verto_set_private(ev, NULL, NULL); /* Don't close the fd or free conn! */
+    remove_event_from_set(ev); /* Remove it from the set. */
+    verto_del(ev);
+    return misc;
+}
+
 static void
 process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
 {
-    struct connection *conn;
+    struct tcp_dispatch_misc *misc = NULL;
+    struct connection *conn = NULL;
     ssize_t nread;
     size_t len;
-    int sock;
 
     conn = verto_get_private(ev);
-    sock = verto_get_fd(ev);
 
     /*
      * Read message length and data into one big buffer, already allocated
@@ -1794,10 +1860,12 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
      * incomplete message.
      */
     if (conn->u.tcp.offset < 4) {
+        krb5_data *response = NULL;
+
         /* msglen has not been computed.  XXX Doing at least two reads
          * here, letting the kernel worry about buffering. */
         len = 4 - conn->u.tcp.offset;
-        nread = SOCKET_READ(sock,
+        nread = SOCKET_READ(verto_get_fd(ev),
                             conn->u.tcp.buffer + conn->u.tcp.offset, len);
         if (nread < 0) /* error */
             goto kill_tcp_connection;
@@ -1815,27 +1883,27 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
                                  (unsigned long) conn->u.tcp.msglen,
                                  (unsigned long) conn->u.tcp.bufsiz - 4);
                 /* XXX Should return an error.  */
-                err = make_toolong_error (conn->handle,
-                                          &conn->u.tcp.response);
+                err = make_toolong_error (conn->handle, &response);
                 if (err) {
                     krb5_klog_syslog(LOG_ERR, _("error constructing "
                                      "KRB_ERR_FIELD_TOOLONG error! %s"),
                                      error_message(err));
                     goto kill_tcp_connection;
                 }
-                goto have_response;
+
+                misc = make_tcp_misc(ctx, ev);
+                if (!misc)
+                    goto kill_tcp_connection;
+                process_tcp_response(0, response, misc);
             }
         }
     } else {
         /* msglen known. */
-        krb5_data request;
-        krb5_error_code err;
-        struct sockaddr_storage local_saddr;
-        socklen_t local_saddrlen = sizeof(local_saddr);
+        socklen_t local_saddrlen = sizeof(struct sockaddr_storage);
         struct sockaddr *local_saddrp = NULL;
 
         len = conn->u.tcp.msglen - (conn->u.tcp.offset - 4);
-        nread = SOCKET_READ(sock,
+        nread = SOCKET_READ(verto_get_fd(ev),
                             conn->u.tcp.buffer + conn->u.tcp.offset, len);
         if (nread < 0) /* error */
             goto kill_tcp_connection;
@@ -1844,34 +1912,21 @@ process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
         conn->u.tcp.offset += nread;
         if (conn->u.tcp.offset < conn->u.tcp.msglen + 4)
             return;
+
         /* Have a complete message, and exactly one message. */
-        request.length = conn->u.tcp.msglen;
-        request.data = conn->u.tcp.buffer + 4;
+        misc = make_tcp_misc(ctx, ev);
+        if (!misc)
+            goto kill_tcp_connection;
+
+        misc->request.length = conn->u.tcp.msglen;
+        misc->request.data = conn->u.tcp.buffer + 4;
 
-        if (getsockname(sock, ss2sa(&local_saddr),
+        if (getsockname(verto_get_fd(ev), ss2sa(&misc->local_saddr),
                         &local_saddrlen) == 0)
-            local_saddrp = ss2sa(&local_saddr);
+            local_saddrp = ss2sa(&misc->local_saddr);
 
-        err = dispatch(conn->handle, local_saddrp, &conn->u.tcp.faddr,
-                       &request, &conn->u.tcp.response, 1);
-        if (err) {
-            com_err(conn->prog, err, _("while dispatching (tcp)"));
-            goto kill_tcp_connection;
-        }
-        if (conn->u.tcp.response == NULL)
-            goto kill_tcp_connection;
-    have_response:
-        /* Queue outgoing response. */
-        store_32_be(conn->u.tcp.response->length, conn->u.tcp.lenbuf);
-        SG_SET(&conn->u.tcp.sgbuf[1], conn->u.tcp.response->data,
-               conn->u.tcp.response->length);
-        conn->u.tcp.sgp = conn->u.tcp.sgbuf;
-        conn->u.tcp.sgnum = 2;
-
-        if (convert_event(ctx, ev,
-                          VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
-                          process_tcp_connection_write))
-            return;
+        dispatch(misc->conn->handle, local_saddrp, &conn->u.tcp.faddr,
+                       &misc->request, process_tcp_response, misc, 1);
     }
 
     return;
-- 
1.7.6.2


--=-np5m4SEPiPtrzkJUNpDq
Content-Disposition: attachment;
	filename="0002-make-do_as_req-respond-via-a-callback.patch"
Content-Type: text/x-patch;
	name="0002-make-do_as_req-respond-via-a-callback.patch"; 
	charset="UTF-8"
Content-Transfer-Encoding: 7bit

>From 92781fb56fd9e80c5d29cc9c3720439d3cf637f4 Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccallum@redhat.com>
Date: Tue, 13 Sep 2011 18:04:59 -0400
Subject: [PATCH 2/4] make do_as_req() respond via a callback

---
 src/kdc/dispatch.c  |  106 ++++++++++++++++++++++++++++++++++----------------
 src/kdc/do_as_req.c |   14 ++++---
 src/kdc/kdc_util.h  |    4 +-
 3 files changed, 82 insertions(+), 42 deletions(-)

diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c
index af76e94..4c12172 100644
--- a/src/kdc/dispatch.c
+++ b/src/kdc/dispatch.c
@@ -36,6 +36,46 @@ static krb5_int32 last_usec = 0, last_os_random = 0;
 
 static krb5_error_code make_too_big_error (krb5_data **out);
 
+struct dispatch_misc {
+    void *misc;
+    krb5_responder respond;
+    krb5_data *request;
+    int is_tcp;
+};
+
+static void
+finish_dispatch(krb5_error_code ec,
+                krb5_data *response,
+                struct dispatch_misc *misc)
+{
+    krb5_responder oldrespond;
+    void *oldmisc;
+
+    assert(misc);
+    oldrespond = misc->respond;
+    oldmisc = misc->misc;
+
+    if (misc->is_tcp == 0 && response &&
+        response->length > max_dgram_reply_size) {
+        krb5_free_data(kdc_context, response);
+        response = NULL;
+        ec = make_too_big_error(&response);
+        if (ec)
+            krb5_klog_syslog(LOG_ERR, "error constructing "
+                             "KRB_ERR_RESPONSE_TOO_BIG error: %s",
+                             error_message(ec));
+    }
+
+#ifndef NOCACHE
+    /* put the response into the lookaside buffer */
+    else if (!ec)
+        kdc_insert_lookaside(misc->request, response);
+#endif
+
+    free(misc);
+    (*oldrespond)(ec, response, oldmisc);
+}
+
 void
 dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
          krb5_data *pkt, krb5_responder respond, void *misc, int is_tcp)
@@ -43,7 +83,18 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
     krb5_error_code retval;
     krb5_kdc_req *as_req;
     krb5_int32 now, now_usec;
-    krb5_data *response;
+    krb5_data *response = NULL;
+    struct dispatch_misc *newmisc;
+
+    newmisc = malloc(sizeof(*newmisc));
+    if (!newmisc) {
+        (*respond)(ENOMEM, NULL, misc);
+        return;
+    }
+    newmisc->misc = misc;
+    newmisc->respond = respond;
+    newmisc->request = pkt;
+    newmisc->is_tcp = is_tcp;
 
     /* decode incoming packet, and dispatch */
 
@@ -54,20 +105,22 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
         const char *name = 0;
         char buf[46];
 
-        if (is_tcp == 0 && response->length > max_dgram_reply_size)
-            goto too_big_for_udp;
-
-        name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
-                          from->address->contents, buf, sizeof (buf));
-        if (name == 0)
-            name = "[unknown address type]";
-        krb5_klog_syslog(LOG_INFO,
-                         "DISPATCH: repeated (retransmitted?) request from %s, resending previous response",
-                         name);
-        (*respond)(0, response, misc);
+        if (is_tcp != 0 || response->length <= max_dgram_reply_size) {
+            name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
+                              from->address->contents, buf, sizeof (buf));
+            if (name == 0)
+                name = "[unknown address type]";
+            krb5_klog_syslog(LOG_INFO,
+                             "DISPATCH: repeated (retransmitted?) request "
+                             "from %s, resending previous response",
+                             name);
+        }
+
+        finish_dispatch(0, response, newmisc);
         return;
     }
 #endif
+
     retval = krb5_crypto_us_timeofday(&now, &now_usec);
     if (retval == 0) {
         krb5_int32 usec_difference = now_usec-last_usec;
@@ -99,32 +152,17 @@ dispatch(void *cb, struct sockaddr *local_saddr, const krb5_fulladdr *from,
              * process_as_req frees the request if it is called
              */
             if (!(retval = setup_server_realm(as_req->server))) {
-                retval = process_as_req(as_req, pkt, from, &response);
+                process_as_req(as_req, pkt, from,
+                               (krb5_responder) finish_dispatch, newmisc);
+                return;
             }
-            else            krb5_free_kdc_req(kdc_context, as_req);
+            else
+                krb5_free_kdc_req(kdc_context, as_req);
         }
-    }
-    else
+    } else
         retval = KRB5KRB_AP_ERR_MSG_TYPE;
-#ifndef NOCACHE
-    /* put the response into the lookaside buffer */
-    if (!retval)
-        kdc_insert_lookaside(pkt, response);
-#endif
-
-    if (is_tcp == 0 && response != NULL &&
-        response->length > max_dgram_reply_size) {
-    too_big_for_udp:
-        krb5_free_data(kdc_context, response);
-        retval = make_too_big_error(&response);
-        if (retval) {
-            krb5_klog_syslog(LOG_ERR,
-                             "error constructing KRB_ERR_RESPONSE_TOO_BIG error: %s",
-                             error_message(retval));
-        }
-    }
 
-    (*respond)(retval, retval == 0 ? response : NULL, misc);
+    finish_dispatch(retval, response, newmisc);
 }
 
 static krb5_error_code
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 87bccdb..f295251 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -99,9 +99,9 @@ get_key_exp(krb5_db_entry *entry)
 }
 
 /*ARGSUSED*/
-krb5_error_code
+void
 process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
-               const krb5_fulladdr *from, krb5_data **response)
+               const krb5_fulladdr *from, krb5_responder respond, void *misc)
 {
     krb5_db_entry *client = NULL, *server = NULL;
     krb5_kdc_rep reply;
@@ -127,6 +127,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     struct kdc_request_state *state = NULL;
     krb5_data encoded_req_body;
     krb5_keyblock *as_encrypting_key = NULL;
+    krb5_data *response;
 
 
 #if APPLE_PKINIT
@@ -593,7 +594,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     }
 
     errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
-                                  0, as_encrypting_key,  &reply, response);
+                                  0, as_encrypting_key,  &reply, &response);
     reply.enc_part.kvno = client_key->key_data_kvno;
     if (errcode) {
         status = "ENCODE_KDC_REP";
@@ -639,11 +640,12 @@ egress:
 
         errcode = prepare_error_as(state, request, errcode, &e_data,
                                    (client != NULL) ? client->princ : NULL,
-                                   response, status);
+                                   &response, status);
         status = 0;
     }
 
-discard: if (emsg)
+discard:
+    if (emsg)
         krb5_free_error_message(kdc_context, emsg);
     if (enc_tkt_reply.authorization_data != NULL)
         krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
@@ -676,7 +678,7 @@ discard: if (emsg)
     krb5_free_kdc_req(kdc_context, request);
     assert(did_log != 0);
 
-    return errcode;
+    (*respond)(errcode, response, misc);
 }
 
 /*
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 36093ad..8338fba 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -118,10 +118,10 @@ void
 rep_etypes2str(char *s, size_t len, krb5_kdc_rep *rep);
 
 /* do_as_req.c */
-krb5_error_code
+void
 process_as_req (krb5_kdc_req *, krb5_data *,
                 const krb5_fulladdr *,
-                krb5_data ** );
+                krb5_responder, void *);
 
 /* do_tgs_req.c */
 krb5_error_code
-- 
1.7.6.2


--=-np5m4SEPiPtrzkJUNpDq
Content-Disposition: attachment;
	filename="0003-make-check_padata-respond-via-a-callback.patch"
Content-Type: text/x-patch;
	name="0003-make-check_padata-respond-via-a-callback.patch"; 
	charset="UTF-8"
Content-Transfer-Encoding: 7bit

>From 76188f827d8168bf1fb70f182e5e891e11f189dd Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccallum@redhat.com>
Date: Tue, 13 Sep 2011 18:14:44 -0400
Subject: [PATCH 3/4] make check_padata() respond via a callback

---
 src/kdc/do_as_req.c   |  903 +++++++++++++++++++++++++++----------------------
 src/kdc/kdc_preauth.c |   35 ++-
 src/kdc/kdc_util.h    |    5 +-
 3 files changed, 523 insertions(+), 420 deletions(-)

diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index f295251..afd4dc8 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -98,127 +98,464 @@ get_key_exp(krb5_db_entry *entry)
     return min(entry->expiration, entry->pw_expiration);
 }
 
-/*ARGSUSED*/
-void
-process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
-               const krb5_fulladdr *from, krb5_responder respond, void *misc)
-{
-    krb5_db_entry *client = NULL, *server = NULL;
-    krb5_kdc_rep reply;
+struct as_req_misc {
+    void *misc;
+    krb5_responder respond;
+
+    krb5_enc_tkt_part enc_tkt_reply;
     krb5_enc_kdc_rep_part reply_encpart;
     krb5_ticket ticket_reply;
-    krb5_enc_tkt_part enc_tkt_reply;
-    krb5_error_code errcode;
-    krb5_timestamp kdc_time, authtime = 0;
-    krb5_keyblock session_key;
+    krb5_keyblock server_keyblock;
+    krb5_keyblock client_keyblock;
+    krb5_db_entry *client;
+    krb5_db_entry *server;
+    krb5_kdc_req *request;
     const char *status;
-    krb5_key_data *server_key, *client_key;
-    krb5_keyblock server_keyblock, client_keyblock;
+    krb5_data e_data;
+    krb5_kdc_rep reply;
+    krb5_timestamp kdc_time;
     krb5_enctype useenctype;
-    krb5_data e_data = empty_data();
+    krb5_timestamp authtime;
+    krb5_keyblock session_key;
+    unsigned int c_flags;
+    krb5_data *req_pkt;
+    struct kdc_request_state *state;
+    char *sname, *cname;
+    void *pa_context;
+    const krb5_fulladdr *from;
+};
+
+static void
+finish_process_as_req(krb5_error_code errcode, struct as_req_misc *misc)
+{
+    krb5_key_data *server_key;
+    krb5_key_data *client_key;
+    krb5_keyblock *as_encrypting_key = NULL;
+    krb5_data *response;
+    const char *emsg = 0;
+    int did_log = 0;
     register int i;
+    void *oldmisc;
+    krb5_responder oldrespond;
+
+    assert(misc);
+    oldmisc = misc->misc;
+    oldrespond = misc->respond;
+
+    if (errcode)
+        goto errout;
+
+    /*
+     * Final check before handing out ticket: If the client requires
+     * preauthentication, verify that the proper kind of
+     * preauthentication was carried out.
+     */
+    misc->status = missing_required_preauth(misc->client,
+                                            misc->server,
+                                            &misc->enc_tkt_reply);
+    if (misc->status) {
+        errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
+        get_preauth_hint_list(misc->request, misc->client,
+                              misc->server, &misc->e_data);
+        goto errout;
+    }
+
+    if ((errcode = validate_forwardable(misc->request, *misc->client,
+                                        *misc->server, misc->kdc_time,
+                                        &misc->status))) {
+        errcode += ERROR_TABLE_BASE_krb5;
+        goto errout;
+    }
+
+    misc->ticket_reply.enc_part2 = &misc->enc_tkt_reply;
+
+    /*
+     * Find the server key
+     */
+    if ((errcode = krb5_dbe_find_enctype(kdc_context, misc->server,
+                                         -1, /* ignore keytype   */
+                                         -1, /* Ignore salttype  */
+                                         0,  /* Get highest kvno */
+                                         &server_key))) {
+        misc->status = "FINDING_SERVER_KEY";
+        goto errout;
+    }
+
+    /*
+     * Convert server->key into a real key
+     * (it may be encrypted in the database)
+     *
+     *  server_keyblock is later used to generate auth data signatures
+     */
+    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
+                                             server_key, &misc->server_keyblock,
+                                             NULL))) {
+        misc->status = "DECRYPT_SERVER_KEY";
+        goto errout;
+    }
+
+    /*
+     * Find the appropriate client key.  We search in the order specified
+     * by request keytype list.
+     */
+    client_key = (krb5_key_data *) NULL;
+    for (i = 0; i < misc->request->nktypes; i++) {
+        misc->useenctype = misc->request->ktype[i];
+        if (!krb5_c_valid_enctype(misc->useenctype))
+            continue;
+
+        if (!krb5_dbe_find_enctype(kdc_context, misc->client,
+                                   misc->useenctype, -1, 0, &client_key))
+            break;
+    }
+    if (!(client_key)) {
+        /* Cannot find an appropriate key */
+        misc->status = "CANT_FIND_CLIENT_KEY";
+        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+        goto errout;
+    }
+
+    /* convert client.key_data into a real key */
+    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
+                                             client_key, &misc->client_keyblock,
+                                             NULL))) {
+        misc->status = "DECRYPT_CLIENT_KEY";
+        goto errout;
+    }
+    misc->client_keyblock.enctype = misc->useenctype;
+
+    /* Start assembling the response */
+    misc->reply.msg_type = KRB5_AS_REP;
+    misc->reply.client = misc->enc_tkt_reply.client; /* post canonicalization */
+    misc->reply.ticket = &misc->ticket_reply;
+    misc->reply_encpart.session = &misc->session_key;
+    if ((errcode = fetch_last_req_info(misc->client,
+                                       &misc->reply_encpart.last_req))) {
+        misc->status = "FETCH_LAST_REQ";
+        goto errout;
+    }
+    misc->reply_encpart.nonce = misc->request->nonce;
+    misc->reply_encpart.key_exp = get_key_exp(misc->client);
+    misc->reply_encpart.flags = misc->enc_tkt_reply.flags;
+    misc->reply_encpart.server = misc->ticket_reply.server;
+
+    /* copy the time fields EXCEPT for authtime; it's location
+     *  is used for ktime
+     */
+    misc->reply_encpart.times = misc->enc_tkt_reply.times;
+    misc->reply_encpart.times.authtime = misc->authtime = misc->kdc_time;
+
+    misc->reply_encpart.caddrs = misc->enc_tkt_reply.caddrs;
+    misc->reply_encpart.enc_padata = NULL;
+
+    /* Fetch the padata info to be returned (do this before
+     *  authdata to handle possible replacement of reply key
+     */
+    errcode = return_padata(kdc_context, misc->client, misc->req_pkt,
+                            misc->request, &misc->reply, client_key,
+                            &misc->client_keyblock, &misc->pa_context);
+    if (errcode) {
+        misc->status = "KDC_RETURN_PADATA";
+        goto errout;
+    }
+
+#if APPLE_PKINIT
+    asReqDebug("process_as_req reply realm %s name %s\n",
+               reply.client->realm.data, reply.client->data->data);
+#endif /* APPLE_PKINIT */
+
+
+
+    errcode = handle_authdata(kdc_context,
+                              misc->c_flags,
+                              misc->client,
+                              misc->server,
+                              misc->server,
+                              &misc->client_keyblock,
+                              &misc->server_keyblock,
+                              &misc->server_keyblock,
+                              misc->req_pkt,
+                              misc->request,
+                              NULL, /* for_user_princ */
+                              NULL, /* enc_tkt_request */
+                              &misc->enc_tkt_reply);
+    if (errcode) {
+        krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
+                         errcode);
+        misc->status = "HANDLE_AUTHDATA";
+        goto errout;
+    }
+
+    errcode = krb5_encrypt_tkt_part(kdc_context, &misc->server_keyblock,
+                                    &misc->ticket_reply);
+    if (errcode) {
+        misc->status = "ENCRYPTING_TICKET";
+        goto errout;
+    }
+    misc->ticket_reply.enc_part.kvno = server_key->key_data_kvno;
+    errcode = kdc_fast_response_handle_padata(misc->state,
+                                              misc->request,
+                                              &misc->reply,
+                                              misc->client_keyblock.enctype);
+    if (errcode) {
+        misc->status = "fast response handling";
+        goto errout;
+    }
+
+    /* now encode/encrypt the response */
+
+    misc->reply.enc_part.enctype = misc->client_keyblock.enctype;
+
+    errcode = kdc_fast_handle_reply_key(misc->state, &misc->client_keyblock,
+                                        &as_encrypting_key);
+    if (errcode) {
+        misc->status = "generating reply key";
+        goto errout;
+    }
+    errcode = return_enc_padata(kdc_context, misc->req_pkt, misc->request,
+                                as_encrypting_key, misc->server,
+                                &misc->reply_encpart, FALSE);
+    if (errcode) {
+        misc->status = "KDC_RETURN_ENC_PADATA";
+        goto errout;
+    }
+
+    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP,
+                                  &misc->reply_encpart, 0,
+                                  as_encrypting_key,
+                                  &misc->reply, &response);
+    misc->reply.enc_part.kvno = client_key->key_data_kvno;
+    if (errcode) {
+        misc->status = "ENCODE_KDC_REP";
+        goto errout;
+    }
+
+    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
+       can use them in raw form if needed.  But, we don't... */
+    memset(misc->reply.enc_part.ciphertext.data, 0,
+           misc->reply.enc_part.ciphertext.length);
+    free(misc->reply.enc_part.ciphertext.data);
+
+    log_as_req(misc->from, misc->request, &misc->reply,
+               misc->client, misc->cname, misc->server,
+               misc->sname, misc->authtime, 0, 0, 0);
+    did_log = 1;
+
+    goto egress;
+
+errout:
+    assert (misc->status != 0);
+    /* fall through */
+
+egress:
+    free_padata_context(kdc_context, misc->pa_context);
+    if (as_encrypting_key)
+        krb5_free_keyblock(kdc_context, as_encrypting_key);
+    if (errcode)
+        emsg = krb5_get_error_message(kdc_context, errcode);
+
+    if (misc->status) {
+        log_as_req(misc->from, misc->request, &misc->reply, misc->client,
+                   misc->cname, misc->server, misc->sname, misc->authtime,
+                   misc->status, errcode, emsg);
+        did_log = 1;
+    }
+    if (errcode) {
+        if (misc->status == 0) {
+            misc->status = emsg;
+        }
+        if (errcode == KRB5KDC_ERR_DISCARD)
+            goto discard;
+        errcode -= ERROR_TABLE_BASE_krb5;
+        if (errcode < 0 || errcode > 128)
+            errcode = KRB_ERR_GENERIC;
+
+        errcode = prepare_error_as(misc->state, misc->request,
+                                   errcode, &misc->e_data,
+                                   (misc->client != NULL) ?
+                                           misc->client->princ :
+                                           NULL,
+                                   &response, misc->status);
+        misc->status = 0;
+    }
+
+discard:
+    if (emsg)
+        krb5_free_error_message(kdc_context, emsg);
+    if (misc->enc_tkt_reply.authorization_data != NULL)
+        krb5_free_authdata(kdc_context, misc->enc_tkt_reply.authorization_data);
+    if (misc->server_keyblock.contents != NULL)
+        krb5_free_keyblock_contents(kdc_context, &misc->server_keyblock);
+    if (misc->client_keyblock.contents != NULL)
+        krb5_free_keyblock_contents(kdc_context, &misc->client_keyblock);
+    if (misc->reply.padata != NULL)
+        krb5_free_pa_data(kdc_context, misc->reply.padata);
+    if (misc->reply_encpart.enc_padata)
+        krb5_free_pa_data(kdc_context, misc->reply_encpart.enc_padata);
+
+    if (misc->cname != NULL)
+        free(misc->cname);
+    if (misc->sname != NULL)
+        free(misc->sname);
+    krb5_db_free_principal(kdc_context, misc->client);
+    krb5_db_free_principal(kdc_context, misc->server);
+    if (misc->session_key.contents != NULL)
+        krb5_free_keyblock_contents(kdc_context, &misc->session_key);
+    if (misc->ticket_reply.enc_part.ciphertext.data != NULL) {
+        memset(misc->ticket_reply.enc_part.ciphertext.data , 0,
+               misc->ticket_reply.enc_part.ciphertext.length);
+        free(misc->ticket_reply.enc_part.ciphertext.data);
+    }
+
+    krb5_free_data_contents(kdc_context, &misc->e_data);
+    kdc_free_rstate(misc->state);
+    misc->request->kdc_state = NULL;
+    krb5_free_kdc_req(kdc_context, misc->request);
+    assert(did_log != 0);
+
+    free(misc);
+    (*oldrespond)(errcode, response, oldmisc);
+}
+
+static void
+finish_preauth(krb5_error_code errcode, struct as_req_misc *misc)
+{
+    if (errcode) {
+        if (errcode == KRB5KDC_ERR_PREAUTH_FAILED)
+            get_preauth_hint_list(misc->request, misc->client,
+                                  misc->server, &misc->e_data);
+
+        misc->status = "PREAUTH_FAILED";
+        if (vague_errors)
+            errcode = KRB5KRB_ERR_GENERIC;
+    }
+
+    finish_process_as_req(errcode, misc);
+}
+
+/*ARGSUSED*/
+void
+process_as_req(krb5_kdc_req *rqst, krb5_data *req_pkt,
+               const krb5_fulladdr *from, krb5_responder respond, void *misc)
+{
+    krb5_error_code errcode;
     krb5_timestamp rtime;
-    char *cname = 0, *sname = 0;
-    unsigned int c_flags = 0, s_flags = 0;
+    unsigned int s_flags = 0;
     krb5_principal_data client_princ;
-    void *pa_context = NULL;
-    int did_log = 0;
-    const char *emsg = 0;
-    struct kdc_request_state *state = NULL;
     krb5_data encoded_req_body;
-    krb5_keyblock *as_encrypting_key = NULL;
-    krb5_data *response;
-
+    struct as_req_misc *newmisc;
+
+    newmisc = malloc(sizeof(*newmisc));
+    if (!newmisc) {
+        (*respond)(ENOMEM, NULL, misc);
+        return;
+    }
+    newmisc->session_key.contents = 0;
+    newmisc->enc_tkt_reply.authorization_data = NULL;
+    newmisc->reply.padata = 0;
+    memset(&newmisc->reply, 0, sizeof(newmisc->reply));
+    newmisc->respond = respond;
+    newmisc->misc = misc;
+    newmisc->ticket_reply.enc_part.ciphertext.data = 0;
+    newmisc->server_keyblock.contents = NULL;
+    newmisc->client_keyblock.contents = NULL;
+    newmisc->reply_encpart.enc_padata = 0;
+    newmisc->client = NULL;
+    newmisc->server = NULL;
+    newmisc->request = rqst;
+    newmisc->e_data = empty_data();
+    newmisc->authtime = 0;
+    newmisc->req_pkt = req_pkt;
+    newmisc->state = NULL;
+    newmisc->sname = 0;
+    newmisc->cname = 0;
+    newmisc->pa_context = NULL;
+    newmisc->from = from;
 
 #if APPLE_PKINIT
     asReqDebug("process_as_req top realm %s name %s\n",
                request->client->realm.data, request->client->data->data);
 #endif /* APPLE_PKINIT */
 
-    ticket_reply.enc_part.ciphertext.data = 0;
-    server_keyblock.contents = NULL;
-    client_keyblock.contents = NULL;
-    reply.padata = 0;
-    reply_encpart.enc_padata = 0;
-    memset(&reply, 0, sizeof(reply));
-
-    session_key.contents = 0;
-    enc_tkt_reply.authorization_data = NULL;
-
-    if (request->msg_type != KRB5_AS_REQ) {
-        status = "msg_type mismatch";
+    if (newmisc->request->msg_type != KRB5_AS_REQ) {
+        newmisc->status = "msg_type mismatch";
         errcode = KRB5_BADMSGTYPE;
         goto errout;
     }
-    errcode = kdc_make_rstate(&state);
+    errcode = kdc_make_rstate(&newmisc->state);
     if (errcode != 0) {
-        status = "constructing state";
+        newmisc->status = "constructing state";
         goto errout;
     }
     if (fetch_asn1_field((unsigned char *) req_pkt->data,
                          1, 4, &encoded_req_body) != 0) {
         errcode = ASN1_BAD_ID;
-        status = "Finding req_body";
+        newmisc->status = "Finding req_body";
         goto errout;
     }
-    errcode = kdc_find_fast(&request, &encoded_req_body,
-                            NULL /*TGS key*/, NULL, state);
+    errcode = kdc_find_fast(&newmisc->request, &encoded_req_body,
+                            NULL /*TGS key*/, NULL, newmisc->state);
     if (errcode) {
-        status = "error decoding FAST";
+        newmisc->status = "error decoding FAST";
         goto errout;
     }
-    request->kdc_state = state;
-    if (!request->client) {
-        status = "NULL_CLIENT";
+    newmisc->request->kdc_state = newmisc->state;
+    if (!newmisc->request->client) {
+        newmisc->status = "NULL_CLIENT";
         errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
         goto errout;
     }
-    if ((errcode = krb5_unparse_name(kdc_context, request->client, &cname))) {
-        status = "UNPARSING_CLIENT";
+    if ((errcode = krb5_unparse_name(kdc_context,
+                                     newmisc->request->client,
+                                     &newmisc->cname))) {
+        newmisc->status = "UNPARSING_CLIENT";
         goto errout;
     }
-    limit_string(cname);
-    if (!request->server) {
-        status = "NULL_SERVER";
+    limit_string(newmisc->cname);
+    if (!newmisc->request->server) {
+        newmisc->status = "NULL_SERVER";
         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
         goto errout;
     }
-    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
-        status = "UNPARSING_SERVER";
+    if ((errcode = krb5_unparse_name(kdc_context,
+                                     newmisc->request->server,
+                                     &newmisc->sname))) {
+        newmisc->status = "UNPARSING_SERVER";
         goto errout;
     }
-    limit_string(sname);
+    limit_string(newmisc->sname);
 
     /*
      * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
      * to the backend to return naming information in lieu
      * of cross realm TGS entries.
      */
-    setflag(c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
+    setflag(newmisc->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
     /*
      * Note that according to the referrals draft we should
      * always canonicalize enterprise principal names.
      */
-    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) ||
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_CANONICALIZE) ||
         krb5_princ_type(kdc_context,
-                        request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
-        setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
-        setflag(c_flags, KRB5_KDB_FLAG_ALIAS_OK);
+                        newmisc->request->client) ==
+                                KRB5_NT_ENTERPRISE_PRINCIPAL) {
+        setflag(newmisc->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
+        setflag(newmisc->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
     }
-    if (include_pac_p(kdc_context, request)) {
-        setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
+    if (include_pac_p(kdc_context, newmisc->request)) {
+        setflag(newmisc->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
     }
-    errcode = krb5_db_get_principal(kdc_context, request->client,
-                                    c_flags, &client);
+    errcode = krb5_db_get_principal(kdc_context, newmisc->request->client,
+                                    newmisc->c_flags, &newmisc->client);
     if (errcode == KRB5_KDB_NOENTRY) {
-        status = "CLIENT_NOT_FOUND";
+        newmisc->status = "CLIENT_NOT_FOUND";
         if (vague_errors)
             errcode = KRB5KRB_ERR_GENERIC;
         else
             errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
         goto errout;
     } else if (errcode) {
-        status = "LOOKING_UP_CLIENT";
+        newmisc->status = "LOOKING_UP_CLIENT";
         goto errout;
     }
 
@@ -226,9 +563,9 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
      * If the backend returned a principal that is not in the local
      * realm, then we need to refer the client to that realm.
      */
-    if (!is_local_principal(client->princ)) {
+    if (!is_local_principal(newmisc->client->princ)) {
         /* Entry is a referral to another realm */
-        status = "REFERRAL";
+        newmisc->status = "REFERRAL";
         errcode = KRB5KDC_ERR_WRONG_REALM;
         goto errout;
     }
@@ -247,30 +584,31 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
 
     s_flags = 0;
     setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
-    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_CANONICALIZE)) {
         setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
     }
-    errcode = krb5_db_get_principal(kdc_context, request->server,
-                                    s_flags, &server);
+    errcode = krb5_db_get_principal(kdc_context, newmisc->request->server,
+                                    s_flags, &newmisc->server);
     if (errcode == KRB5_KDB_NOENTRY) {
-        status = "SERVER_NOT_FOUND";
+        newmisc->status = "SERVER_NOT_FOUND";
         errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
         goto errout;
     } else if (errcode) {
-        status = "LOOKING_UP_SERVER";
+        newmisc->status = "LOOKING_UP_SERVER";
         goto errout;
     }
 
-    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
-        status = "TIMEOFDAY";
+    if ((errcode = krb5_timeofday(kdc_context, &newmisc->kdc_time))) {
+        newmisc->status = "TIMEOFDAY";
         goto errout;
     }
-    authtime = kdc_time; /* for audit_as_request() */
+    newmisc->authtime = newmisc->kdc_time; /* for audit_as_request() */
 
-    if ((errcode = validate_as_request(request, *client, *server,
-                                       kdc_time, &status, &e_data))) {
-        if (!status)
-            status = "UNKNOWN_REASON";
+    if ((errcode = validate_as_request(newmisc->request, *newmisc->client,
+                                       *newmisc->server, newmisc->kdc_time,
+                                       &newmisc->status, &newmisc->e_data))) {
+        if (!newmisc->status)
+            newmisc->status = "UNKNOWN_REASON";
         errcode += ERROR_TABLE_BASE_krb5;
         goto errout;
     }
@@ -278,18 +616,19 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     /*
      * Select the keytype for the ticket session key.
      */
-    if ((useenctype = select_session_keytype(kdc_context, server,
-                                             request->nktypes,
-                                             request->ktype)) == 0) {
+    if ((newmisc->useenctype = select_session_keytype(kdc_context,
+                                              newmisc->server,
+                                              newmisc->request->nktypes,
+                                              newmisc->request->ktype)) == 0) {
         /* unsupported ktype */
-        status = "BAD_ENCRYPTION_TYPE";
+        newmisc->status = "BAD_ENCRYPTION_TYPE";
         errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
         goto errout;
     }
 
-    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
-                                          &session_key))) {
-        status = "RANDOM_KEY_FAILED";
+    if ((errcode = krb5_c_make_random_key(kdc_context, newmisc->useenctype,
+                                          &newmisc->session_key))) {
+        newmisc->status = "RANDOM_KEY_FAILED";
         goto errout;
     }
 
@@ -299,18 +638,18 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
      * aliases, nothing more).
      */
     if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
-        krb5_is_tgs_principal(request->server) &&
-        krb5_is_tgs_principal(server->princ)) {
-        ticket_reply.server = server->princ;
+        krb5_is_tgs_principal(newmisc->request->server) &&
+        krb5_is_tgs_principal(newmisc->server->princ)) {
+            newmisc->ticket_reply.server = newmisc->server->princ;
     } else {
-        ticket_reply.server = request->server;
+            newmisc->ticket_reply.server = newmisc->request->server;
     }
 
-    enc_tkt_reply.flags = 0;
-    enc_tkt_reply.times.authtime = authtime;
+    newmisc->enc_tkt_reply.flags = 0;
+    newmisc->enc_tkt_reply.times.authtime = newmisc->authtime;
 
-    setflag(enc_tkt_reply.flags, TKT_FLG_INITIAL);
-    setflag(enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
+    setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_INITIAL);
+    setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);
 
     /*
      * It should be noted that local policy may affect the
@@ -318,367 +657,119 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
      * realms may refuse to issue renewable tickets
      */
 
-    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
-        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_FORWARDABLE))
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
-    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
-        setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_PROXIABLE))
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
 
-    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
-        setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
 
-    enc_tkt_reply.session = &session_key;
-    if (isflagset(c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
-        client_princ = *(client->princ);
+    newmisc->enc_tkt_reply.session = &newmisc->session_key;
+    if (isflagset(newmisc->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
+        client_princ = *(newmisc->client->princ);
     } else {
-        client_princ = *(request->client);
+        client_princ = *(newmisc->request->client);
         /* The realm is always canonicalized */
-        client_princ.realm = *(krb5_princ_realm(context, client->princ));
+        client_princ.realm = *(krb5_princ_realm(context,
+                                                newmisc->client->princ));
     }
-    enc_tkt_reply.client = &client_princ;
-    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
-    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
+    newmisc->enc_tkt_reply.client = &client_princ;
+    newmisc->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
+    newmisc->enc_tkt_reply.transited.tr_contents =
+                                          empty_string; /* equivalent of "" */
+
 
-    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
-        setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
-        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
-        enc_tkt_reply.times.starttime = request->from;
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_POSTDATED)) {
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_INVALID);
+        newmisc->enc_tkt_reply.times.starttime = newmisc->request->from;
     } else
-        enc_tkt_reply.times.starttime = kdc_time;
+        newmisc->enc_tkt_reply.times.starttime = newmisc->kdc_time;
 
     kdc_get_ticket_endtime(kdc_context,
-                           enc_tkt_reply.times.starttime,
+                           newmisc->enc_tkt_reply.times.starttime,
                            kdc_infinity,
-                           request->till,
-                           client,
-                           server,
-                           &enc_tkt_reply.times.endtime);
+                           newmisc->request->till,
+                           newmisc->client,
+                           newmisc->server,
+                           &newmisc->enc_tkt_reply.times.endtime);
 
-    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
-        !isflagset(client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
-        (enc_tkt_reply.times.endtime < request->till)) {
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
+        !isflagset(newmisc->client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
+        (newmisc->enc_tkt_reply.times.endtime < newmisc->request->till)) {
 
         /* we set the RENEWABLE option for later processing */
 
-        setflag(request->kdc_options, KDC_OPT_RENEWABLE);
-        request->rtime = request->till;
+        setflag(newmisc->request->kdc_options, KDC_OPT_RENEWABLE);
+        newmisc->request->rtime = newmisc->request->till;
     }
-    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;
+    rtime = (newmisc->request->rtime == 0) ?
+            kdc_infinity :
+            newmisc->request->rtime;
 
-    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_RENEWABLE)) {
         /*
          * XXX Should we squelch the output renew_till to be no
          * earlier than the endtime of the ticket?
          */
-        setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
-        enc_tkt_reply.times.renew_till =
-            min(rtime, enc_tkt_reply.times.starttime +
-                min(client->max_renewable_life,
-                    min(server->max_renewable_life,
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
+        newmisc->enc_tkt_reply.times.renew_till =
+            min(rtime, newmisc->enc_tkt_reply.times.starttime +
+                min(newmisc->client->max_renewable_life,
+                    min(newmisc->server->max_renewable_life,
                         max_renewable_life_for_realm)));
     } else
-        enc_tkt_reply.times.renew_till = 0; /* XXX */
+        newmisc->enc_tkt_reply.times.renew_till = 0; /* XXX */
 
     /*
      * starttime is optional, and treated as authtime if not present.
      * so we can nuke it if it matches
      */
-    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
-        enc_tkt_reply.times.starttime = 0;
+    if (newmisc->enc_tkt_reply.times.starttime ==
+            newmisc->enc_tkt_reply.times.authtime)
+        newmisc->enc_tkt_reply.times.starttime = 0;
 
-    enc_tkt_reply.caddrs = request->addresses;
-    enc_tkt_reply.authorization_data = 0;
+    newmisc->enc_tkt_reply.caddrs = newmisc->request->addresses;
+    newmisc->enc_tkt_reply.authorization_data = 0;
 
     /* If anonymous requests are being used, adjust the realm of the client
      * principal. */
-    if (isflagset(request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
-        if (!krb5_principal_compare_any_realm(kdc_context, request->client,
+    if (isflagset(newmisc->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
+        if (!krb5_principal_compare_any_realm(kdc_context,
+                                              newmisc->request->client,
                                               krb5_anonymous_principal())) {
             errcode = KRB5KDC_ERR_BADOPTION;
-            status = "Anonymous requested but anonymous principal not used.";
+            newmisc->status = "Anonymous requested but anonymous "
+                              "principal not used.";
             goto errout;
         }
-        setflag(enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
-        krb5_free_principal(kdc_context, request->client);
+        setflag(newmisc->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
+        krb5_free_principal(kdc_context, newmisc->request->client);
         errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
-                                      &request->client);
+                                      &newmisc->request->client);
         if (errcode) {
-            status = "Copying anonymous principal";
+            newmisc->status = "Copying anonymous principal";
             goto errout;
         }
-        enc_tkt_reply.client = request->client;
-        setflag(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
+        newmisc->enc_tkt_reply.client = newmisc->request->client;
+        setflag(newmisc->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
     }
     /*
      * Check the preauthentication if it is there.
      */
-    if (request->padata) {
-        errcode = check_padata(kdc_context, client, req_pkt, request,
-                               &enc_tkt_reply, &pa_context, &e_data);
-        if (errcode) {
-            if (errcode == KRB5KDC_ERR_PREAUTH_FAILED)
-                get_preauth_hint_list(request, client, server, &e_data);
-
-            status = "PREAUTH_FAILED";
-            if (vague_errors)
-                errcode = KRB5KRB_ERR_GENERIC;
-            goto errout;
-        }
-    }
-
-    /*
-     * Final check before handing out ticket: If the client requires
-     * preauthentication, verify that the proper kind of
-     * preauthentication was carried out.
-     */
-    status = missing_required_preauth(client, server, &enc_tkt_reply);
-    if (status) {
-        errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
-        get_preauth_hint_list(request, client, server, &e_data);
-        goto errout;
-    }
-
-    if ((errcode = validate_forwardable(request, *client, *server,
-                                        kdc_time, &status))) {
-        errcode += ERROR_TABLE_BASE_krb5;
-        goto errout;
-    }
-
-    ticket_reply.enc_part2 = &enc_tkt_reply;
-
-    /*
-     * Find the server key
-     */
-    if ((errcode = krb5_dbe_find_enctype(kdc_context, server,
-                                         -1, /* ignore keytype   */
-                                         -1, /* Ignore salttype  */
-                                         0,  /* Get highest kvno */
-                                         &server_key))) {
-        status = "FINDING_SERVER_KEY";
-        goto errout;
-    }
-
-    /*
-     * Convert server->key into a real key
-     * (it may be encrypted in the database)
-     *
-     *  server_keyblock is later used to generate auth data signatures
-     */
-    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
-                                             server_key, &server_keyblock,
-                                             NULL))) {
-        status = "DECRYPT_SERVER_KEY";
-        goto errout;
-    }
-
-    /*
-     * Find the appropriate client key.  We search in the order specified
-     * by request keytype list.
-     */
-    client_key = (krb5_key_data *) NULL;
-    for (i = 0; i < request->nktypes; i++) {
-        useenctype = request->ktype[i];
-        if (!krb5_c_valid_enctype(useenctype))
-            continue;
-
-        if (!krb5_dbe_find_enctype(kdc_context, client, useenctype, -1,
-                                   0, &client_key))
-            break;
+    if (newmisc->request->padata) {
+        check_padata(kdc_context, newmisc->client, newmisc->req_pkt,
+                     newmisc->request, &newmisc->enc_tkt_reply,
+                     &newmisc->pa_context, &newmisc->e_data,
+                     (void (*)(krb5_error_code, void*)) finish_preauth,
+                     newmisc);
+        return;
     }
-    if (!(client_key)) {
-        /* Cannot find an appropriate key */
-        status = "CANT_FIND_CLIENT_KEY";
-        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
-        goto errout;
-    }
-
-    /* convert client.key_data into a real key */
-    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
-                                             client_key, &client_keyblock,
-                                             NULL))) {
-        status = "DECRYPT_CLIENT_KEY";
-        goto errout;
-    }
-    client_keyblock.enctype = useenctype;
-
-    /* Start assembling the response */
-    reply.msg_type = KRB5_AS_REP;
-    reply.client = enc_tkt_reply.client; /* post canonicalization */
-    reply.ticket = &ticket_reply;
-    reply_encpart.session = &session_key;
-    if ((errcode = fetch_last_req_info(client, &reply_encpart.last_req))) {
-        status = "FETCH_LAST_REQ";
-        goto errout;
-    }
-    reply_encpart.nonce = request->nonce;
-    reply_encpart.key_exp = get_key_exp(client);
-    reply_encpart.flags = enc_tkt_reply.flags;
-    reply_encpart.server = ticket_reply.server;
-
-    /* copy the time fields EXCEPT for authtime; it's location
-     *  is used for ktime
-     */
-    reply_encpart.times = enc_tkt_reply.times;
-    reply_encpart.times.authtime = authtime = kdc_time;
-
-    reply_encpart.caddrs = enc_tkt_reply.caddrs;
-    reply_encpart.enc_padata = NULL;
-
-    /* Fetch the padata info to be returned (do this before
-     *  authdata to handle possible replacement of reply key
-     */
-    errcode = return_padata(kdc_context, client, req_pkt, request,
-                            &reply, client_key, &client_keyblock, &pa_context);
-    if (errcode) {
-        status = "KDC_RETURN_PADATA";
-        goto errout;
-    }
-
-#if APPLE_PKINIT
-    asReqDebug("process_as_req reply realm %s name %s\n",
-               reply.client->realm.data, reply.client->data->data);
-#endif /* APPLE_PKINIT */
-
-
-
-    errcode = handle_authdata(kdc_context,
-                              c_flags,
-                              client,
-                              server,
-                              server,
-                              &client_keyblock,
-                              &server_keyblock,
-                              &server_keyblock,
-                              req_pkt,
-                              request,
-                              NULL, /* for_user_princ */
-                              NULL, /* enc_tkt_request */
-                              &enc_tkt_reply);
-    if (errcode) {
-        krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
-                         errcode);
-        status = "HANDLE_AUTHDATA";
-        goto errout;
-    }
-
-    errcode = krb5_encrypt_tkt_part(kdc_context, &server_keyblock,
-                                    &ticket_reply);
-    if (errcode) {
-        status = "ENCRYPTING_TICKET";
-        goto errout;
-    }
-    ticket_reply.enc_part.kvno = server_key->key_data_kvno;
-    errcode = kdc_fast_response_handle_padata(state, request, &reply,
-                                              client_keyblock.enctype);
-    if (errcode) {
-        status = "fast response handling";
-        goto errout;
-    }
-
-    /* now encode/encrypt the response */
-
-    reply.enc_part.enctype = client_keyblock.enctype;
-
-    errcode = kdc_fast_handle_reply_key(state, &client_keyblock,
-                                        &as_encrypting_key);
-    if (errcode) {
-        status = "generating reply key";
-        goto errout;
-    }
-    errcode = return_enc_padata(kdc_context, req_pkt, request,
-                                as_encrypting_key, server, &reply_encpart,
-                                FALSE);
-    if (errcode) {
-        status = "KDC_RETURN_ENC_PADATA";
-        goto errout;
-    }
-
-    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
-                                  0, as_encrypting_key,  &reply, &response);
-    reply.enc_part.kvno = client_key->key_data_kvno;
-    if (errcode) {
-        status = "ENCODE_KDC_REP";
-        goto errout;
-    }
-
-    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
-       can use them in raw form if needed.  But, we don't... */
-    memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length);
-    free(reply.enc_part.ciphertext.data);
-
-    log_as_req(from, request, &reply, client, cname, server, sname,
-               authtime, 0, 0, 0);
-    did_log = 1;
-
-    goto egress;
 
 errout:
-    assert (status != 0);
-    /* fall through */
-
-egress:
-    free_padata_context(kdc_context, pa_context);
-    if (as_encrypting_key)
-        krb5_free_keyblock(kdc_context, as_encrypting_key);
-    if (errcode)
-        emsg = krb5_get_error_message(kdc_context, errcode);
-
-    if (status) {
-        log_as_req(from, request, &reply, client, cname, server, sname,
-                   authtime, status, errcode, emsg);
-        did_log = 1;
-    }
-    if (errcode) {
-        if (status == 0) {
-            status = emsg;
-        }
-        if (errcode == KRB5KDC_ERR_DISCARD)
-            goto discard;
-        errcode -= ERROR_TABLE_BASE_krb5;
-        if (errcode < 0 || errcode > 128)
-            errcode = KRB_ERR_GENERIC;
-
-        errcode = prepare_error_as(state, request, errcode, &e_data,
-                                   (client != NULL) ? client->princ : NULL,
-                                   &response, status);
-        status = 0;
-    }
-
-discard:
-    if (emsg)
-        krb5_free_error_message(kdc_context, emsg);
-    if (enc_tkt_reply.authorization_data != NULL)
-        krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
-    if (server_keyblock.contents != NULL)
-        krb5_free_keyblock_contents(kdc_context, &server_keyblock);
-    if (client_keyblock.contents != NULL)
-        krb5_free_keyblock_contents(kdc_context, &client_keyblock);
-    if (reply.padata != NULL)
-        krb5_free_pa_data(kdc_context, reply.padata);
-    if (reply_encpart.enc_padata)
-        krb5_free_pa_data(kdc_context, reply_encpart.enc_padata);
-
-    if (cname != NULL)
-        free(cname);
-    if (sname != NULL)
-        free(sname);
-    krb5_db_free_principal(kdc_context, client);
-    krb5_db_free_principal(kdc_context, server);
-    if (session_key.contents != NULL)
-        krb5_free_keyblock_contents(kdc_context, &session_key);
-    if (ticket_reply.enc_part.ciphertext.data != NULL) {
-        memset(ticket_reply.enc_part.ciphertext.data , 0,
-               ticket_reply.enc_part.ciphertext.length);
-        free(ticket_reply.enc_part.ciphertext.data);
-    }
-
-    krb5_free_data_contents(kdc_context, &e_data);
-    kdc_free_rstate(state);
-    request->kdc_state = NULL;
-    krb5_free_kdc_req(kdc_context, request);
-    assert(did_log != 0);
-
-    (*respond)(errcode, response, misc);
+    finish_process_as_req(errcode, newmisc);
 }
 
 /*
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 72c1752..c297c95 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -940,10 +940,11 @@ add_authorization_data(krb5_enc_tkt_part *enc_tkt_part, krb5_authdata **ad)
  * an error code of some sort.
  */
 
-krb5_error_code
+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)
+              void **padata_context, krb5_data *e_data,
+              void (*respond)(krb5_error_code, void*), void *misc)
 {
     krb5_error_code retval = 0;
     krb5_pa_data **padata;
@@ -956,11 +957,14 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
     const char *emsg;
     krb5_authdata **tmp_authz_data = NULL;
 
-    if (request->padata == 0)
-        return 0;
+    if (request->padata == 0) {
+        (*respond)(0, misc);
+        return;
+    }
 
     if (make_padata_context(context, padata_context) != 0) {
-        return KRB5KRB_ERR_GENERIC;
+        (*respond)(KRB5KRB_ERR_GENERIC, misc);
+        return;
     }
 
 #ifdef DEBUG
@@ -1055,7 +1059,8 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
         e_data->data = malloc(pa_e_data->length);
         if (e_data->data == NULL) {
             krb5_free_data(context, pa_e_data);
-            return KRB5KRB_ERR_GENERIC;
+            (*respond)(KRB5KRB_ERR_GENERIC, misc);
+            return;
         }
         memcpy(e_data->data, pa_e_data->data, pa_e_data->length);
         e_data->length = pa_e_data->length;
@@ -1065,13 +1070,17 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
             retval = saved_retval;
     }
 
-    if (pa_ok)
-        return 0;
+    if (pa_ok) {
+        (*respond)(0, misc);
+        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)
-        return 0;
+    if (!pa_found) {
+        (*respond)(0, misc);
+        return;
+    }
 
 
     /* The following switch statement allows us
@@ -1104,9 +1113,11 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
         /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */
         /* case KRB5KDC_ERR_KEY_TOO_WEAK: */
     case KRB5KDC_ERR_DISCARD:
-        return retval;
+        (*respond)(retval, misc);
+        return;
     default:
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(KRB5KDC_ERR_PREAUTH_FAILED, misc);
+        return;
     }
 }
 
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 8338fba..908e8b1 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -176,12 +176,13 @@ load_preauth_plugins(krb5_context context);
 void
 unload_preauth_plugins(krb5_context context);
 
-krb5_error_code
+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);
+              void **padata_context, krb5_data *e_data,
+              void (*respond)(krb5_error_code, void*), void *misc);
 
 krb5_error_code
 return_padata (krb5_context context, krb5_db_entry *client,
-- 
1.7.6.2


--=-np5m4SEPiPtrzkJUNpDq
Content-Disposition: attachment;
	filename*0=0004-make-krb5_kdcpreauth_verify_fn-respond-via-a-callbac.pat;
	filename*1=ch
Content-Type: text/x-patch;
	name="0004-make-krb5_kdcpreauth_verify_fn-respond-via-a-callbac.patch"; 
	charset="UTF-8"
Content-Transfer-Encoding: 7bit

>From 3ec1c21b2c3f7648f09207165cdb6cd35551e0ec Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccallum@redhat.com>
Date: Tue, 13 Sep 2011 18:21:56 -0400
Subject: [PATCH 4/4] make krb5_kdcpreauth_verify_fn() respond via a callback

---
 src/include/krb5/preauth_plugin.h                  |   12 +-
 src/kdc/kdc_preauth.c                              |  348 ++++++++++++--------
 src/plugins/preauth/cksum_body/cksum_body_main.c   |   43 ++-
 .../encrypted_challenge/encrypted_challenge_main.c |   15 +-
 src/plugins/preauth/pkinit/pkinit_srv.c            |   43 ++--
 .../preauth/securid_sam2/securid_sam2_main.c       |   12 +-
 src/plugins/preauth/wpse/wpse_main.c               |   30 +-
 7 files changed, 305 insertions(+), 198 deletions(-)

diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index d376098..d8cf82b 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -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)(krb5_error_code error_code,
+                                     krb5_data *e_data,
+                                     krb5_authdata **authz_data,
+                                     void *misc);
+
+typedef void
 (*krb5_kdcpreauth_verify_fn)(krb5_context context,
                              struct _krb5_db_entry_new *client,
                              krb5_data *req_pkt, krb5_kdc_req *request,
@@ -428,8 +434,8 @@ typedef krb5_error_code
                              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 *misc);
 
 /*
  * Optional: generate preauthentication response data to send to the client as
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index c297c95..2a3a304 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -932,161 +932,77 @@ 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_misc {
+    void *misc;
+    void (*respond)(krb5_error_code, void*);
 
-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,
-              void (*respond)(krb5_error_code, void*), void *misc)
-{
-    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;
+    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)(0, misc);
-        return;
-    }
+    preauth_system *pa_sys;
+    krb5_data *pa_e_data;
+    int pa_ok;
+    krb5_error_code saved_ec;
+};
 
-    if (make_padata_context(context, padata_context) != 0) {
-        (*respond)(KRB5KRB_ERR_GENERIC, misc);
-        return;
-    }
+static void
+finish_check_padata(krb5_error_code ec, struct padata_misc *misc)
+{
+    void *oldmisc;
+    void (*oldrespond)(krb5_error_code, void*);
 
-#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(misc);
+    oldmisc = misc->misc;
+    oldrespond = misc->respond;
 
     /* 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 (misc->pa_ok && misc->pa_e_data != NULL) {
+        krb5_free_data(misc->context, misc->pa_e_data);
+        misc->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)(KRB5KRB_ERR_GENERIC, misc);
+    if (misc->pa_e_data != NULL) {
+        misc->e_data->data = malloc(misc->pa_e_data->length);
+        if (misc->e_data->data == NULL) {
+            krb5_free_data(misc->context, misc->pa_e_data);
+            free(misc);
+            (*oldrespond)(KRB5KRB_ERR_GENERIC, oldmisc);
             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(misc->e_data->data, misc->pa_e_data->data,
+               misc->pa_e_data->length);
+        misc->e_data->length = misc->pa_e_data->length;
+        krb5_free_data(misc->context, misc->pa_e_data);
+        misc->pa_e_data = NULL;
     }
 
-    if (pa_ok) {
-        (*respond)(0, misc);
+    if (misc->pa_ok) {
+        free(misc);
+        (*oldrespond)(0, oldmisc);
         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)(0, misc);
+    if (!misc->pa_found) {
+        free(misc);
+        (*oldrespond)(0, oldmisc);
         return;
     }
-
+    free(misc);
 
     /* The following switch statement allows us
      * to return some preauth system errors back to the client.
      */
-    switch(retval) {
+    switch(ec) {
     case 0: /* in case of PA-PAC-REQUEST with no PA-ENC-TIMESTAMP */
     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
     case KRB5KRB_AP_ERR_SKEW:
@@ -1110,15 +1026,179 @@ 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:
-        (*respond)(retval, misc);
+        (*oldrespond)(ec, oldmisc);
         return;
     default:
-        (*respond)(KRB5KDC_ERR_PREAUTH_FAILED, misc);
+        (*oldrespond)(KRB5KDC_ERR_PREAUTH_FAILED, oldmisc);
+        return;
+    }
+}
+
+static void
+next_padata(struct padata_misc *misc);
+
+static void
+finish_verify_padata(krb5_error_code ec, krb5_data *e_data,
+                     krb5_authdata **authz_data, struct padata_misc *misc)
+{
+    const char *emsg;
+
+    assert(misc);
+
+    if (ec) {
+        emsg = krb5_get_error_message (misc->context, ec);
+        krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s",
+                          misc->pa_sys->name, emsg);
+        krb5_free_error_message (misc->context, emsg);
+
+        /* Ignore authorization data returned from modules that fail */
+        if (authz_data != NULL) {
+            krb5_free_authdata(misc->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 (misc->pa_sys->flags & PA_REQUIRED) {
+            /* free up any previous edata we might have been saving */
+            if (misc->pa_e_data != NULL)
+                krb5_free_data(misc->context, misc->pa_e_data);
+            misc->pa_e_data = e_data;
+
+            /* Make sure we use the current retval */
+            misc->pa_ok = 0;
+            finish_check_padata(ec, misc);
+            return;
+        } else if (misc->pa_e_data == NULL) {
+            /* save the first error code and e-data */
+            misc->pa_e_data = e_data;
+            misc->saved_ec = ec;
+        } else if (e_data != NULL) {
+            /* discard this extra e-data from non-PA_REQUIRED module */
+            krb5_free_data(misc->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(misc->context, e_data);
+
+        /* Add any authorization data to the ticket */
+        if (authz_data != NULL) {
+            add_authorization_data(misc->enc_tkt_reply, authz_data);
+            free(authz_data);
+        }
+
+        misc->pa_ok = 1;
+        if (misc->pa_sys->flags & PA_SUFFICIENT) {
+            finish_check_padata(misc->saved_ec, misc);
+            return;
+        }
+    }
+
+    next_padata(misc);
+}
+
+static void
+next_padata(struct padata_misc *misc)
+{
+    krb5_kdcpreauth_modreq *modreq_ptr;
+
+    assert(misc);
+    if (!misc->padata)
+        misc->padata = misc->request->padata;
+    else
+        misc->padata++;
+
+    if (!*misc->padata) {
+        finish_check_padata(misc->saved_ec, misc);
+        return;
+    }
+
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*misc->padata)->pa_type);
+#endif
+    if (find_pa_system((*misc->padata)->pa_type, &misc->pa_sys))
+        goto next;
+    if (find_modreq(misc->pa_sys, *misc->padata_context, &modreq_ptr))
+        goto next;
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", misc->pa_sys->name);
+#endif
+    if (misc->pa_sys->verify_padata == 0)
+        goto next;
+
+    misc->pa_found++;
+    misc->pa_sys->verify_padata(misc->context, misc->client,
+                                misc->req_pkt, misc->request,
+                                misc->enc_tkt_reply, *misc->padata,
+                                get_entry_data, misc->pa_sys->moddata,
+                                modreq_ptr, (krb5_kdcpreauth_verify_respond_fn)
+                                                finish_verify_padata, misc);
+    return;
+
+next:
+    next_padata(misc);
+}
+
+/*
+ * 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,
+              void (*respond)(krb5_error_code, void*), void *misc)
+{
+    struct padata_misc *newmisc;
+
+    if (request->padata == 0) {
+        (*respond)(0, misc);
+        return;
+    }
+
+    if (make_padata_context(context, padata_context) != 0) {
+        (*respond)(KRB5KRB_ERR_GENERIC, misc);
         return;
     }
+
+    newmisc = malloc(sizeof(*newmisc));
+    if (!newmisc) {
+        (*respond)(ENOMEM, misc);
+        return;
+    }
+    memset(newmisc, 0, sizeof(*newmisc));
+    newmisc->context = context;
+    newmisc->client = client;
+    newmisc->req_pkt = req_pkt;
+    newmisc->request = request;
+    newmisc->enc_tkt_reply = enc_tkt_reply;
+    newmisc->padata_context = padata_context;
+    newmisc->e_data = e_data;
+    newmisc->respond = respond;
+    newmisc->misc = misc;
+
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, "checking padata");
+#endif
+
+    next_padata(newmisc);
 }
 
 /*
diff --git a/src/plugins/preauth/cksum_body/cksum_body_main.c b/src/plugins/preauth/cksum_body/cksum_body_main.c
index e79b84a..d88deb8 100644
--- a/src/plugins/preauth/cksum_body/cksum_body_main.c
+++ b/src/plugins/preauth/cksum_body/cksum_body_main.c
@@ -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,
@@ -339,8 +339,8 @@ server_verify(krb5_context kcontext,
               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 *misc)
 {
     krb5_int32 cksumtype;
     krb5_checksum checksum;
@@ -365,7 +365,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)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        return;
     }
     memcpy(&cksumtype, data->contents, 4);
     memset(&checksum, 0, sizeof(checksum));
@@ -379,14 +380,16 @@ server_verify(krb5_context kcontext,
                 "Is it supported?\n", checksum.checksum_type);
 #endif
         stats->failures++;
-        return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+        (*respond)(KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, misc);
+        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)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        return;
     }
     checksum.length = length;
 
@@ -398,7 +401,8 @@ server_verify(krb5_context kcontext,
         fprintf(stderr, "Error retrieving client keys.\n");
 #endif
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        return;
     }
 
     /* Find the key which would have been used to generate the checksum. */
@@ -429,7 +433,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)(KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, misc);
+        return;
     }
 
     /* Save a copy of the key. */
@@ -438,7 +443,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)(KRB5KDC_ERR_SUMTYPE_NOSUPP, NULL, NULL, misc);
+        return;
     }
     for (i = 0; keys[i].enctype != 0; i++)
         krb5_free_keyblock_contents(kcontext, &keys[i]);
@@ -454,7 +460,8 @@ server_verify(krb5_context kcontext,
                                  &req_body) != 0) {
         krb5_free_keyblock(kcontext, key);
         stats->failures++;
-        return KRB5KDC_ERR_PREAUTH_FAILED;
+        (*respond)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        return;
     }
 
 #ifdef DEBUG
@@ -488,14 +495,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)(KRB5KDC_ERR_PREAUTH_FAILED, test_edata, NULL, misc);
+        return;
     }
 
     /*
@@ -527,13 +535,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)(ENOMEM, NULL, NULL, misc);
+            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)(ENOMEM, NULL, NULL, misc);
+            return;
         }
         memset(my_authz_data[0]->contents, '\0', AD_ALLOC_SIZE);
         my_authz_data[0]->magic = KV5M_AUTHDATA;
@@ -543,7 +553,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 +565,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;
         }
     }
 
@@ -578,7 +587,7 @@ server_verify(krb5_context kcontext,
     /* Note that preauthentication succeeded. */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
     stats->successes++;
-    return 0;
+    (*respond)(0, test_edata, my_authz_data, misc);
 }
 
 /* Create the response for a client. */
diff --git a/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c
index 58a6592..89cec37 100644
--- a/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c
+++ b/src/plugins/preauth/encrypted_challenge/encrypted_challenge_main.c
@@ -188,14 +188,15 @@ 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 *misc)
 {
     krb5_error_code retval = 0;
     krb5_timestamp now;
@@ -211,8 +212,10 @@ kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
     int i = 0;
 
     plain.data = NULL;
-    if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0)
-        return 0;
+    if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) {
+        (*respond)(0, NULL, NULL, misc);
+        return;
+    }
 
     retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key);
     if (retval == 0 &&armor_key == NULL) {
@@ -297,7 +300,9 @@ kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
         kaccess.free_enc_data(context, enc);
     if (ts)
         kaccess.free_enc_ts(context, ts);
-    return retval;
+
+    (*respond)(retval, NULL, NULL, misc);
+    return;
 }
 
 static krb5_error_code
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 1dea777..f8eb21a 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -286,7 +286,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,8 +296,8 @@ pkinit_server_verify_padata(krb5_context 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)
+                            krb5_kdcpreauth_verify_respond_fn respond,
+                            void *misc)
 {
     krb5_error_code retval = 0;
     krb5_octet_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
@@ -315,10 +315,13 @@ pkinit_server_verify_padata(krb5_context context,
     krb5_data k5data;
     int is_signed = 1;
     krb5_keyblock *armor_key;
+    krb5_data *e_data = 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)(0, NULL, NULL, misc);
+        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)(EINVAL, NULL, NULL, misc);
+        return;
     }
 
-    if (moddata == NULL || e_data == NULL)
-        return EINVAL;
+    if (moddata == NULL) {
+        (*respond)(EINVAL, NULL, NULL, misc);
+        return;
+    }
 
     plgctx = pkinit_find_realm_context(context, moddata, request->server);
-    if (plgctx == NULL)
-        return 0;
+    if (plgctx == NULL) {
+        (*respond)(0, NULL, NULL, misc);
+        return;
+    }
 
 #ifdef DEBUG_ASN1
     print_buffer_bin(data->contents, data->length, "/tmp/kdc_as_req");
@@ -550,16 +558,6 @@ 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;
@@ -569,7 +567,7 @@ 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");
     }
 
@@ -595,7 +593,8 @@ cleanup:
     if (auth_pack9 != NULL)
         free_krb5_auth_pack_draft9(context, &auth_pack9);
 
-    return retval;
+    (*respond)(retval, e_data, NULL, misc);
+    return;
 }
 static krb5_error_code
 return_pkinit_kx(krb5_context context, krb5_kdc_req *request,
diff --git a/src/plugins/preauth/securid_sam2/securid_sam2_main.c b/src/plugins/preauth/securid_sam2/securid_sam2_main.c
index 0c420d2..7cbf41d 100644
--- a/src/plugins/preauth/securid_sam2/securid_sam2_main.c
+++ b/src/plugins/preauth/securid_sam2/securid_sam2_main.c
@@ -202,18 +202,19 @@ 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 *misc)
 {
     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 +277,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 +285,8 @@ encode_error:
     free(client_name);
     if (retval == 0)
         retval = saved_retval;
-    return retval;
+
+    (*respond)(retval, NULL, NULL, misc);
 }
 
 
diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c
index 866286c..7652c4b 100644
--- a/src/plugins/preauth/wpse/wpse_main.c
+++ b/src/plugins/preauth/wpse/wpse_main.c
@@ -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,
@@ -269,8 +269,8 @@ server_verify(krb5_context kcontext,
               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 *misc)
 {
     krb5_int32 nnonce;
     krb5_data *test_edata;
@@ -280,12 +280,16 @@ server_verify(krb5_context kcontext,
     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)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        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)(KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, misc);
+        return;
+    }
     /* Note that preauthentication succeeded. */
     enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
     enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
@@ -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)(ENOMEM, NULL, NULL, misc);
+            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)(ENOMEM, NULL, NULL, misc);
+            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)(0, test_edata, my_authz_data, misc);
 }
 
 /* Create the response for a client. */
-- 
1.7.6.2


--=-np5m4SEPiPtrzkJUNpDq
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
krbdev mailing list             krbdev@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev

--=-np5m4SEPiPtrzkJUNpDq--


home help back first fref pref prev next nref lref last post