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