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,
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);
}
/*
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) {
db_etype, &entry[i], etype_info2);
if (retval != 0)
goto cleanup;
- entry[i+1] = 0;
i++;
}
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