diff options
| author | Kevin Coffman <kwc@citi.umich.edu> | 2006-11-01 22:40:30 +0000 |
|---|---|---|
| committer | Kevin Coffman <kwc@citi.umich.edu> | 2006-11-01 22:40:30 +0000 |
| commit | 2b2f711f2addee052253e4ff54fb7cdf3e20c0ae (patch) | |
| tree | a3e86969623f704a21780e47936a7a0ee5cd15f0 /src/lib | |
| parent | 45fde258dbced00d2db9d999d5749cb186f2250d (diff) | |
| download | krb5-2b2f711f2addee052253e4ff54fb7cdf3e20c0ae.tar.gz krb5-2b2f711f2addee052253e4ff54fb7cdf3e20c0ae.tar.xz krb5-2b2f711f2addee052253e4ff54fb7cdf3e20c0ae.zip | |
Modify the preath plugin interface so that a plugin's context is
global to all the modules within a plugin. Also, change the
client-side interface so that the preauth plugin context (once
created) lives the lifetime of a krb5_context. This will allow
future changes that can set plugin parameters. The client side
request context lives the lifetime of a call to krb5_get_init_creds().
Make the sample preauth plugins buildable outside the source tree.
Fix minor memory leak in sort_krb5_padata_sequence().
Add a prototype for krb5_do_preauth_tryagain() and change the plugin
interface.
Incorporates fixes from Nalin Dahyabhai <nalin@redhat.com> for leaks
of the function table pointers (rt #4566) and fix KDC crash (rt #4567)
ticket: 4566
ticket: 4567
ticket: 4587
Target_Version: 1.6
Tags: pullup
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18754 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 30 | ||||
| -rw-r--r-- | src/lib/krb5/krb/init_ctx.c | 1 | ||||
| -rw-r--r-- | src/lib/krb5/krb/preauth2.c | 267 | ||||
| -rw-r--r-- | src/lib/krb5/os/init_os_ctx.c | 5 |
4 files changed, 153 insertions, 150 deletions
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 8d75c60c37..947984f62a 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -774,6 +774,7 @@ sort_krb5_padata_sequence(krb5_context context, krb5_data *realm, long l; char *q, *preauth_types = NULL; krb5_pa_data *tmp; + int need_free_string = 1; if ((padata == NULL) || (padata[0] == NULL)) { return 0; @@ -784,6 +785,7 @@ sort_krb5_padata_sequence(krb5_context context, krb5_data *realm, if ((ret != 0) || (preauth_types == NULL)) { /* Try to use PKINIT first. */ preauth_types = "17, 16, 15, 14"; + need_free_string = 0; } #ifdef DEBUG @@ -820,6 +822,8 @@ sort_krb5_padata_sequence(krb5_context context, krb5_data *realm, } } } + if (need_free_string) + free(preauth_types); #ifdef DEBUG fprintf (stderr, "preauth data types after sorting:"); @@ -861,7 +865,6 @@ krb5_get_init_creds(krb5_context context, krb5_kdc_rep *local_as_reply; krb5_timestamp time_now; krb5_enctype etype = 0; - krb5_preauth_context *preauth_context; /* initialize everything which will be freed at cleanup */ @@ -881,7 +884,6 @@ krb5_get_init_creds(krb5_context context, local_as_reply = 0; - preauth_context = NULL; err_reply = NULL; /* @@ -1017,7 +1019,7 @@ krb5_get_init_creds(krb5_context context, goto cleanup; } - krb5_init_preauth_context(context, &preauth_context); + krb5_preauth_request_context_init(context); /* nonce is filled in by send_as_request if we don't take care of it */ @@ -1084,7 +1086,7 @@ krb5_get_init_creds(krb5_context context, request.nonce = (krb5_int32) time_now; /* give the preauth plugins a chance to prep the request body */ - krb5_preauth_prepare_request(context, &preauth_context, options, &request); + krb5_preauth_prepare_request(context, options, &request); ret = encode_krb5_kdc_req_body(&request, &encoded_request_body); if (ret) goto cleanup; @@ -1097,7 +1099,7 @@ krb5_get_init_creds(krb5_context context, krb5_free_pa_data(context, request.padata); request.padata = NULL; } - if ((ret = krb5_do_preauth(context, &preauth_context, + if ((ret = krb5_do_preauth(context, &request, encoded_request_body, encoded_previous_request, @@ -1109,14 +1111,13 @@ krb5_get_init_creds(krb5_context context, } else { /* retrying after an error other than PREAUTH_NEEDED, using e-data * to figure out what to change */ - if (krb5_do_preauth_tryagain(context, &preauth_context, + if (krb5_do_preauth_tryagain(context, &request, encoded_request_body, encoded_previous_request, - preauth_to_use, err_reply, - &request.padata, - &salt, &s2kparams, - &etype, &as_key, + preauth_to_use, + err_reply, + &salt, &s2kparams, &etype, &as_key, prompter, prompter_data, gak_fct, gak_data)) { /* couldn't come up with anything better */ @@ -1188,11 +1189,11 @@ krb5_get_init_creds(krb5_context context, } /* process any preauth data in the as_reply */ - krb5_clear_preauth_context_use_counts(context, preauth_context); + krb5_clear_preauth_context_use_counts(context); if ((ret = sort_krb5_padata_sequence(context, &request.server->realm, local_as_reply->padata))) goto cleanup; - if ((ret = krb5_do_preauth(context, &preauth_context, + if ((ret = krb5_do_preauth(context, &request, encoded_request_body, encoded_previous_request, local_as_reply->padata, &kdc_padata, @@ -1252,10 +1253,7 @@ krb5_get_init_creds(krb5_context context, ret = 0; cleanup: - if (preauth_context != NULL) { - krb5_free_preauth_context(context, preauth_context); - preauth_context = NULL; - } + krb5_preauth_request_context_fini(context); if (encoded_previous_request != NULL) { krb5_free_data(context, encoded_previous_request); encoded_previous_request = NULL; diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c index 46c3068eee..5ce00169a3 100644 --- a/src/lib/krb5/krb/init_ctx.c +++ b/src/lib/krb5/krb/init_ctx.c @@ -535,6 +535,7 @@ krb5_copy_context(krb5_context ctx, krb5_context *nctx_out) nctx->os_context->default_ccname = NULL; memset(&nctx->preauth_plugins, 0, sizeof(nctx->preauth_plugins)); + nctx->preauth_context = NULL; memset(&nctx->libkrb5_plugins, 0, sizeof(nctx->libkrb5_plugins)); nctx->vtbl = NULL; diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index ce2bf68834..64823732fb 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -59,76 +59,25 @@ typedef struct _pa_types_t { int flags; } pa_types_t; -/* 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. */ -struct _krb5_preauth_context { - int n_modules; - struct _krb5_preauth_context_module { - /* 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 module's per-module context and a function to clear it. */ - void *module_context; - void (*client_fini)(krb5_context context, krb5_preauthtype pa_type, - void *module_context); - /* The module's table, and some of its members, copied here for - * convenience when we populated the list. */ - struct krb5plugin_preauth_client_ftable_v0 *ftable; - const char *name; - int flags, use_count; - krb5_error_code (*client_process)(krb5_context context, - void *module_context, - void **request_context, - krb5_kdc_req *request, - krb5_data *encoded_request_body, - krb5_data *encoded_previous_request, - krb5_pa_data *pa_data, - krb5_prompter_fct prompter, - void *prompter_data, - preauth_get_as_key_proc gak_fct, - krb5_data *salt, - krb5_data *s2kparams, - void *gak_data, - krb5_keyblock *as_key, - krb5_pa_data **out_pa_data); - krb5_error_code (*client_tryagain)(krb5_context context, - void *module_context, - void **request_context, - krb5_kdc_req *request, - krb5_data *encoded_request_body, - krb5_error *err_reply, - krb5_pa_data *old_pa_data, - krb5_pa_data **new_pa_data); - void (*client_cleanup)(krb5_context context, void *module_context, - void **request_context); - /* The per-pa_type context which the client_process() function - * might allocate, which we'll need to clean up later by - * calling the client_cleanup() function. */ - void *request_context; - } *modules; -}; - -/* Create the per-AS-REQ 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. */ +/* 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. */ void -krb5_init_preauth_context(krb5_context kcontext, - krb5_preauth_context **preauth_context) +krb5_init_preauth_context(krb5_context kcontext) { int n_modules, n_tables, i, j, k; void **tables; struct krb5plugin_preauth_client_ftable_v0 *table; - krb5_preauth_context *context; - void *module_context; + krb5_preauth_context *context = NULL; + void *plugin_context; krb5_preauthtype pa_type; + /* Only do this once for each krb5_context */ + if (kcontext->preauth_context != NULL) + return; + /* load the plugins for the current context */ if (PLUGIN_DIR_OPEN(&kcontext->preauth_plugins) == 0) { if (krb5int_open_plugin_dirs(objdirs, NULL, @@ -167,10 +116,12 @@ krb5_init_preauth_context(krb5_context kcontext, /* allocate the space we need */ context = malloc(sizeof(*context)); if (context == NULL) { + krb5int_free_plugin_dir_data(tables); return; } context->modules = malloc(sizeof(context->modules[0]) * n_modules); if (context->modules == NULL) { + krb5int_free_plugin_dir_data(tables); free(context); return; } @@ -182,28 +133,40 @@ krb5_init_preauth_context(krb5_context kcontext, for (i = 0; i < n_tables; i++) { table = tables[i]; if ((table->pa_type_list != NULL) && (table->process != NULL)) { - for (j = 0; table->pa_type_list[j] > 0; j++) { - pa_type = table->pa_type_list[j]; - module_context = NULL; - if ((table->init != NULL) && - ((*table->init)(kcontext, pa_type, &module_context) != 0)) { + plugin_context = NULL; + if ((table->init != NULL) && + ((*table->init)(kcontext, &plugin_context) != 0)) { #ifdef DEBUG - fprintf (stderr, "skip module \"%s\", pa_type %d\n", - table->name, pa_type); + fprintf (stderr, "init err, skipping module \"%s\"\n", + table->name); #endif - continue; - } + continue; + } + + for (j = 0; table->pa_type_list[j] > 0; j++) { + pa_type = table->pa_type_list[j]; context->modules[k].pa_type = pa_type; context->modules[k].enctypes = table->enctype_list; - context->modules[k].module_context = module_context; - context->modules[k].client_fini = table->fini; + context->modules[k].plugin_context = plugin_context; + /* Only call client_fini once per plugin */ + if (j == 0) + context->modules[k].client_fini = table->fini; + else + context->modules[k].client_fini = NULL; context->modules[k].ftable = table; context->modules[k].name = table->name; context->modules[k].flags = (*table->flags)(kcontext, pa_type); context->modules[k].use_count = 0; context->modules[k].client_process = table->process; context->modules[k].client_tryagain = table->tryagain; - context->modules[k].client_cleanup = table->cleanup; + /* Only call request_init and request_fini once per plugin */ + if (j == 0) { + context->modules[k].client_req_init = table->request_init; + context->modules[k].client_req_fini = table->request_fini; + } else { + context->modules[k].client_req_init = NULL; + context->modules[k].client_req_fini = NULL; + } context->modules[k].request_context = NULL; #ifdef DEBUG fprintf (stderr, "init module \"%s\", pa_type %d, flag %d\n", @@ -215,60 +178,92 @@ krb5_init_preauth_context(krb5_context kcontext, } } } + krb5int_free_plugin_dir_data(tables); /* return the result */ - *preauth_context = context; + kcontext->preauth_context = context; } /* Zero the use counts for the modules herein. Usually used before we * start processing any data from the server, at which point every module * will again be able to take a crack at whatever the server sent. */ void -krb5_clear_preauth_context_use_counts(krb5_context context, - krb5_preauth_context *preauth_context) +krb5_clear_preauth_context_use_counts(krb5_context context) { int i; - if (preauth_context != NULL) { - for (i = 0; i < preauth_context->n_modules; i++) { - preauth_context->modules[i].use_count = 0; + if (context->preauth_context != NULL) { + for (i = 0; i < context->preauth_context->n_modules; i++) { + context->preauth_context->modules[i].use_count = 0; } } } -/* Free the per-AS-REQ context. This means clearing any module-specific or - * request-specific context which the modules may have created, and then +/* Free the per-krb5_context preauth_context. This means clearing any + * plugin-specific context which may have been created, and then * freeing the context itself. */ void -krb5_free_preauth_context(krb5_context context, - krb5_preauth_context *preauth_context) +krb5_free_preauth_context(krb5_context context) { int i; - krb5_preauthtype pa_type; - void **rctx, *mctx; - if (preauth_context != NULL) { - for (i = 0; i < preauth_context->n_modules; i++) { - mctx = preauth_context->modules[i].module_context; - if (preauth_context->modules[i].request_context != NULL) { - if (preauth_context->modules[i].client_cleanup != NULL) { - rctx = &preauth_context->modules[i].request_context; - preauth_context->modules[i].client_cleanup(context, - mctx, rctx); - } - preauth_context->modules[i].request_context = NULL; + void *pctx; + if (context->preauth_context != NULL) { + for (i = 0; i < context->preauth_context->n_modules; i++) { + pctx = context->preauth_context->modules[i].plugin_context; + if (context->preauth_context->modules[i].client_fini != NULL) { + (*context->preauth_context->modules[i].client_fini)(context, pctx); } - if (preauth_context->modules[i].client_fini != NULL) { - pa_type = preauth_context->modules[i].pa_type; - (*preauth_context->modules[i].client_fini)(context, pa_type, - mctx); + memset(&context->preauth_context->modules[i], 0, + sizeof(context->preauth_context->modules[i])); + } + if (context->preauth_context->modules != NULL) { + free(context->preauth_context->modules); + context->preauth_context->modules = NULL; + } + free(context->preauth_context); + context->preauth_context = NULL; + } +} + +/* Initialize the per-AS-REQ context. This means calling the client_req_init + * function to give the plugin a chance to allocate a per-request context. */ +void +krb5_preauth_request_context_init(krb5_context context) +{ + int i; + void *rctx, *pctx; + + /* Limit this to only one attempt per context? */ + if (context->preauth_context == NULL) + krb5_init_preauth_context(context); + if (context->preauth_context != NULL) { + for (i = 0; i < context->preauth_context->n_modules; i++) { + pctx = context->preauth_context->modules[i].plugin_context; + if (context->preauth_context->modules[i].client_req_init != NULL) { + rctx = &context->preauth_context->modules[i].request_context; + (*context->preauth_context->modules[i].client_req_init) (context, pctx, rctx); } - memset(&preauth_context->modules[i], 0, - sizeof(preauth_context->modules[i])); } - if (preauth_context->modules != NULL) { - free(preauth_context->modules); - preauth_context->modules = NULL; + } +} + +/* Free the per-AS-REQ context. This means clearing any request-specific + * context which the plugin may have created. */ +void +krb5_preauth_request_context_fini(krb5_context context) +{ + int i; + void *rctx, *pctx; + if (context->preauth_context != NULL) { + for (i = 0; i < context->preauth_context->n_modules; i++) { + pctx = context->preauth_context->modules[i].plugin_context; + rctx = context->preauth_context->modules[i].request_context; + if (rctx != NULL) { + if (context->preauth_context->modules[i].client_req_fini != NULL) { + (*context->preauth_context->modules[i].client_req_fini)(context, pctx, rctx); + } + context->preauth_context->modules[i].request_context = NULL; + } } - free(preauth_context); } } @@ -337,24 +332,23 @@ grow_pa_list(krb5_pa_data ***out_pa_list, int *out_pa_list_size, * involved things. */ void krb5_preauth_prepare_request(krb5_context kcontext, - krb5_preauth_context **preauth_context, krb5_get_init_creds_opt *options, krb5_kdc_req *request) { int i, j; - if ((preauth_context == NULL) || (*preauth_context == NULL)) { + if (kcontext->preauth_context == NULL) { return; } /* Add the module-specific enctype list to the request, but only if * it's something we can safely modify. */ if (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))) { - for (i = 0; i < (*preauth_context)->n_modules; i++) { - if ((*preauth_context)->modules[i].enctypes == NULL) + for (i = 0; i < kcontext->preauth_context->n_modules; i++) { + if (kcontext->preauth_context->modules[i].enctypes == NULL) continue; - for (j = 0; (*preauth_context)->modules[i].enctypes[j] != 0; j++) { + for (j = 0; kcontext->preauth_context->modules[i].enctypes[j] != 0; j++) { grow_ktypes(&request->ktype, &request->nktypes, - (*preauth_context)->modules[i].enctypes[j]); + kcontext->preauth_context->modules[i].enctypes[j]); } } } @@ -365,7 +359,6 @@ krb5_preauth_prepare_request(krb5_context kcontext, * they don't generate preauth data), and run it. */ static krb5_error_code krb5_run_preauth_plugins(krb5_context kcontext, - krb5_preauth_context *preauth_context, int module_required_flags, krb5_kdc_req *request, krb5_data *encoded_request_body, @@ -388,12 +381,12 @@ krb5_run_preauth_plugins(krb5_context kcontext, krb5_error_code ret; struct _krb5_preauth_context_module *module; - if (preauth_context == NULL) { + if (kcontext->preauth_context == NULL) { return ENOENT; } /* iterate over all loaded modules */ - for (i = 0; i < preauth_context->n_modules; i++) { - module = &preauth_context->modules[i]; + 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; @@ -418,14 +411,14 @@ krb5_run_preauth_plugins(krb5_context kcontext, module->name, module->pa_type, module->flags); #endif ret = module->client_process(kcontext, - module->module_context, - &module->request_context, + module->plugin_context, + module->request_context, request, encoded_request_body, encoded_previous_request, in_padata, prompter, prompter_data, - gak_fct, salt, s2kparams, gak_data, + gak_fct, gak_data, salt, s2kparams, as_key, &out_pa_data); /* Make note of the module's flags and status. */ @@ -439,7 +432,7 @@ krb5_run_preauth_plugins(krb5_context kcontext, } break; } - if (i >= preauth_context->n_modules) { + if (i >= kcontext->preauth_context->n_modules) { return ENOENT; } return 0; @@ -1219,10 +1212,16 @@ static const pa_types_t pa_types[] = { */ krb5_error_code krb5_do_preauth_tryagain(krb5_context kcontext, - krb5_preauth_context **preauth_context, krb5_kdc_req *request, krb5_data *encoded_request_body, - krb5_error *err_reply, krb5_pa_data **padata) + krb5_data *encoded_previous_request, + krb5_pa_data **padata, + krb5_error *err_reply, + krb5_data *salt, krb5_data *s2kparams, + krb5_enctype *etype, + krb5_keyblock *as_key, + krb5_prompter_fct prompter, void *prompter_data, + krb5_gic_get_as_key_fct gak_fct, void *gak_data) { krb5_error_code ret; krb5_pa_data *out_padata; @@ -1231,10 +1230,10 @@ krb5_do_preauth_tryagain(krb5_context kcontext, int i, j; ret = KRB_ERR_GENERIC; - if (preauth_context == NULL) { + if (kcontext->preauth_context == NULL) { return KRB_ERR_GENERIC; } - context = *preauth_context; + context = kcontext->preauth_context; if (context == NULL) { return KRB_ERR_GENERIC; } @@ -1250,12 +1249,16 @@ krb5_do_preauth_tryagain(krb5_context kcontext, continue; } if ((*module->client_tryagain)(kcontext, - module->module_context, + module->plugin_context, module->request_context, request, encoded_request_body, - err_reply, + encoded_previous_request, padata[i], + err_reply, + prompter, prompter_data, + gak_fct, gak_data, salt, s2kparams, + as_key, &out_padata) == 0) { if (out_padata != NULL) { if (padata[i]->contents != NULL) @@ -1272,7 +1275,6 @@ krb5_do_preauth_tryagain(krb5_context kcontext, krb5_error_code krb5_do_preauth(krb5_context context, - krb5_preauth_context **preauth_context, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, @@ -1450,18 +1452,15 @@ krb5_do_preauth(krb5_context context, } /* Try to use plugins now. */ - if ((!realdone) && (preauth_context != NULL)) { - if (*preauth_context == NULL) { - krb5_init_preauth_context(context, preauth_context); - } - if (*preauth_context != NULL) { + if (!realdone) { + krb5_init_preauth_context(context); + if (context->preauth_context != NULL) { int module_ret, module_flags; #ifdef DEBUG fprintf (stderr, "trying modules for pa_type %d, flag %d\n", in_padata[i]->pa_type, paorder[h]); #endif ret = krb5_run_preauth_plugins(context, - *preauth_context, paorder[h], request, encoded_request_body, diff --git a/src/lib/krb5/os/init_os_ctx.c b/src/lib/krb5/os/init_os_ctx.c index bc7e007ff7..b3d8dcf8c5 100644 --- a/src/lib/krb5/os/init_os_ctx.c +++ b/src/lib/krb5/os/init_os_ctx.c @@ -392,6 +392,7 @@ krb5_os_init_context(krb5_context ctx, krb5_boolean kdc) ctx->vtbl = 0; PLUGIN_DIR_INIT(&ctx->libkrb5_plugins); PLUGIN_DIR_INIT(&ctx->preauth_plugins); + ctx->preauth_context = NULL; retval = os_init_paths(ctx, kdc); /* @@ -493,6 +494,10 @@ krb5_os_free_context(krb5_context ctx) ctx->profile = 0; } + if (ctx->preauth_context) { + krb5_free_preauth_context(ctx); + ctx->preauth_context = NULL; + } krb5int_close_plugin_dirs (&ctx->preauth_plugins); krb5int_close_plugin_dirs (&ctx->libkrb5_plugins); |
