summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2011-10-15 15:06:37 +0000
committerGreg Hudson <ghudson@mit.edu>2011-10-15 15:06:37 +0000
commit1b885bfc9a05e3e030a0f49c16493f114bb661a1 (patch)
tree7c87da42594b6ae106ab8694032138ecbf674b27
parent5f8d6146a69b3afe6bf8a83d40e811c8a6d8f96b (diff)
downloadkrb5-1b885bfc9a05e3e030a0f49c16493f114bb661a1.tar.gz
krb5-1b885bfc9a05e3e030a0f49c16493f114bb661a1.tar.xz
krb5-1b885bfc9a05e3e030a0f49c16493f114bb661a1.zip
Make kdcpreauth edata method respond via callback
From npmccallum@redhat.com with changes. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25348 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/include/krb5/preauth_plugin.h30
-rw-r--r--src/kdc/kdc_preauth.c249
-rw-r--r--src/kdc/kdc_preauth_ec.c8
-rw-r--r--src/kdc/kdc_preauth_encts.c7
-rw-r--r--src/plugins/preauth/cksum_body/cksum_body_main.c22
-rw-r--r--src/plugins/preauth/pkinit/pkinit_srv.c14
-rw-r--r--src/plugins/preauth/wpse/wpse_main.c11
7 files changed, 218 insertions, 123 deletions
diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index e618edd97a..7d5dc99b1b 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -418,21 +418,31 @@ typedef int
(*krb5_kdcpreauth_flags_fn)(krb5_context context, krb5_preauthtype pa_type);
/*
- * Optional: fill in pa_out->length and pa_out->contents with data to send to
- * the client as part of the "you need to use preauthentication" error. If
- * this function returns non-zero, the padata type will not be included in the
- * list; if this function is not provided or returns zero without changing
- * pa_out, the padata type will be included in the list with an empty value.
- * This function not allowed to create a context because we have no guarantee
- * 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.
+ * Responder for krb5_kdcpreauth_edata_fn. If invoked with a non-zero code, pa
+ * will be ignored and the padata type will not be included in the hint list.
+ * If invoked with a zero code and a null pa value, the padata type will be
+ * included in the list with an empty value. If invoked with a zero code and a
+ * non-null pa value, pa will be included in the hint list and will later be
+ * freed by the KDC.
*/
-typedef krb5_error_code
+typedef void
+(*krb5_kdcpreauth_edata_respond_fn)(void *arg, krb5_error_code code,
+ krb5_pa_data *pa);
+
+/*
+ * Optional: provide pa_data to send to the client as part of the "you need to
+ * use preauthentication" error. This function is not allowed to create a
+ * modreq object because we have no guarantee that the client will ever make a
+ * follow-up request, or that it will hit this KDC if it does.
+ */
+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_preauthtype pa_type,
+ 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 13b51e3299..93fddd7753 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -104,15 +104,17 @@ typedef struct preauth_system_st {
krb5_kdcpreauth_free_modreq_fn free_modreq;
} preauth_system;
-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_preauthtype pa_type,
+ 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_preauthtype pa_type,
+ krb5_kdcpreauth_edata_respond_fn respond, void *arg);
static krb5_error_code
etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata,
@@ -744,67 +746,132 @@ const char *missing_required_preauth(krb5_db_entry *client,
return 0;
}
+struct hint_state {
+ kdc_hint_respond_fn respond;
+ 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_cur;
+ krb5_preauthtype pa_type;
+};
+
+static void
+hint_list_finish(struct hint_state *state, krb5_error_code code)
+{
+ kdc_hint_respond_fn oldrespond = state->respond;
+ void *oldarg = state->arg;
+
+ if (!code) {
+ if (state->pa_data[0] == 0) {
+ krb5_klog_syslog(LOG_INFO,
+ _("%spreauth required but hint list is empty"),
+ state->hw_only ? "hw" : "");
+ }
+ /* If we fail to get the cookie it is probably still reasonable to
+ * continue with the response. */
+ kdc_preauth_get_cookie(state->rock->rstate, state->pa_cur);
+
+ *state->e_data_out = state->pa_data;
+ state->pa_data = NULL;
+ }
+
+ krb5_free_pa_data(kdc_context, state->pa_data);
+ free(state);
+ (*oldrespond)(oldarg);
+}
+
+static void
+hint_list_next(struct hint_state *arg);
+
+static void
+finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
+{
+ struct hint_state *state = arg;
+
+ kdc_active_realm = state->realm;
+ if (code == 0) {
+ if (pa == NULL) {
+ /* Include an empty value of the current type. */
+ pa = calloc(1, sizeof(*pa));
+ pa->magic = KV5M_PA_DATA;
+ pa->pa_type = state->pa_type;
+ }
+ *state->pa_cur++ = pa;
+ }
+
+ state->ap++;
+ hint_list_next(state);
+}
+
+static void
+hint_list_next(struct hint_state *state)
+{
+ preauth_system *ap = state->ap;
+
+ if (ap->type == -1) {
+ hint_list_finish(state, 0);
+ return;
+ }
+
+ if (state->hw_only && !(ap->flags & PA_HARDWARE))
+ goto next;
+ if (ap->flags & PA_PSEUDO)
+ goto next;
+
+ state->pa_type = ap->type;
+ if (ap->get_edata) {
+ ap->get_edata(kdc_context, state->request, &callbacks, state->rock,
+ ap->moddata, ap->type, finish_get_edata, state);
+ } else
+ finish_get_edata(state, ap->type, NULL);
+ return;
+
+next:
+ state->ap++;
+ hint_list_next(state);
+}
+
void
get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
void *arg)
{
- int hw_only;
- preauth_system *ap;
- krb5_pa_data **pa_data, **pa;
- krb5_error_code retval;
+ struct hint_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_cur = state->pa_data;
+ state->ap = preauth_systems;
+ hint_list_next(state);
}
/*
@@ -1306,29 +1373,26 @@ fail:
free(salt.data);
return retval;
}
-/*
- * This function returns the etype information for a particular
- * client, to be passed back in the preauth list in the KRB_ERROR
- * message. It supports generating both etype_info and etype_info2
- * as most of the work is the same.
- */
-static krb5_error_code
+
+/* Create etype information for a client for the preauth-required hint list,
+ * for either etype-info or etype-info2. */
+static void
etype_info_helper(krb5_context context, krb5_kdc_req *request,
- krb5_db_entry *client, krb5_pa_data *pa_data,
- int etype_info2)
+ krb5_db_entry *client, krb5_preauthtype pa_type,
+ krb5_kdcpreauth_edata_respond_fn respond, void *arg)
{
- krb5_etype_info_entry ** entry = 0;
- krb5_key_data *client_key;
- krb5_error_code retval;
- krb5_data * scratch;
- krb5_enctype db_etype;
- int i = 0;
- int start = 0;
- int seen_des = 0;
+ krb5_error_code retval;
+ krb5_pa_data *pa = NULL;
+ krb5_etype_info_entry **entry = NULL;
+ krb5_data *scratch = NULL;
+ krb5_key_data *client_key;
+ krb5_enctype db_etype;
+ int i = 0, start = 0, seen_des = 0;
+ int etype_info2 = (pa_type == KRB5_PADATA_ETYPE_INFO2);
- entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *));
+ entry = k5alloc((client->n_key_data * 2 + 1) * sizeof(*entry), &retval);
if (entry == NULL)
- return ENOMEM;
+ goto cleanup;
entry[0] = NULL;
while (1) {
@@ -1349,7 +1413,6 @@ etype_info_helper(krb5_context context, krb5_kdc_req *request,
db_etype, &entry[i], etype_info2);
if (retval != 0)
goto cleanup;
- entry[i+1] = 0;
i++;
}
@@ -1387,39 +1450,47 @@ etype_info_helper(krb5_context context, krb5_kdc_req *request,
retval = encode_krb5_etype_info(entry, &scratch);
if (retval)
goto cleanup;
- pa_data->contents = (unsigned char *)scratch->data;
- pa_data->length = scratch->length;
- free(scratch);
-
- retval = 0;
+ pa = k5alloc(sizeof(*pa), &retval);
+ if (pa == NULL)
+ goto cleanup;
+ pa->magic = KV5M_PA_DATA;
+ pa->pa_type = pa_type;
+ pa->contents = (unsigned char *)scratch->data;
+ pa->length = scratch->length;
+ scratch->data = NULL;
cleanup:
- if (entry)
- krb5_free_etype_info(context, entry);
- return retval;
+ krb5_free_etype_info(context, entry);
+ krb5_free_data(context, scratch);
+ (*respond)(arg, retval, pa);
}
-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_preauthtype pa_type,
+ 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])) {
+ /* Requestor understands etype-info2, so don't send etype-info. */
+ (*respond)(arg, KRB5KDC_ERR_PADATA_TYPE_NOSUPP, NULL);
+ return;
+ }
}
- return etype_info_helper(context, request, rock->client, pa_data, 0);
+
+ etype_info_helper(context, request, rock->client, pa_type, respond, 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_preauthtype pa_type,
+ krb5_kdcpreauth_edata_respond_fn respond, void *arg)
{
- return etype_info_helper(context, request, rock->client, pa_data, 1);
+ etype_info_helper(context, request, rock->client, pa_type, respond, arg);
}
static krb5_error_code
diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c
index e5f5d6e586..9d7236c101 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_preauthtype pa_type,
+ 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, NULL);
}
static void
diff --git a/src/kdc/kdc_preauth_encts.c b/src/kdc/kdc_preauth_encts.c
index 48626d9722..a63298a9c4 100644
--- a/src/kdc/kdc_preauth_encts.c
+++ b/src/kdc/kdc_preauth_encts.c
@@ -28,14 +28,15 @@
#include <krb5/preauth_plugin.h>
#include "kdc_util.h"
-static krb5_error_code
+static void
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_preauthtype pa_type,
+ 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, NULL);
}
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 da2643fc18..6643e8e042 100644
--- a/src/plugins/preauth/cksum_body/cksum_body_main.c
+++ b/src/plugins/preauth/cksum_body/cksum_body_main.c
@@ -271,13 +271,15 @@ server_fini(krb5_context kcontext, krb5_kdcpreauth_moddata moddata)
/* 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_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
+ krb5_kdcpreauth_edata_respond_fn respond, void *arg)
{
krb5_keyblock *keys;
krb5_int32 *enctypes, enctype;
+ krb5_pa_data *data;
int i;
/* Retrieve the client's keys. */
@@ -285,7 +287,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, NULL);
+ return;
}
/* Count which types of keys we've got. */
@@ -295,7 +298,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, NULL);
+ return;
}
#ifdef DEBUG
fprintf(stderr, "Supported enctypes = {");
@@ -310,11 +314,17 @@ server_get_edata(krb5_context kcontext, krb5_kdc_req *request,
#ifdef DEBUG
fprintf(stderr, "}.\n");
#endif
+ cb->free_keys(kcontext, rock, keys);
+ data = malloc(sizeof(*data));
+ if (data == NULL) {
+ free(enctypes);
+ (*respond)(arg, ENOMEM, NULL);
+ }
+ data->magic = KV5M_PA_DATA;
data->pa_type = KRB5_PADATA_CKSUM_BODY_REQ;
data->length = (i * 4);
data->contents = (unsigned char *) enctypes;
- cb->free_keys(kcontext, rock, keys);
- return 0;
+ (*respond)(arg, 0, data);
}
/* 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 d209f9e76f..e43fb7e816 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_preauthtype pa_type,
+ 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, NULL);
+ 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, NULL);
}
static krb5_error_code
diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c
index 4da2c2f48c..4f603474d8 100644
--- a/src/plugins/preauth/wpse/wpse_main.c
+++ b/src/plugins/preauth/wpse/wpse_main.c
@@ -243,18 +243,17 @@ 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_preauthtype pa_type,
+ krb5_kdcpreauth_edata_respond_fn respond,
+ void *arg)
{
- /* Return zero bytes of data. */
- data->length = 0;
- data->contents = NULL;
- return 0;
+ (*respond)(arg, 0, NULL);
}
/* Verify a request from a client. */