From 1b885bfc9a05e3e030a0f49c16493f114bb661a1 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Sat, 15 Oct 2011 15:06:37 +0000 Subject: 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 --- src/kdc/kdc_preauth.c | 249 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 160 insertions(+), 89 deletions(-) (limited to 'src/kdc/kdc_preauth.c') 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 -- cgit