aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2012-10-23 13:02:12 -0400
committerGreg Hudson <ghudson@mit.edu>2012-12-19 14:24:22 -0500
commit5c23bce0e8d3328bb36bc85ee10cfac486b8ae9b (patch)
treeae833e0dc6016ded58b0f89cfc30d26e5521afcf /src
parentf0794cba6a406fc834434eb6dc794bf29eda4a13 (diff)
downloadkrb5-5c23bce0e8d3328bb36bc85ee10cfac486b8ae9b.zip
krb5-5c23bce0e8d3328bb36bc85ee10cfac486b8ae9b.tar.gz
krb5-5c23bce0e8d3328bb36bc85ee10cfac486b8ae9b.tar.bz2
Use a proper consumer interface for clpreauth
In preauth2.c, use wrapper functions for calls to clpreauth functions. Get rid of the expanded-out module table, instead using a helper function to find the handle for a preauth type. Replace use counts with a list of previously processed pa types. Check for pa type conflicts when loading clpreauth modules.
Diffstat (limited to 'src')
-rw-r--r--src/include/k5-trace.h9
-rw-r--r--src/lib/krb5/krb/preauth2.c778
2 files changed, 365 insertions, 422 deletions
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
index df7159f..53dcba5 100644
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -235,6 +235,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
#define TRACE_MSPAC_DISCARD_UNVERF(c) \
TRACE(c, "Filtering out unverified MS PAC")
+#define TRACE_PREAUTH_CONFLICT(c, name1, name2, patype) \
+ TRACE(c, "Preauth module {str} conflicts with module {str} for pa " \
+ "type {int}", name1, name2, (int) patype)
#define TRACE_PREAUTH_COOKIE(c, len, data) \
TRACE(c, "Received cookie: {lenstr}", (size_t) len, data)
#define TRACE_PREAUTH_ENC_TS_KEY_GAK(c, keyblock) \
@@ -252,9 +255,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
TRACE(c, "Processing preauth types: {patypes}", padata)
#define TRACE_PREAUTH_OUTPUT(c, padata) \
TRACE(c, "Produced preauth for next request: {patypes}", padata)
-#define TRACE_PREAUTH_PROCESS(c, name, patype, flags, code) \
- TRACE(c, "Preauth module {str} ({int}) (flags={int}) returned: " \
- "{kerr}", name, (int) patype, flags, code)
+#define TRACE_PREAUTH_PROCESS(c, name, patype, real, code) \
+ TRACE(c, "Preauth module {str} ({int}) ({str}) returned: " \
+ "{kerr}", name, (int) patype, real ? "real" : "info", code)
#define TRACE_PREAUTH_SAM_KEY_GAK(c, keyblock) \
TRACE(c, "AS key obtained for SAM: {keyblock}", keyblock)
#define TRACE_PREAUTH_SALT(c, salt, patype) \
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
index 60504e4..fbf7a44 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -42,78 +42,59 @@
#include <unistd.h>
#endif
-/* This structure lets us keep track of all of the modules which are loaded,
- * turning the list of modules and their lists of implemented preauth types
- * into a single list which we can walk easily. */
+typedef struct {
+ struct krb5_clpreauth_vtable_st vt;
+ krb5_clpreauth_moddata data;
+ krb5_clpreauth_modreq req;
+} *clpreauth_handle;
+
struct krb5_preauth_context_st {
- int n_modules;
- struct krb5_preauth_context_module_st {
- /* Which of the possibly more than one preauth types which the
- * module supports we're using at this point in the list. */
- krb5_preauthtype pa_type;
- /* Encryption types which the client claims to support -- we
- * copy them directly into the krb5_kdc_req structure during
- * krb5_preauth_prepare_request(). */
- krb5_enctype *enctypes;
- /* The plugin's module data and a function to clear it. */
- krb5_clpreauth_moddata moddata;
- krb5_clpreauth_fini_fn client_fini;
- /* The module's table, and some of its members, copied here for
- * convenience when we populated the list. */
- const char *name;
- int flags, use_count;
- krb5_clpreauth_prep_questions_fn client_prep_questions;
- krb5_clpreauth_process_fn client_process;
- krb5_clpreauth_tryagain_fn client_tryagain;
- krb5_clpreauth_supply_gic_opts_fn client_supply_gic_opts;
- krb5_clpreauth_request_init_fn client_req_init;
- krb5_clpreauth_request_fini_fn client_req_fini;
- /* The per-request context which the client_req_init() function
- * might allocate, which we'll need to clean up later by
- * calling the client_req_fini() function. */
- krb5_clpreauth_modreq modreq;
- /* A pointer to the request_context pointer. All modules within
- * a plugin will point at the request_context of the first
- * module within the plugin. */
- krb5_clpreauth_modreq *modreq_p;
- } *modules;
+ krb5_preauthtype *tried;
+ clpreauth_handle *handles;
};
-typedef krb5_error_code (*pa_function)(krb5_context,
- krb5_kdc_req *request,
- krb5_pa_data *in_padata,
- krb5_pa_data **out_padata,
- krb5_data *salt, krb5_data *s2kparams,
- krb5_enctype *etype,
- krb5_keyblock *as_key,
- krb5_prompter_fct prompter_fct,
- void *prompter_data,
- krb5_gic_get_as_key_fct gak_fct,
- void *gak_data);
-
-typedef struct _pa_types_t {
- krb5_preauthtype type;
- pa_function fct;
- int flags;
-} pa_types_t;
-
-/* Create the per-krb5_context context. This means loading the modules
- * if we haven't done that yet (applications which never obtain initial
- * credentials should never hit this routine), breaking up the module's
- * list of support pa_types so that we can iterate over the modules more
- * easily, and copying over the relevant parts of the module's table. */
+/* Release the memory used by a list of handles. */
+static void
+free_handles(krb5_context context, clpreauth_handle *handles)
+{
+ clpreauth_handle *hp, h;
+
+ if (handles == NULL)
+ return;
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->vt.fini != NULL)
+ h->vt.fini(context, h->data);
+ free(h);
+ }
+ free(handles);
+}
+
+/* Find the handle in handles which can process pa_type. */
+static clpreauth_handle
+find_module(clpreauth_handle *handles, krb5_preauthtype pa_type)
+{
+ clpreauth_handle *hp, h;
+ krb5_preauthtype *tp;
+
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+ for (tp = h->vt.pa_type_list; *tp != 0; tp++) {
+ if (*tp == pa_type)
+ return h;
+ }
+ }
+ return FALSE;
+}
+
+/* Initialize the preauth state for a krb5 context. */
void KRB5_CALLCONV
krb5_init_preauth_context(krb5_context kcontext)
{
- int n_tables, n_modules, i, count;
- krb5_plugin_initvt_fn *plugins = NULL, *pl;
- struct krb5_clpreauth_vtable_st *vtables = NULL, *vt;
- struct krb5_preauth_context_module_st *mod;
- krb5_preauth_context *context = NULL;
- krb5_clpreauth_moddata moddata;
- krb5_preauthtype pa_type, *pat;
- krb5_boolean first;
- krb5_clpreauth_modreq *rcpp;
+ krb5_plugin_initvt_fn *modules = NULL, *mod;
+ clpreauth_handle *list = NULL, h, h2;
+ size_t count;
+ krb5_preauthtype *tp;
/* Only do this once for each krb5_context */
if (kcontext->preauth_context != NULL)
@@ -134,105 +115,61 @@ krb5_init_preauth_context(krb5_context kcontext)
clpreauth_otp_initvt);
/* Get all available clpreauth vtables. */
- if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins))
+ if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &modules))
return;
- for (count = 0; plugins[count] != NULL; count++);
- vtables = calloc(count, sizeof(*vtables));
- if (vtables == NULL)
+
+ /* Allocate a large enough list of handles. */
+ for (count = 0; modules[count] != NULL; count++);
+ list = calloc(count + 1, sizeof(*list));
+ if (list == NULL)
goto cleanup;
- for (pl = plugins, n_tables = 0; *pl != NULL; pl++) {
- if ((*pl)(kcontext, 1, 2, (krb5_plugin_vtable)&vtables[n_tables]) == 0)
- n_tables++;
- }
- /* Count how many modules we ended up loading, and how many preauth
- * types we may claim to support as a result. */
- n_modules = 0;
- for (i = 0; i < n_tables; i++) {
- for (count = 0; vtables[i].pa_type_list[count] > 0; count++);
- n_modules += count;
- }
+ /* Create a handle for each module we can successfully initialize. */
+ count = 0;
+ for (mod = modules; *mod != NULL; mod++) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ goto cleanup;
- /* Allocate the space we need. */
- context = malloc(sizeof(*context));
- if (context == NULL)
- goto cleanup;
- context->modules = calloc(n_modules, sizeof(*context->modules));
- if (context->modules == NULL)
- goto cleanup;
+ /* Initialize the handle vtable. */
+ if ((*mod)(kcontext, 1, 1, (krb5_plugin_vtable)&h->vt) != 0) {
+ free(h);
+ continue;
+ }
- /* fill in the structure */
- n_modules = 0;
- for (i = 0; i < n_tables; i++) {
- vt = &vtables[i];
- if ((vt->pa_type_list != NULL) && (vt->process != NULL)) {
- moddata = NULL;
- if (vt->init != NULL && vt->init(kcontext, &moddata) != 0) {
-#ifdef DEBUG
- fprintf(stderr, "init err, skipping module \"%s\"\n",
- vt->name);
-#endif
- continue;
+ /* Check for a preauth type conflict with an existing module. */
+ for (tp = h->vt.pa_type_list; *tp != 0; tp++) {
+ h2 = find_module(list, *tp);
+ if (h2 != NULL) {
+ TRACE_PREAUTH_CONFLICT(kcontext, h->vt.name, h2->vt.name, *tp);
+ break;
}
+ }
+ if (*tp != 0)
+ continue;
- rcpp = NULL;
- for (pat = vt->pa_type_list, first = TRUE; *pat > 0;
- pat++, first = FALSE) {
- pa_type = *pat;
- mod = &context->modules[n_modules];
- mod->pa_type = pa_type;
- mod->enctypes = vt->enctype_list;
- mod->moddata = moddata;
- /* Only call client_fini once per plugin */
- if (first)
- mod->client_fini = vt->fini;
- else
- mod->client_fini = NULL;
- mod->name = vt->name;
- mod->flags = (*vt->flags)(kcontext, pa_type);
- mod->use_count = 0;
- mod->client_prep_questions = vt->prep_questions;
- mod->client_process = vt->process;
- mod->client_tryagain = vt->tryagain;
- mod->client_supply_gic_opts = first ? vt->gic_opts : NULL;
- mod->modreq = NULL;
- /*
- * Only call request_init and request_fini once per plugin.
- * Only the first module within each plugin will ever
- * have request_context filled in. Every module within
- * the plugin will have its request_context_pp pointing
- * to that entry's request_context. That way all the
- * modules within the plugin share the same request_context
- */
- if (first) {
- mod->client_req_init = vt->request_init;
- mod->client_req_fini = vt->request_fini;
- rcpp = &mod->modreq;
- } else {
- mod->client_req_init = NULL;
- mod->client_req_fini = NULL;
- }
- mod->modreq_p = rcpp;
-#ifdef DEBUG
- fprintf(stderr, "init module \"%s\", pa_type %d, flag %d\n",
- mod->name, mod->pa_type, mod->flags);
-#endif
- n_modules++;
- }
+ /* Initialize the module data. */
+ h->data = NULL;
+ if (h->vt.init != NULL && h->vt.init(kcontext, &h->data) != 0) {
+ free(h);
+ continue;
}
+ list[count++] = h;
+ list[count] = NULL;
}
- context->n_modules = n_modules;
+ list[count] = NULL;
/* Place the constructed preauth context into the krb5 context. */
- kcontext->preauth_context = context;
- context = NULL;
+ kcontext->preauth_context = malloc(sizeof(struct krb5_preauth_context_st));
+ if (kcontext->preauth_context == NULL)
+ goto cleanup;
+ kcontext->preauth_context->tried = NULL;
+ kcontext->preauth_context->handles = list;
+ list = NULL;
cleanup:
- if (context)
- free(context->modules);
- free(context);
- k5_plugin_free_modules(kcontext, plugins);
- free(vtables);
+ k5_plugin_free_modules(kcontext, modules);
+ free_handles(kcontext, list);
}
/* Zero the use counts for the modules herein. Usually used before we
@@ -241,12 +178,12 @@ cleanup:
void KRB5_CALLCONV
krb5_clear_preauth_context_use_counts(krb5_context context)
{
- int i;
- if (context->preauth_context != NULL) {
- for (i = 0; i < context->preauth_context->n_modules; i++) {
- context->preauth_context->modules[i].use_count = 0;
- }
- }
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+
+ if (pctx == NULL)
+ return;
+ free(pctx->tried);
+ pctx->tried = NULL;
}
@@ -256,19 +193,13 @@ krb5_clear_preauth_context_use_counts(krb5_context context)
void KRB5_CALLCONV
krb5_free_preauth_context(krb5_context context)
{
- int i;
- struct krb5_preauth_context_module_st *mod;
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
- if (context == NULL || context->preauth_context == NULL)
+ if (pctx == NULL)
return;
- for (i = 0; i < context->preauth_context->n_modules; i++) {
- mod = &context->preauth_context->modules[i];
- if (mod->client_fini != NULL)
- mod->client_fini(context, mod->moddata);
- zap(mod, sizeof(*mod));
- }
- free(context->preauth_context->modules);
- free(context->preauth_context);
+ free(pctx->tried);
+ free_handles(context, pctx->handles);
+ free(pctx);
context->preauth_context = NULL;
}
@@ -277,18 +208,20 @@ krb5_free_preauth_context(krb5_context context)
void KRB5_CALLCONV
krb5_preauth_request_context_init(krb5_context context)
{
- int i;
- struct krb5_preauth_context_module_st *mod;
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+ clpreauth_handle *hp, h;
- if (context->preauth_context == NULL)
+ if (pctx == NULL) {
krb5_init_preauth_context(context);
- if (context->preauth_context == NULL)
- return;
- for (i = 0; i < context->preauth_context->n_modules; i++) {
- context->preauth_context->modules[i].use_count = 0;
- mod = &context->preauth_context->modules[i];
- if (mod->client_req_init != NULL)
- mod->client_req_init(context, mod->moddata, mod->modreq_p);
+ pctx = context->preauth_context;
+ if (pctx == NULL)
+ return;
+ }
+ krb5_clear_preauth_context_use_counts(context);
+ for (hp = pctx->handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->vt.request_init != NULL)
+ h->vt.request_init(context, h->data, &h->req);
}
}
@@ -297,21 +230,80 @@ krb5_preauth_request_context_init(krb5_context context)
void KRB5_CALLCONV
krb5_preauth_request_context_fini(krb5_context context)
{
- int i;
- struct krb5_preauth_context_module_st *mod;
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+ clpreauth_handle *hp, h;
- if (context->preauth_context == NULL)
+ if (pctx == NULL)
return;
- for (i = 0; i < context->preauth_context->n_modules; i++) {
- mod = &context->preauth_context->modules[i];
- if (mod->modreq != NULL) {
- if (mod->client_req_fini != NULL)
- mod->client_req_fini(context, mod->moddata, mod->modreq);
- mod->modreq = NULL;
- }
+ for (hp = pctx->handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->req != NULL && h->vt.request_fini != NULL)
+ h->vt.request_fini(context, h->data, h->req);
+ h->req = NULL;
}
}
+/* Return 1 if pa_type is a real preauthentication mechanism according to the
+ * module h. Return 0 if it is not. */
+static int
+clpreauth_is_real(krb5_context context, clpreauth_handle h,
+ krb5_preauthtype pa_type)
+{
+ return (h->vt.flags(context, pa_type) & PA_REAL) != 0;
+}
+
+static krb5_error_code
+clpreauth_prep_questions(krb5_context context, clpreauth_handle h,
+ krb5_get_init_creds_opt *opt,
+ krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
+ krb5_kdc_req *req, krb5_data *req_body,
+ krb5_data *prev_req, krb5_pa_data *pa_data)
+{
+ if (h->vt.prep_questions == NULL)
+ return 0;
+ return h->vt.prep_questions(context, h->data, h->req, opt, cb, rock, req,
+ req_body, prev_req, pa_data);
+}
+
+static krb5_error_code
+clpreauth_process(krb5_context context, clpreauth_handle h,
+ krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb,
+ krb5_clpreauth_rock rock, krb5_kdc_req *req,
+ krb5_data *req_body, krb5_data *prev_req,
+ krb5_pa_data *pa_data, krb5_prompter_fct prompter,
+ void *prompter_data, krb5_pa_data ***pa_data_out)
+{
+ return h->vt.process(context, h->data, h->req, opt, cb, rock, req,
+ req_body, prev_req, pa_data, prompter, prompter_data,
+ pa_data_out);
+}
+
+static krb5_error_code
+clpreauth_tryagain(krb5_context context, clpreauth_handle h,
+ krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb,
+ krb5_clpreauth_rock rock, krb5_kdc_req *req,
+ krb5_data *req_body, krb5_data *prev_req,
+ krb5_preauthtype pa_type, krb5_error *error,
+ krb5_pa_data **error_padata, krb5_prompter_fct prompter,
+ void *prompter_data, krb5_pa_data ***pa_data_out)
+{
+ if (h->vt.tryagain == NULL)
+ return 0;
+ return h->vt.tryagain(context, h->data, h->req, opt, cb, rock, req,
+ req_body, prev_req, pa_type, error, error_padata,
+ prompter, prompter_data, pa_data_out);
+}
+
+static krb5_error_code
+clpreauth_gic_opts(krb5_context context, clpreauth_handle h,
+ krb5_get_init_creds_opt *opt, const char *attr,
+ const char *value)
+{
+ if (h->vt.gic_opts == NULL)
+ return 0;
+ return h->vt.gic_opts(context, h->data, opt, attr, value);
+}
+
/* Add the named encryption type to the existing list of ktypes. */
static void
grow_ktypes(krb5_enctype **out_ktypes, int *out_nktypes, krb5_enctype ktype)
@@ -500,22 +492,21 @@ krb5_preauth_prepare_request(krb5_context kcontext,
krb5_gic_opt_ext *opte,
krb5_kdc_req *request)
{
- int i, j;
+ struct krb5_preauth_context_st *pctx = kcontext->preauth_context;
+ clpreauth_handle *hp, h;
+ krb5_enctype *ep;
- if (kcontext->preauth_context == NULL) {
+ if (pctx == NULL)
return;
- }
- /* Add the module-specific enctype list to the request, but only if
- * it's something we can safely modify. */
- if (!(opte && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) {
- for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
- if (kcontext->preauth_context->modules[i].enctypes == NULL)
- continue;
- for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) {
- grow_ktypes(&request->ktype, &request->nktypes,
- kcontext->preauth_context->modules[i].enctypes[j]);
- }
- }
+ /* Don't modify the enctype list if it's specified in the gic opts. */
+ if (opte != NULL && (opte->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))
+ return;
+ for (hp = pctx->handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->vt.enctype_list == NULL)
+ continue;
+ for (ep = h->vt.enctype_list; *ep != ENCTYPE_NULL; ep++)
+ grow_ktypes(&request->ktype, &request->nktypes, *ep);
}
}
@@ -545,83 +536,99 @@ krb5_responder_set_answer(krb5_context ctx, krb5_responder_context rctx,
return k5_response_items_set_answer(rctx->items, question, answer);
}
-/* Find the first module which provides for the named preauth type which also
- * hasn't had a chance to run yet (INFO modules don't count, because as a rule
- * they don't generate preauth data), and run it. */
+/* Return true if pa_type matches the specific preauth type allowed for this
+ * authentication, or if there is no specific allowed type. */
+static inline krb5_boolean
+pa_type_allowed(krb5_clpreauth_rock rock, krb5_preauthtype pa_type)
+{
+ return *rock->allowed_preauth_type == KRB5_PADATA_NONE ||
+ pa_type == *rock->allowed_preauth_type;
+}
+
+/*
+ * If pa_type has already been tried as a real preauth type for this
+ * authentication, return true. Otherwise ass pa_type to the list of tried
+ * types and return false.
+ */
+static krb5_boolean
+already_tried(krb5_context context, krb5_preauthtype pa_type)
+{
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+ size_t count;
+ krb5_preauthtype *newptr;
+
+ for (count = 0; pctx->tried != NULL && pctx->tried[count] != 0; count++) {
+ if (pctx->tried[count] == pa_type)
+ return TRUE;
+ }
+ newptr = realloc(pctx->tried, (count + 2) * sizeof(*newptr));
+ if (newptr == NULL)
+ return FALSE;
+ pctx->tried = newptr;
+ pctx->tried[count] = pa_type;
+ pctx->tried[count + 1] = ENCTYPE_NULL;
+ return FALSE;
+}
+
+/* Allow clpreauth modules to process in_pa_list and produce output padata.
+ * Set *preauthed to true if we succeeded on a real preauth type. */
static krb5_error_code
-run_preauth_plugins(krb5_context kcontext,
- int module_required_flags,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data *in_padata,
- krb5_prompter_fct prompter,
- void *prompter_data,
- krb5_clpreauth_rock preauth_rock,
- krb5_pa_data ***out_pa_list,
- int *out_pa_list_size,
- krb5_error_code *module_ret,
- krb5_gic_opt_ext *opte)
+process_pa_data(krb5_context context, krb5_get_init_creds_opt *opt,
+ krb5_clpreauth_rock rock, krb5_kdc_req *req,
+ krb5_data *req_body, krb5_data *prev_req,
+ krb5_pa_data **in_pa_list, krb5_prompter_fct prompter,
+ void *prompter_data, krb5_pa_data ***out_pa_list,
+ int *out_pa_list_size, krb5_boolean *got_real_out)
{
- int i;
- krb5_pa_data **out_pa_data;
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+ krb5_pa_data *pa, **pa_ptr, **mod_pa;
krb5_error_code ret;
- struct krb5_preauth_context_module_st *module;
+ clpreauth_handle h;
+ int real, i;
- if (kcontext->preauth_context == NULL) {
+ if (pctx == NULL)
return ENOENT;
- }
- /* iterate over all loaded modules */
- for (i = 0; i < kcontext->preauth_context->n_modules; i++) {
- module = &kcontext->preauth_context->modules[i];
- /* skip over those which don't match the preauth type */
- if (module->pa_type != in_padata->pa_type)
- continue;
- /* skip over those which don't match the flags (INFO vs REAL, mainly) */
- if ((module->flags & module_required_flags) == 0)
- continue;
- if ((module->flags & PA_REAL) &&
- *preauth_rock->allowed_preauth_type != KRB5_PADATA_NONE &&
- in_padata->pa_type != *preauth_rock->allowed_preauth_type)
- continue;
- /* if it's a REAL module, try to call it only once per library call */
- if (module_required_flags & PA_REAL) {
- if (module->use_count > 0) {
- TRACE_PREAUTH_SKIP(kcontext, module->name, module->pa_type);
+
+ /* Process all informational padata types, then the first real preauth type
+ * we succeed on. */
+ for (real = 0; real <= 1; real++) {
+ for (pa_ptr = in_pa_list; *pa_ptr != NULL; pa_ptr++) {
+ pa = *pa_ptr;
+ /* Restrict real mechanisms to the chosen one if we have one. */
+ if (real && !pa_type_allowed(rock, pa->pa_type))
+ continue;
+ h = find_module(pctx->handles, pa->pa_type);
+ if (h == NULL)
+ continue;
+ /* Make sure this type is for the current pass. */
+ if (clpreauth_is_real(context, h, pa->pa_type) != real)
continue;
+ /* Only try a real mechanism once per authentication. */
+ if (real && already_tried(context, pa->pa_type))
+ continue;
+ mod_pa = NULL;
+ ret = clpreauth_process(context, h, opt, &callbacks, rock, req,
+ req_body, prev_req, pa, prompter,
+ prompter_data, &mod_pa);
+ TRACE_PREAUTH_PROCESS(context, h->vt.name, pa->pa_type, real,
+ ret);
+ if (mod_pa != NULL) {
+ for (i = 0; mod_pa[i] != NULL; i++);
+ ret = grow_pa_list(out_pa_list, out_pa_list_size, mod_pa, i);
+ if (ret) {
+ krb5_free_pa_data(context, mod_pa);
+ return ret;
+ }
+ free(mod_pa);
+ }
+ if (ret == 0 && real) {
+ /* Record which real padata type we answered. */
+ if (rock->selected_preauth_type != NULL)
+ *rock->selected_preauth_type = pa->pa_type;
+ *got_real_out = TRUE;
+ break;
}
- module->use_count++;
- }
- /* run the module's callback function */
- out_pa_data = NULL;
-#ifdef DEBUG
- fprintf(stderr, "using module \"%s\" (%d), flags = %d\n",
- module->name, module->pa_type, module->flags);
-#endif
- ret = module->client_process(kcontext, module->moddata,
- *module->modreq_p,
- (krb5_get_init_creds_opt *)opte,
- &callbacks, preauth_rock,
- request, encoded_request_body,
- encoded_previous_request, in_padata,
- prompter, prompter_data, &out_pa_data);
- TRACE_PREAUTH_PROCESS(kcontext, module->name, module->pa_type,
- module->flags, ret);
- /* Make note of the module's flags and status. */
- *module_ret = ret;
- /* Save the new preauth data item. */
- if (out_pa_data != NULL) {
- int j;
- for (j = 0; out_pa_data[j] != NULL; j++);
- ret = grow_pa_list(out_pa_list, out_pa_list_size, out_pa_data, j);
- free(out_pa_data);
- if (ret != 0)
- return ret;
}
- break;
- }
- if (i >= kcontext->preauth_context->n_modules) {
- return ENOENT;
}
return 0;
}
@@ -832,133 +839,87 @@ add_s4u_x509_user_padata(krb5_context context, krb5_s4u_userid *userid,
* ask the user another question, we let the calling application deal with it.
*/
krb5_error_code KRB5_CALLCONV
-krb5_do_preauth_tryagain(krb5_context kcontext,
- krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data **padata,
- krb5_pa_data ***return_padata,
- krb5_error *err_reply,
- krb5_pa_data **err_padata,
+krb5_do_preauth_tryagain(krb5_context context, krb5_kdc_req *req,
+ krb5_data *req_body, krb5_data *prev_req,
+ krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
+ krb5_error *err_reply, krb5_pa_data **err_padata,
krb5_prompter_fct prompter, void *prompter_data,
- krb5_clpreauth_rock preauth_rock,
- krb5_gic_opt_ext *opte)
+ krb5_clpreauth_rock rock, krb5_gic_opt_ext *opte)
{
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
krb5_error_code ret;
- krb5_pa_data **out_padata;
- krb5_preauth_context *context;
- struct krb5_preauth_context_module_st *module;
- int i, j;
- int out_pa_list_size = 0;
+ krb5_pa_data **mod_pa;
+ krb5_get_init_creds_opt *opt = (krb5_get_init_creds_opt *)opte;
+ clpreauth_handle h;
+ int i;
- ret = KRB5KRB_ERR_GENERIC;
- if (kcontext->preauth_context == NULL) {
- return KRB5KRB_ERR_GENERIC;
- }
- context = kcontext->preauth_context;
- if (context == NULL) {
+ *out_padata = NULL;
+ if (pctx == NULL)
return KRB5KRB_ERR_GENERIC;
- }
- TRACE_PREAUTH_TRYAGAIN_INPUT(kcontext, padata);
+ TRACE_PREAUTH_TRYAGAIN_INPUT(context, in_padata);
- for (i = 0; padata[i] != NULL && padata[i]->pa_type != 0; i++) {
+ for (i = 0; in_padata[i] != NULL; i++) {
out_padata = NULL;
- for (j = 0; j < context->n_modules; j++) {
- module = &context->modules[j];
- if (module->pa_type != padata[i]->pa_type) {
- continue;
- }
- if ((module->flags & PA_REAL) &&
- *preauth_rock->allowed_preauth_type != KRB5_PADATA_NONE &&
- padata[i]->pa_type != *preauth_rock->allowed_preauth_type) {
- /* It's unlikely that we'll get here. */
- continue;
- }
- if (module->client_tryagain == NULL) {
- continue;
- }
- if ((*module->client_tryagain)(kcontext, module->moddata,
- *module->modreq_p,
- (krb5_get_init_creds_opt *)opte,
- &callbacks, preauth_rock,
- request,
- encoded_request_body,
- encoded_previous_request,
- padata[i]->pa_type,
- err_reply, err_padata,
- prompter, prompter_data,
- &out_padata) == 0) {
- if (out_padata != NULL) {
- int k;
- for (k = 0; out_padata[k] != NULL; k++);
- grow_pa_list(return_padata, &out_pa_list_size,
- out_padata, k);
- free(out_padata);
- TRACE_PREAUTH_TRYAGAIN_OUTPUT(kcontext, *return_padata);
- return 0;
- }
- }
+ h = find_module(pctx->handles, in_padata[i]->pa_type);
+ if (h == NULL)
+ continue;
+ mod_pa = NULL;
+ ret = clpreauth_tryagain(context, h, opt, &callbacks, rock, req,
+ req_body, prev_req, in_padata[i]->pa_type,
+ err_reply, err_padata, prompter,
+ prompter_data, &mod_pa);
+ if (ret == 0 && mod_pa != NULL) {
+ TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa);
+ *out_padata = mod_pa;
+ return 0;
}
}
- return ret;
+ return KRB5KRB_ERR_GENERIC;
}
/* Compile the set of response items for in_padata by invoke each module's
* prep_questions method. */
static krb5_error_code
-fill_response_items(krb5_context context, krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data **in_padata, krb5_clpreauth_rock rock,
- krb5_gic_opt_ext *opte)
+fill_response_items(krb5_context context, krb5_get_init_creds_opt *opt,
+ krb5_clpreauth_rock rock, krb5_kdc_req *req,
+ krb5_data *req_body, krb5_data *prev_req,
+ krb5_pa_data **in_padata)
{
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
krb5_error_code ret;
krb5_pa_data *pa;
- struct krb5_preauth_context_module_st *module;
- krb5_clpreauth_prep_questions_fn prep_questions;
- int i, j;
+ clpreauth_handle h;
+ int i;
k5_response_items_reset(rock->rctx.items);
for (i = 0; in_padata[i] != NULL; i++) {
pa = in_padata[i];
- for (j = 0; j < context->preauth_context->n_modules; j++) {
- module = &context->preauth_context->modules[j];
- prep_questions = module->client_prep_questions;
- if (module->pa_type != pa->pa_type || prep_questions == NULL)
- continue;
- if ((module->flags & PA_REAL) &&
- *rock->allowed_preauth_type != KRB5_PADATA_NONE &&
- pa->pa_type != *rock->allowed_preauth_type)
- continue;
- ret = (*prep_questions)(context, module->moddata,
- *module->modreq_p,
- (krb5_get_init_creds_opt *)opte,
- &callbacks, rock, request,
- encoded_request_body,
- encoded_previous_request, pa);
- if (ret)
- return ret;
- }
+ if (!pa_type_allowed(rock, pa->pa_type))
+ continue;
+ h = find_module(pctx->handles, pa->pa_type);
+ if (h == NULL)
+ continue;
+ ret = clpreauth_prep_questions(context, h, opt, &callbacks, rock, req,
+ req_body, prev_req, pa);
+ if (ret)
+ return ret;
}
return 0;
}
krb5_error_code KRB5_CALLCONV
-krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
- krb5_data *encoded_request_body,
- krb5_data *encoded_previous_request,
- krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
- krb5_prompter_fct prompter, void *prompter_data,
- krb5_clpreauth_rock rock, krb5_gic_opt_ext *opte,
- krb5_boolean *got_real_out)
+krb5_do_preauth(krb5_context context, krb5_kdc_req *req, krb5_data *req_body,
+ krb5_data *prev_req, krb5_pa_data **in_padata,
+ krb5_pa_data ***out_padata, krb5_prompter_fct prompter,
+ void *prompter_data, krb5_clpreauth_rock rock,
+ krb5_gic_opt_ext *opte, krb5_boolean *got_real_out)
{
- size_t i, h;
int out_pa_list_size = 0;
krb5_pa_data **out_pa_list = NULL;
- krb5_error_code ret, module_ret;
+ krb5_error_code ret;
krb5_responder_fn responder = opte->opt_private->responder;
- static const int paorder[] = { PA_INFO, PA_REAL };
+ krb5_get_init_creds_opt *opt = (krb5_get_init_creds_opt *)opte;
*out_padata = NULL;
*got_real_out = FALSE;
@@ -969,7 +930,7 @@ krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
TRACE_PREAUTH_INPUT(context, in_padata);
/* Scan the padata list and process etype-info or salt elements. */
- ret = get_etype_info(context, in_padata, request, rock);
+ ret = get_etype_info(context, in_padata, req, rock);
if (ret)
return ret;
@@ -981,9 +942,8 @@ krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
if (krb5int_find_pa_data(context, in_padata,
KRB5_PADATA_S4U_X509_USER) != NULL) {
/* Fulfill a private contract with krb5_get_credentials_for_user. */
- ret = add_s4u_x509_user_padata(context, *rock->gak_data,
- request->client, &out_pa_list,
- &out_pa_list_size);
+ ret = add_s4u_x509_user_padata(context, *rock->gak_data, req->client,
+ &out_pa_list, &out_pa_list_size);
if (ret)
goto error;
}
@@ -996,8 +956,8 @@ krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
}
/* Get a list of response items for in_padata from the preauth modules. */
- ret = fill_response_items(context, request, encoded_request_body,
- encoded_previous_request, in_padata, rock, opte);
+ ret = fill_response_items(context, opt, rock, req, req_body, prev_req,
+ in_padata);
if (ret)
goto error;
@@ -1009,29 +969,11 @@ krb5_do_preauth(krb5_context context, krb5_kdc_req *request,
goto error;
}
- /* Produce output padata, first from all the informational preauths, then
- * the from first real one. */
- for (h = 0; h < sizeof(paorder) / sizeof(paorder[0]); h++) {
- for (i = 0; in_padata[i] != NULL; i++) {
-#ifdef DEBUG
- fprintf (stderr, "trying modules for pa_type %d, flag %d\n",
- in_padata[i]->pa_type, paorder[h]);
-#endif
- ret = run_preauth_plugins(context, paorder[h], request,
- encoded_request_body,
- encoded_previous_request, in_padata[i],
- prompter, prompter_data, rock,
- &out_pa_list, &out_pa_list_size,
- &module_ret, opte);
- if (ret == 0 && module_ret == 0 && paorder[h] == PA_REAL) {
- /* Record which real padata type we answered. */
- if (rock->selected_preauth_type != NULL)
- *rock->selected_preauth_type = in_padata[i]->pa_type;
- *got_real_out = TRUE;
- break;
- }
- }
- }
+ ret = process_pa_data(context, opt, rock, req, req_body, prev_req,
+ in_padata, prompter, prompter_data, &out_pa_list,
+ &out_pa_list_size, got_real_out);
+ if (ret)
+ goto error;
TRACE_PREAUTH_OUTPUT(context, out_pa_list);
*out_padata = out_pa_list;
@@ -1050,38 +992,36 @@ krb5_error_code
krb5_preauth_supply_preauth_data(krb5_context context, krb5_gic_opt_ext *opte,
const char *attr, const char *value)
{
- krb5_error_code retval = 0;
- int i;
- struct krb5_preauth_context_module_st *mod;
+ struct krb5_preauth_context_st *pctx = context->preauth_context;
+ krb5_get_init_creds_opt *opt = (krb5_get_init_creds_opt *)opte;
+ clpreauth_handle *hp, h;
+ krb5_error_code ret;
const char *emsg = NULL;
- if (context->preauth_context == NULL)
+ if (pctx == NULL) {
krb5_init_preauth_context(context);
- if (context->preauth_context == NULL) {
- retval = EINVAL;
- krb5_set_error_message(context, retval,
- _("Unable to initialize preauth context"));
- return retval;
+ pctx = context->preauth_context;
+ if (pctx == NULL) {
+ krb5_set_error_message(context, EINVAL,
+ _("Unable to initialize preauth context"));
+ return EINVAL;
+ }
}
/*
* Go down the list of preauth modules, and supply them with the
* attribute/value pair.
*/
- for (i = 0; i < context->preauth_context->n_modules; i++) {
- mod = &context->preauth_context->modules[i];
- if (mod->client_supply_gic_opts == NULL)
- continue;
- retval = mod->client_supply_gic_opts(context, mod->moddata,
- (krb5_get_init_creds_opt *)opte,
- attr, value);
- if (retval) {
- emsg = krb5_get_error_message(context, retval);
- krb5_set_error_message(context, retval, _("Preauth plugin %s: %s"),
- mod->name, emsg);
+ for (hp = pctx->handles; *hp != NULL; hp++) {
+ h = *hp;
+ ret = clpreauth_gic_opts(context, h, opt, attr, value);
+ if (ret) {
+ emsg = krb5_get_error_message(context, ret);
+ krb5_set_error_message(context, ret, _("Preauth module %s: %s"),
+ h->vt.name, emsg);
krb5_free_error_message(context, emsg);
- break;
+ return ret;
}
}
- return retval;
+ return 0;
}