From 2b2f711f2addee052253e4ff54fb7cdf3e20c0ae Mon Sep 17 00:00:00 2001 From: Kevin Coffman Date: Wed, 1 Nov 2006 22:40:30 +0000 Subject: 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 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 --- src/include/k5-int.h | 113 +++++- src/include/krb5/preauth_plugin.h | 56 ++- src/kdc/kdc_preauth.c | 98 ++--- src/lib/krb5/krb/get_in_tkt.c | 30 +- src/lib/krb5/krb/init_ctx.c | 1 + src/lib/krb5/krb/preauth2.c | 267 ++++++------ src/lib/krb5/os/init_os_ctx.c | 5 + src/plugins/preauth/cksum_body/Makefile.in | 6 +- src/plugins/preauth/cksum_body/cksum_body_main.c | 492 ++++++++++++++++++++++ src/plugins/preauth/cksum_body/src/cksum_body.c | 493 ----------------------- src/plugins/preauth/wpse/Makefile.in | 6 +- src/plugins/preauth/wpse/src/wpse.c | 341 ---------------- src/plugins/preauth/wpse/wpse_main.c | 374 +++++++++++++++++ 13 files changed, 1209 insertions(+), 1073 deletions(-) create mode 100644 src/plugins/preauth/cksum_body/cksum_body_main.c delete mode 100644 src/plugins/preauth/cksum_body/src/cksum_body.c delete mode 100644 src/plugins/preauth/wpse/src/wpse.c create mode 100644 src/plugins/preauth/wpse/wpse_main.c diff --git a/src/include/k5-int.h b/src/include/k5-int.h index f659e2e1e..884bd23c8 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -552,9 +552,6 @@ krb5int_locate_server (krb5_context, const krb5_data *realm, #endif /* KRB5_LIBOS_PROTO__ */ -#include -typedef struct _krb5_preauth_context krb5_preauth_context; - /* new encryption provider api */ struct krb5_enc_provider { @@ -844,6 +841,71 @@ error(MIT_DES_KEYSIZE does not equal KRB5_MIT_DES_KEYSIZE) #ifndef KRB5_PREAUTH__ #define KRB5_PREAUTH__ +#include + +/* 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 _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 plugin's per-plugin context and a function to clear it. */ + void *plugin_context; + void (*client_fini)(krb5_context context, void *plugin_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 *plugin_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, + void *gak_data, + krb5_data *salt, + krb5_data *s2kparams, + krb5_keyblock *as_key, + krb5_pa_data **out_pa_data); + krb5_error_code (*client_tryagain)(krb5_context context, + void *plugin_context, + void *request_context, + krb5_kdc_req *request, + krb5_data *encoded_request_body, + krb5_data *encoded_previous_request, + krb5_pa_data *old_pa_data, + krb5_error *err_reply, + krb5_prompter_fct prompter, + void *prompter_data, + preauth_get_as_key_proc gak_fct, + void *gak_data, + krb5_data *salt, + krb5_data *s2kparams, + krb5_keyblock *as_key, + krb5_pa_data **new_pa_data); + void (*client_req_init)(krb5_context context, void *plugin_context, + void **request_context); + void (*client_req_fini)(krb5_context context, void *plugin_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; +} krb5_preauth_context; + typedef struct _krb5_pa_enc_ts { krb5_timestamp patimestamp; krb5_int32 pausec; @@ -970,23 +1032,39 @@ void krb5int_populate_gic_opt ( krb5_preauthtype *pre_auth_types, krb5_creds *creds); -krb5_error_code krb5_do_preauth -(krb5_context, krb5_preauth_context **, krb5_kdc_req *, krb5_data *, - krb5_data *, krb5_pa_data **, krb5_pa_data ***, - krb5_data *salt, krb5_data *s2kparams, - krb5_enctype *, - krb5_keyblock *, - krb5_prompter_fct, void *, - krb5_gic_get_as_key_fct, void *); +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_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 KRB5_CALLCONV krb5_do_preauth_tryagain + (krb5_context context, + krb5_kdc_req *request, + krb5_data *encoded_request_body, + krb5_data *encoded_previous_request, + krb5_pa_data **in_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); void KRB5_CALLCONV krb5_init_preauth_context - (krb5_context, krb5_preauth_context **); + (krb5_context); +void KRB5_CALLCONV krb5_free_preauth_context + (krb5_context); void KRB5_CALLCONV krb5_clear_preauth_context_use_counts - (krb5_context, krb5_preauth_context *); + (krb5_context); void KRB5_CALLCONV krb5_preauth_prepare_request - (krb5_context, krb5_preauth_context **, - krb5_get_init_creds_opt *, krb5_kdc_req *); -void KRB5_CALLCONV krb5_free_preauth_context - (krb5_context, krb5_preauth_context *); + (krb5_context, krb5_get_init_creds_opt *, krb5_kdc_req *); +void KRB5_CALLCONV krb5_preauth_request_context_init + (krb5_context); +void KRB5_CALLCONV krb5_preauth_request_context_fini + (krb5_context); void KRB5_CALLCONV krb5_free_sam_challenge (krb5_context, krb5_sam_challenge * ); @@ -1079,6 +1157,7 @@ struct _krb5_context { /* preauth module stuff */ struct plugin_dir_handle preauth_plugins; + krb5_preauth_context *preauth_context; /* error detail info */ struct errinfo err; diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h index 63600fead..d164192af 100644 --- a/src/include/krb5/preauth_plugin.h +++ b/src/include/krb5/preauth_plugin.h @@ -157,20 +157,27 @@ typedef struct krb5plugin_preauth_client_ftable_v0 { * to add support for. */ krb5_enctype *enctype_list; - /* Per-module initialization/cleanup. The init function is called - * by libkrb5 when the module is loaded, and the fini function is - * called before the module is unloaded. Both are optional and - * may be called multiple times in case the module is used in - * multiple contexts.*/ - krb5_error_code (*init)(krb5_context, krb5_preauthtype, void **); - void (*fini)(krb5_context, krb5_preauthtype, void *); + /* Per-plugin initialization/cleanup. The init function is called + * by libkrb5 when the plugin is loaded, and the fini function is + * called before the plugin is unloaded. Both are optional and + * may be called multiple times in case the plugin is used in + * multiple contexts. The returned context lives the lifetime of + * the krb5_context */ + krb5_error_code (*init)(krb5_context context, void **plugin_context); + void (*fini)(krb5_context context, void *plugin_context); /* A callback which returns flags indicating if the module is a "real" or * an "info" mechanism, and so on. This function is called for each entry * in the client_pa_type_list. */ - int (*flags)(krb5_context, krb5_preauthtype); - /* Clean up a client context. Can be NULL. */ - void (*cleanup)(krb5_context context, void *module_context, + int (*flags)(krb5_context context, krb5_preauthtype pa_type); + /* Per-request initialization/cleanup. The request_init function is + * called when beginning to process a get_init_creds request and the + * request_fini function is called when processing of the request is + * complete. This is optional. It may be called multiple times in + * the lifetime of a krb5_context. */ + void (*request_init)(krb5_context context, void *plugin_context, void **request_context); + void (*request_fini)(krb5_context context, void *plugin_context, + void *request_context); /* Client function which processes server-supplied data in pa_data, * returns created data in out_pa_data, storing any of its own state in * client_context if data for the associated preauthentication type is @@ -180,8 +187,8 @@ typedef struct krb5plugin_preauth_client_ftable_v0 { * function is called, because it is expected to only ever contain the data * obtained from a previous call to this function. */ krb5_error_code (*process)(krb5_context context, - void *module_context, - void **request_context, + void *plugin_context, + void *request_context, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, @@ -189,8 +196,8 @@ typedef struct krb5plugin_preauth_client_ftable_v0 { krb5_prompter_fct prompter, void *prompter_data, preauth_get_as_key_proc gak_fct, - krb5_data *salt, krb5_data *s2kparams, void *gak_data, + krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, krb5_pa_data **out_pa_data); /* Client function which can attempt to use e-data in the error response to @@ -198,12 +205,19 @@ typedef struct krb5plugin_preauth_client_ftable_v0 { * it stores data in out_pa_data which is different data from the contents * of in_pa_data, then the client library will retransmit the request. */ krb5_error_code (*tryagain)(krb5_context context, - void *module_context, - void **request_context, + void *plugin_context, + void *request_context, krb5_kdc_req *request, krb5_data *encoded_request_body, - krb5_error *error, + krb5_data *encoded_previous_request, krb5_pa_data *in_pa_data, + krb5_error *error, + krb5_prompter_fct prompter, + void *prompter_data, + preauth_get_as_key_proc gak_fct, + void *gak_data, + krb5_data *salt, krb5_data *s2kparams, + krb5_keyblock *as_key, krb5_pa_data **out_pa_data); } krb5plugin_preauth_client_ftable_v0; @@ -223,11 +237,11 @@ typedef struct krb5plugin_preauth_server_ftable_v0 { * provide services for. */ krb5_preauthtype *pa_type_list; - /* Per-module initialization/cleanup. The init function is called by the - * KDC when the module is loaded, and the fini function is called before - * the module is unloaded. Both are optional. */ - krb5_error_code (*init_proc)(krb5_context, krb5_preauthtype, void **); - void (*fini_proc)(krb5_context, krb5_preauthtype, void *); + /* Per-plugin initialization/cleanup. The init function is called by the + * KDC when the plugin is loaded, and the fini function is called before + * the plugin is unloaded. Both are optional. */ + krb5_error_code (*init_proc)(krb5_context, void **); + void (*fini_proc)(krb5_context, void *); /* Return the flags which the KDC should use for this module. This is a * callback instead of a static value because the module may or may not * wish to count itself as a hardware preauthentication module (in other diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 16af527a6..dfbb5fcc9 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -109,15 +109,15 @@ typedef krb5_error_code (*freepa_proc) (krb5_context, void *pa_module_context, void **pa_request_context); typedef krb5_error_code (*init_proc) - (krb5_context, krb5_preauthtype, void **); + (krb5_context, void **); typedef void (*fini_proc) - (krb5_context, krb5_preauthtype, void *); + (krb5_context, void *); typedef struct _krb5_preauth_systems { const char *name; int type; int flags; - void *pa_sys_context; + void *plugin_context; init_proc init; fini_proc fini; edata_proc get_edata; @@ -301,8 +301,7 @@ load_preauth_plugins(krb5_context context) void **preauth_plugins_ftables; struct krb5plugin_preauth_server_ftable_v0 *ftable; int module_count, i, j, k; - krb5_preauthtype pa_type; - void *pa_sys_context; + void *plugin_context; init_proc server_init_proc; memset(&err, 0, sizeof(err)); @@ -349,6 +348,7 @@ load_preauth_plugins(krb5_context context) * leave room for a terminator entry. */ preauth_systems = malloc(sizeof(krb5_preauth_systems) * (module_count + 1)); if (preauth_systems == NULL) { + krb5int_free_plugin_dir_data(preauth_plugins_ftables); return ENOMEM; } @@ -361,15 +361,14 @@ load_preauth_plugins(krb5_context context) preauth_systems[k] = static_preauth_systems[i]; /* Try to initialize the preauth system. If it fails, we'll remove it * from the list of systems we'll be using. */ - pa_sys_context = NULL; - pa_type = static_preauth_systems[i].type; + plugin_context = NULL; server_init_proc = static_preauth_systems[i].init; if ((server_init_proc != NULL) && - ((*server_init_proc)(context, pa_type, &pa_sys_context) != 0)) { + ((*server_init_proc)(context, &plugin_context) != 0)) { memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); continue; } - preauth_systems[k].pa_sys_context = pa_sys_context; + preauth_systems[k].plugin_context = plugin_context; k++; } @@ -383,28 +382,34 @@ load_preauth_plugins(krb5_context context) (ftable->return_proc == NULL)) { continue; } + plugin_context = NULL; for (j = 0; ftable->pa_type_list != NULL && ftable->pa_type_list[j] > 0; j++) { - /* Try to initialize the module. If it fails, we'll remove it + /* Try to initialize the plugin. If it fails, we'll remove it * from the list of modules we'll be using. */ - pa_sys_context = NULL; - server_init_proc = ftable->init_proc; - pa_type = ftable->pa_type_list[j]; - if ((server_init_proc != NULL) && - ((*server_init_proc)(context, pa_type, - &pa_sys_context) != 0)) { - memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); - continue; + if (j == 0) { + server_init_proc = ftable->init_proc; + if ((server_init_proc != NULL) && + ((*server_init_proc)(context, &plugin_context) != 0)) { + memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); + continue; + } } preauth_systems[k].name = ftable->name; - pa_type = ftable->pa_type_list[j]; - preauth_systems[k].type = pa_type; - preauth_systems[k].flags = ftable->flags_proc(context, pa_type); - preauth_systems[k].pa_sys_context = pa_sys_context; + preauth_systems[k].type = ftable->pa_type_list[j]; + if (ftable->flags_proc != NULL) + preauth_systems[k].flags = ftable->flags_proc(context, preauth_systems[k].type); + else + preauth_systems[k].flags = 0; + preauth_systems[k].plugin_context = plugin_context; preauth_systems[k].init = server_init_proc; - preauth_systems[k].fini = ftable->fini_proc; + /* Only call fini once for each plugin */ + if (j == 0) + preauth_systems[k].fini = ftable->fini_proc; + else + preauth_systems[k].fini = NULL; preauth_systems[k].get_edata = ftable->edata_proc; preauth_systems[k].verify_padata = ftable->verify_proc; preauth_systems[k].return_padata = ftable->return_proc; @@ -413,6 +418,7 @@ load_preauth_plugins(krb5_context context) k++; } } + krb5int_free_plugin_dir_data(preauth_plugins_ftables); } n_preauth_systems = k; /* Add the end-of-list marker. */ @@ -429,8 +435,7 @@ unload_preauth_plugins(krb5_context context) for (i = 0; i < n_preauth_systems; i++) { if (preauth_systems[i].fini != NULL) { (*preauth_systems[i].fini)(context, - preauth_systems[i].type, - preauth_systems[i].pa_sys_context); + preauth_systems[i].plugin_context); } memset(&preauth_systems[i], 0, sizeof(preauth_systems[i])); } @@ -506,7 +511,7 @@ free_padata_context(krb5_context kcontext, void **padata_context) for (i = 0; i < context->n_contexts; i++) { if (context->contexts[i].pa_context != NULL) { preauth_system = context->contexts[i].pa_system; - mctx = preauth_system->pa_sys_context; + mctx = preauth_system->plugin_context; if (preauth_system->free_pa_request_context != NULL) { pctx = &context->contexts[i].pa_context; (*preauth_system->free_pa_request_context)(kcontext, mctx, @@ -721,25 +726,28 @@ sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order) } } - /* Now sort just the modules which replace the key, placing those which - * handle the pa_data types provided by the client ahead of the others. */ - for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) { - continue; - } - n_key_replacers = i; - for (i = 0; i < n_key_replacers; i++) { - if (pa_list_includes(request->padata, - preauth_systems[pa_order[i]].type)) + if (request->padata != NULL) { + /* Now reorder the subset of modules which replace the key, + * bubbling those which handle pa_data types provided by the + * client ahead of the others. */ + for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) { continue; - for (j = i + 1; j < n_key_replacers; j++) { + } + n_key_replacers = i; + for (i = 0; i < n_key_replacers; i++) { if (pa_list_includes(request->padata, - preauth_systems[pa_order[j]].type)) { - k = pa_order[j]; - pa_order[j] = pa_order[i]; - pa_order[i] = k; - break; + preauth_systems[pa_order[i]].type)) + continue; + for (j = i + 1; j < n_key_replacers; j++) { + if (pa_list_includes(request->padata, + preauth_systems[pa_order[j]].type)) { + k = pa_order[j]; + pa_order[j] = pa_order[i]; + pa_order[i] = k; + break; + } } - } + } } #ifdef DEBUG krb5_klog_syslog(LOG_DEBUG, "original preauth mechanism list:"); @@ -827,7 +835,7 @@ void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client, (*pa)->pa_type = ap->type; if (ap->get_edata) { retval = (ap->get_edata)(kdc_context, request, client, server, - get_entry_data, ap->pa_sys_context, *pa); + get_entry_data, ap->plugin_context, *pa); if (retval) { /* just failed on this type, continue */ free(*pa); @@ -899,7 +907,7 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, pa_found++; retval = pa_sys->verify_padata(context, client, req_pkt, request, enc_tkt_reply, *padata, - get_entry_data, pa_sys->pa_sys_context, + get_entry_data, pa_sys->plugin_context, pa_context); if (retval) { const char * emsg = krb5_get_error_message (context, retval); @@ -1046,7 +1054,7 @@ return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, } if ((retval = ap->return_padata(context, pa, client, req_pkt, request, reply, client_key, encrypting_key, send_pa, - get_entry_data, ap->pa_sys_context, + get_entry_data, ap->plugin_context, pa_context))) { goto cleanup; } diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 8d75c60c3..947984f62 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 46c3068ee..5ce00169a 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 ce2bf6883..64823732f 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 bc7e007ff..b3d8dcf8c 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); diff --git a/src/plugins/preauth/cksum_body/Makefile.in b/src/plugins/preauth/cksum_body/Makefile.in index ddac24dca..83d7cdb5b 100644 --- a/src/plugins/preauth/cksum_body/Makefile.in +++ b/src/plugins/preauth/cksum_body/Makefile.in @@ -9,7 +9,7 @@ PROG_RPATH=$(KRB5_LIBDIR) MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) DEFS=@DEFS@ -LOCALINCLUDES = -I../../../include/krb5 +LOCALINCLUDES = -I../../../include/krb5 -I. LIBBASE=cksum_body LIBMAJOR=0 @@ -25,9 +25,9 @@ SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS) SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) STOBJLISTS=OBJS.ST -STLIBOBJS=src/cksum_body.o +STLIBOBJS=cksum_body_main.o -SRCS= $(srcdir)/src/cksum_body.c +SRCS= $(srcdir)/cksum_body_main.c all-unix:: $(LIBBASE)$(SO_EXT) install-unix:: install-libs diff --git a/src/plugins/preauth/cksum_body/cksum_body_main.c b/src/plugins/preauth/cksum_body/cksum_body_main.c new file mode 100644 index 000000000..abf019a75 --- /dev/null +++ b/src/plugins/preauth/cksum_body/cksum_body_main.c @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2006 Red Hat, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Red Hat, Inc., nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Checksum the request body with the user's long-term key. + * + * The e-data from the KDC is a list of network-byte-order 32-bit integers + * listing key types which the KDC has for the user. + * + * The client uses one of these key types to generate a checksum over the body + * of the request, and includes the checksum in the AS-REQ as preauthentication + * data. + * + * The AS-REP carries no preauthentication data for this scheme. + */ + +#ident "$Id$" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include + +#include +#include + +/* This is not a standardized value. It's defined here only to make it easier + * to change in this module. */ +#define KRB5_PADATA_CKSUM_BODY_REQ 130 + +struct server_stats{ + int successes, failures; +}; + +static int +client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) +{ + return PA_REAL; +} + +static krb5_error_code +client_process(krb5_context kcontext, + void *client_plugin_context, + void *client_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, + void *gak_data, + krb5_data *salt, krb5_data *s2kparams, + krb5_keyblock *as_key, + krb5_pa_data **out_pa_data) +{ + krb5_pa_data *send_pa; + krb5_checksum checksum; + krb5_enctype enctype; + krb5_cksumtype *cksumtypes; + krb5_error_code status = 0; + krb5_int32 cksumtype, *enctypes; + unsigned int i, n_enctypes, cksumtype_count; + + memset(&checksum, 0, sizeof(checksum)); + + /* Get the user's long-term key if we haven't asked for it yet. Try + * all of the encryption types which the server supports. */ + if (as_key->length == 0) { + if ((pa_data != NULL) && (pa_data->length >= 4)) { +#ifdef DEBUG + fprintf(stderr, "%d bytes of preauth data.\n", pa_data->length); +#endif + n_enctypes = pa_data->length / 4; + enctypes = (krb5_int32*) pa_data->contents; + } else { + n_enctypes = request->nktypes; + } + for (i = 0; i < n_enctypes; i++) { + if ((pa_data != NULL) && (pa_data->length >= 4)) { + memcpy(&enctype, pa_data->contents + 4 * i, 4); + enctype = ntohl(enctype); + } else { + enctype = request->ktype[i]; + } +#ifdef DEBUG + fprintf(stderr, "Asking for AS key (type = %d).\n", enctype); +#endif + status = (*gak_fct)(kcontext, request->client, enctype, + prompter, prompter_data, + salt, s2kparams, as_key, gak_data); + if (status == 0) + break; + } + if (status != 0) + return status; + } +#ifdef DEBUG + fprintf(stderr, "Got AS key (type = %d).\n", as_key->enctype); +#endif + + /* Determine an appropriate checksum type for this key. */ + cksumtype_count = 0; + cksumtypes = NULL; + status = krb5_c_keyed_checksum_types(kcontext, as_key->enctype, + &cksumtype_count, &cksumtypes); + if (status != 0) + return status; + + /* Generate the checksum. */ + for (i = 0; i < cksumtype_count; i++) { + status = krb5_c_make_checksum(kcontext, cksumtypes[i], as_key, + KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, + encoded_request_body, + &checksum); + if (status == 0) { +#ifdef DEBUG + fprintf(stderr, "Made checksum (type = %d, %d bytes).\n", + checksum.checksum_type, encoded_request_body->length); +#endif + break; + } + } + cksumtype = htonl(cksumtypes[i]); + krb5_free_cksumtypes(kcontext, cksumtypes); + if (status != 0) { + if (checksum.length > 0) + krb5_free_checksum_contents(kcontext, &checksum); + return status; + } + + /* Allocate the preauth data structure. */ + send_pa = malloc(sizeof(krb5_pa_data)); + if (send_pa == NULL) { + krb5_free_checksum_contents(kcontext, &checksum); + return ENOMEM; + } + send_pa->pa_type = KRB5_PADATA_CKSUM_BODY_REQ; + send_pa->length = 4 + checksum.length; + send_pa->contents = malloc(4 + checksum.length); + if (send_pa->contents == NULL) { + krb5_free_checksum_contents(kcontext, &checksum); + free(send_pa); + return ENOMEM; + } + + /* Store the checksum. */ + memcpy(send_pa->contents, &cksumtype, 4); + memcpy(send_pa->contents + 4, checksum.contents, checksum.length); + *out_pa_data = send_pa; + + /* Clean up. */ + krb5_free_checksum_contents(kcontext, &checksum); + + return 0; +} + +/* Initialize and tear down the server-side module, and do stat tracking. */ +static krb5_error_code +server_init(krb5_context kcontext, void **module_context) +{ + struct server_stats *stats; + stats = malloc(sizeof(struct server_stats)); + if (stats == NULL) + return ENOMEM; + stats->successes = 0; + stats->failures = 0; + *module_context = stats; + return 0; +} +static void +server_fini(krb5_context kcontext, void *module_context) +{ + struct server_stats *stats; + stats = module_context; + if (stats != NULL) { +#ifdef DEBUG + fprintf(stderr, "Total: %d clients failed, %d succeeded.\n", + stats->failures, stats->successes); +#endif + free(stats); + } +} + +/* Obtain and return any preauthentication data (which is destined for the + * client) which matches type data->pa_type. */ +static krb5_error_code +server_get_edata(krb5_context kcontext, + krb5_kdc_req *request, + struct _krb5_db_entry_new *client, + struct _krb5_db_entry_new *server, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + krb5_pa_data *data) +{ + krb5_data *key_data; + krb5_keyblock *keys, *key; + krb5_int32 *enctypes, enctype; + int i; + + /* Retrieve the client's keys. */ + key_data = NULL; + if ((*server_get_entry_data)(kcontext, request, client, + krb5plugin_preauth_keys, &key_data) != 0) { +#ifdef DEBUG + fprintf(stderr, "Error retrieving client keys.\n"); +#endif + return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; + } + + /* Count which types of keys we've got, freeing the contents, which we + * don't need at this point. */ + keys = (krb5_keyblock *) key_data->data; + key = NULL; + for (i = 0; keys[i].enctype != 0; i++) + krb5_free_keyblock_contents(kcontext, &keys[i]); + + /* Return the list of encryption types. */ + enctypes = malloc((unsigned)i * 4); + if (enctypes == NULL) { + krb5_free_data(kcontext, key_data); + return ENOMEM; + } +#ifdef DEBUG + fprintf(stderr, "Supported enctypes = {"); +#endif + for (i = 0; keys[i].enctype != 0; i++) { +#ifdef DEBUG + fprintf(stderr, "%s%d", (i > 0) ? ", " : "", keys[i].enctype); +#endif + enctype = htonl(keys[i].enctype); + memcpy(&enctypes[i], &enctype, 4); + } +#ifdef DEBUG + fprintf(stderr, "}.\n"); +#endif + data->pa_type = KRB5_PADATA_CKSUM_BODY_REQ; + data->length = (i * 4); + data->contents = (unsigned char *) enctypes; + krb5_free_data(kcontext, key_data); + return 0; +} + +/* Verify a request from a client. */ +static krb5_error_code +server_verify(krb5_context kcontext, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply, + krb5_pa_data *data, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + void **pa_request_context) +{ + krb5_int32 cksumtype; + krb5_checksum checksum; + krb5_boolean valid; + krb5_data *key_data, *req_body; + krb5_keyblock *keys, *key; + size_t length; + int i; + unsigned int j, cksumtypes_count; + krb5_cksumtype *cksumtypes; + krb5_error_code status; + struct server_stats *stats; + + stats = pa_module_context; + + /* Verify the preauth data. Start with the checksum type. */ + if (data->length < 4) { + stats->failures++; + return KRB5KDC_ERR_PREAUTH_FAILED; + } + memcpy(&cksumtype, data->contents, 4); + memset(&checksum, 0, sizeof(checksum)); + checksum.checksum_type = ntohl(cksumtype); + + /* Verify that the amount of data we have left is what we expect. */ + if (krb5_c_checksum_length(kcontext, checksum.checksum_type, + &length) != 0) { +#ifdef DEBUG + fprintf(stderr, "Error determining checksum size (type = %d). " + "Is it supported?\n", checksum.checksum_type); +#endif + stats->failures++; + return KRB5KDC_ERR_SUMTYPE_NOSUPP; + } + if (data->length - 4 != length) { +#ifdef DEBUG + fprintf(stderr, "Checksum size doesn't match client packet size.\n"); +#endif + stats->failures++; + return KRB5KDC_ERR_PREAUTH_FAILED; + } + checksum.length = length; + + /* Pull up the client's keys. */ + key_data = NULL; + if ((*server_get_entry_data)(kcontext, request, client, + krb5plugin_preauth_keys, &key_data) != 0) { +#ifdef DEBUG + fprintf(stderr, "Error retrieving client keys.\n"); +#endif + stats->failures++; + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + /* Find the key which would have been used to generate the checksum. */ + keys = (krb5_keyblock *) key_data->data; + key = NULL; + for (i = 0; keys[i].enctype != 0; i++) { + key = &keys[i]; + cksumtypes_count = 0; + cksumtypes = NULL; + if (krb5_c_keyed_checksum_types(kcontext, key->enctype, + &cksumtypes_count, &cksumtypes) != 0) + continue; + for (j = 0; j < cksumtypes_count; j++) { + if (cksumtypes[j] == checksum.checksum_type) + break; + } + if (cksumtypes != NULL) + krb5_free_cksumtypes(kcontext, cksumtypes); + if (j < cksumtypes_count) { +#ifdef DEBUG + fprintf(stderr, "Found checksum key.\n"); +#endif + break; + } + } + if ((key == NULL) || (key->enctype == 0)) { + for (i = 0; keys[i].enctype != 0; i++) + krb5_free_keyblock_contents(kcontext, &keys[i]); + krb5_free_data(kcontext, key_data); + stats->failures++; + return KRB5KDC_ERR_SUMTYPE_NOSUPP; + } + + /* Save a copy of the key. */ + if (krb5_copy_keyblock(kcontext, &keys[i], &key) != 0) { + for (i = 0; keys[i].enctype != 0; i++) + krb5_free_keyblock_contents(kcontext, &keys[i]); + krb5_free_data(kcontext, key_data); + stats->failures++; + return KRB5KDC_ERR_SUMTYPE_NOSUPP; + } + for (i = 0; keys[i].enctype != 0; i++) + krb5_free_keyblock_contents(kcontext, &keys[i]); + krb5_free_data(kcontext, key_data); + + /* Rebuild a copy of the client's request-body. If we were serious + * about doing this with any chance of working interoperability, we'd + * extract the structure directly from the req_pkt structure. This + * will probably work if it's us on both ends, though. */ + req_body = NULL; + if ((*server_get_entry_data)(kcontext, request, client, + krb5plugin_preauth_request_body, + &req_body) != 0) { + krb5_free_keyblock(kcontext, key); + stats->failures++; + return KRB5KDC_ERR_PREAUTH_FAILED; + } + +#ifdef DEBUG + fprintf(stderr, "AS key type %d, checksum type %d, %d bytes.\n", + key->enctype, checksum.checksum_type, req_body->length); +#endif + + /* Verify the checksum itself. */ + checksum.contents = data->contents + 4; + valid = FALSE; + status = krb5_c_verify_checksum(kcontext, key, + KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, + req_body, &checksum, &valid); + + /* Clean up. */ + krb5_free_data(kcontext, req_body); + krb5_free_keyblock(kcontext, key); + + /* Evaluate our results. */ + if ((status != 0) || (!valid)) { +#ifdef DEBUG + if (status != 0) { + fprintf(stderr, "Error in checksum verification.\n"); + } else { + fprintf(stderr, "Checksum mismatch.\n"); + } +#endif + stats->failures++; + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + /* Note that preauthentication succeeded. */ + enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + stats->successes++; + return 0; +} + +/* Create the response for a client. */ +static krb5_error_code +server_return(krb5_context kcontext, + krb5_pa_data *padata, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_kdc_rep *reply, + struct _krb5_key_data *client_key, + krb5_keyblock *encrypting_key, + krb5_pa_data **send_pa, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + void **pa_request_context) +{ + /* We don't need to send data back on the return trip. */ + *send_pa = NULL; + return 0; +} + +static int +server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) +{ + return PA_SUFFICIENT; +} + +static krb5_preauthtype supported_client_pa_types[] = { + KRB5_PADATA_CKSUM_BODY_REQ, 0, +}; +static krb5_preauthtype supported_server_pa_types[] = { + KRB5_PADATA_CKSUM_BODY_REQ, 0, +}; + +struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = { + "cksum_body", /* name */ + &supported_client_pa_types[0], /* pa_type_list */ + NULL, /* enctype_list */ + NULL, /* plugin init function */ + NULL, /* plugin fini function */ + client_get_flags, /* get flags function */ + NULL, /* request init function */ + NULL, /* request fini function */ + client_process, /* process function */ + NULL, /* try_again function */ +}; + +struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = { + "cksum_body", + &supported_server_pa_types[0], + server_init, + server_fini, + server_get_flags, + server_get_edata, + server_verify, + server_return, + NULL +}; diff --git a/src/plugins/preauth/cksum_body/src/cksum_body.c b/src/plugins/preauth/cksum_body/src/cksum_body.c deleted file mode 100644 index 31ecaf839..000000000 --- a/src/plugins/preauth/cksum_body/src/cksum_body.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (C) 2006 Red Hat, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Red Hat, Inc., nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Checksum the request body with the user's long-term key. - * - * The e-data from the KDC is a list of network-byte-order 32-bit integers - * listing key types which the KDC has for the user. - * - * The client uses one of these key types to generate a checksum over the body - * of the request, and includes the checksum in the AS-REQ as preauthentication - * data. - * - * The AS-REP carries no preauthentication data for this scheme. - */ - -#ident "$Id$" - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include -#include - -#include -#include - -/* This is not a standardized value. It's defined here only to make it easier - * to change in this module. */ -#define KRB5_PADATA_CKSUM_BODY_REQ 130 - -struct server_stats{ - int successes, failures; -}; - -static int -client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) -{ - return PA_REAL; -} - -static krb5_error_code -client_process(krb5_context kcontext, - void *client_module_context, - void **client_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_pa_data *send_pa; - krb5_checksum checksum; - krb5_enctype enctype; - krb5_cksumtype *cksumtypes; - krb5_error_code status; - krb5_int32 cksumtype, *enctypes; - unsigned int i, n_enctypes, cksumtype_count; - - memset(&checksum, 0, sizeof(checksum)); - - /* Get the user's long-term key if we haven't asked for it yet. Try - * all of the encryption types which the server supports. */ - if (as_key->length == 0) { - if ((pa_data != NULL) && (pa_data->length >= 4)) { -#ifdef DEBUG - fprintf(stderr, "%d bytes of preauth data.\n", pa_data->length); -#endif - n_enctypes = pa_data->length / 4; - enctypes = (krb5_int32*) pa_data->contents; - } else { - n_enctypes = request->nktypes; - } - for (i = 0; i < n_enctypes; i++) { - if ((pa_data != NULL) && (pa_data->length >= 4)) { - memcpy(&enctype, pa_data->contents + 4 * i, 4); - enctype = ntohl(enctype); - } else { - enctype = request->ktype[i]; - } -#ifdef DEBUG - fprintf(stderr, "Asking for AS key (type = %d).\n", enctype); -#endif - status = (*gak_fct)(kcontext, request->client, enctype, - prompter, prompter_data, - salt, s2kparams, as_key, gak_data); - if (status == 0) - break; - } - if (status != 0) - return status; - } -#ifdef DEBUG - fprintf(stderr, "Got AS key (type = %d).\n", as_key->enctype); -#endif - - /* Determine an appropriate checksum type for this key. */ - cksumtype_count = 0; - cksumtypes = NULL; - status = krb5_c_keyed_checksum_types(kcontext, as_key->enctype, - &cksumtype_count, &cksumtypes); - if (status != 0) - return status; - - /* Generate the checksum. */ - for (i = 0; i < cksumtype_count; i++) { - status = krb5_c_make_checksum(kcontext, cksumtypes[i], as_key, - KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, - encoded_request_body, - &checksum); - if (status == 0) { -#ifdef DEBUG - fprintf(stderr, "Made checksum (type = %d, %d bytes).\n", - checksum.checksum_type, encoded_request_body->length); -#endif - break; - } - } - cksumtype = htonl(cksumtypes[i]); - krb5_free_cksumtypes(kcontext, cksumtypes); - if (status != 0) { - if (checksum.length > 0) - krb5_free_checksum_contents(kcontext, &checksum); - return status; - } - - /* Allocate the preauth data structure. */ - send_pa = malloc(sizeof(krb5_pa_data)); - if (send_pa == NULL) { - krb5_free_checksum_contents(kcontext, &checksum); - return ENOMEM; - } - send_pa->pa_type = KRB5_PADATA_CKSUM_BODY_REQ; - send_pa->length = 4 + checksum.length; - send_pa->contents = malloc(4 + checksum.length); - if (send_pa->contents == NULL) { - krb5_free_checksum_contents(kcontext, &checksum); - free(send_pa); - return ENOMEM; - } - - /* Store the checksum. */ - memcpy(send_pa->contents, &cksumtype, 4); - memcpy(send_pa->contents + 4, checksum.contents, checksum.length); - *out_pa_data = send_pa; - - /* Clean up. */ - krb5_free_checksum_contents(kcontext, &checksum); - - return 0; -} - -/* Initialize and tear down the server-side module, and do stat tracking. */ -static krb5_error_code -server_init(krb5_context kcontext, krb5_preauthtype pa_type, - void **module_context) -{ - struct server_stats *stats; - stats = malloc(sizeof(struct server_stats)); - if (stats == NULL) - return ENOMEM; - stats->successes = 0; - stats->failures = 0; - *module_context = stats; - return 0; -} -static void -server_fini(krb5_context kcontext, krb5_preauthtype pa_type, - void *module_context) -{ - struct server_stats *stats; - stats = module_context; - if (stats != NULL) { -#ifdef DEBUG - fprintf(stderr, "Total %d clients failed pa_type %d, %d succeeded.\n", - stats->failures, pa_type, stats->successes); -#endif - free(stats); - } -} - -/* Obtain and return any preauthentication data (which is destined for the - * client) which matches type data->pa_type. */ -static krb5_error_code -server_get_edata(krb5_context kcontext, - krb5_kdc_req *request, - struct _krb5_db_entry_new *client, - struct _krb5_db_entry_new *server, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - krb5_pa_data *data) -{ - krb5_data *key_data; - krb5_keyblock *keys, *key; - krb5_int32 *enctypes, enctype; - int i; - - /* Retrieve the client's keys. */ - key_data = NULL; - if ((*server_get_entry_data)(kcontext, request, client, - krb5plugin_preauth_keys, &key_data) != 0) { -#ifdef DEBUG - fprintf(stderr, "Error retrieving client keys.\n"); -#endif - return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - } - - /* Count which types of keys we've got, freeing the contents, which we - * don't need at this point. */ - keys = (krb5_keyblock *) key_data->data; - key = NULL; - for (i = 0; keys[i].enctype != 0; i++) - krb5_free_keyblock_contents(kcontext, &keys[i]); - - /* Return the list of encryption types. */ - enctypes = malloc(i * 4); - if (enctypes == NULL) { - krb5_free_data(kcontext, key_data); - return ENOMEM; - } -#ifdef DEBUG - fprintf(stderr, "Supported enctypes = {"); -#endif - for (i = 0; keys[i].enctype != 0; i++) { -#ifdef DEBUG - fprintf(stderr, "%s%d", (i > 0) ? ", " : "", keys[i].enctype); -#endif - enctype = htonl(keys[i].enctype); - memcpy(&enctypes[i], &enctype, 4); - } -#ifdef DEBUG - fprintf(stderr, "}.\n"); -#endif - data->pa_type = KRB5_PADATA_CKSUM_BODY_REQ; - data->length = (i * 4); - data->contents = (unsigned char *) enctypes; - krb5_free_data(kcontext, key_data); - return 0; -} - -/* Verify a request from a client. */ -static krb5_error_code -server_verify(krb5_context kcontext, - struct _krb5_db_entry_new *client, - krb5_data *req_pkt, - krb5_kdc_req *request, - krb5_enc_tkt_part *enc_tkt_reply, - krb5_pa_data *data, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - void **pa_request_context) -{ - krb5_int32 cksumtype; - krb5_checksum checksum; - krb5_boolean valid; - krb5_data *key_data, *req_body; - krb5_keyblock *keys, *key; - size_t length; - int i; - unsigned int j, cksumtypes_count; - krb5_cksumtype *cksumtypes; - krb5_error_code status; - struct server_stats *stats; - - stats = pa_module_context; - - /* Verify the preauth data. Start with the checksum type. */ - if (data->length < 4) { - stats->failures++; - return KRB5KDC_ERR_PREAUTH_FAILED; - } - memcpy(&cksumtype, data->contents, 4); - memset(&checksum, 0, sizeof(checksum)); - checksum.checksum_type = ntohl(cksumtype); - - /* Verify that the amount of data we have left is what we expect. */ - if (krb5_c_checksum_length(kcontext, checksum.checksum_type, - &length) != 0) { -#ifdef DEBUG - fprintf(stderr, "Error determining checksum size (type = %d). " - "Is it supported?\n", checksum.checksum_type); -#endif - stats->failures++; - return KRB5KDC_ERR_SUMTYPE_NOSUPP; - } - if (data->length - 4 != length) { -#ifdef DEBUG - fprintf(stderr, "Checksum size doesn't match client packet size.\n"); -#endif - stats->failures++; - return KRB5KDC_ERR_PREAUTH_FAILED; - } - checksum.length = length; - - /* Pull up the client's keys. */ - key_data = NULL; - if ((*server_get_entry_data)(kcontext, request, client, - krb5plugin_preauth_keys, &key_data) != 0) { -#ifdef DEBUG - fprintf(stderr, "Error retrieving client keys.\n"); -#endif - stats->failures++; - return KRB5KDC_ERR_PREAUTH_FAILED; - } - - /* Find the key which would have been used to generate the checksum. */ - keys = (krb5_keyblock *) key_data->data; - key = NULL; - for (i = 0; keys[i].enctype != 0; i++) { - key = &keys[i]; - cksumtypes_count = 0; - cksumtypes = NULL; - if (krb5_c_keyed_checksum_types(kcontext, key->enctype, - &cksumtypes_count, &cksumtypes) != 0) - continue; - for (j = 0; j < cksumtypes_count; j++) { - if (cksumtypes[j] == checksum.checksum_type) - break; - } - if (cksumtypes != NULL) - krb5_free_cksumtypes(kcontext, cksumtypes); - if (j < cksumtypes_count) { -#ifdef DEBUG - fprintf(stderr, "Found checksum key.\n"); -#endif - break; - } - } - if ((key == NULL) || (key->enctype == 0)) { - for (i = 0; keys[i].enctype != 0; i++) - krb5_free_keyblock_contents(kcontext, &keys[i]); - krb5_free_data(kcontext, key_data); - stats->failures++; - return KRB5KDC_ERR_SUMTYPE_NOSUPP; - } - - /* Save a copy of the key. */ - if (krb5_copy_keyblock(kcontext, &keys[i], &key) != 0) { - for (i = 0; keys[i].enctype != 0; i++) - krb5_free_keyblock_contents(kcontext, &keys[i]); - krb5_free_data(kcontext, key_data); - stats->failures++; - return KRB5KDC_ERR_SUMTYPE_NOSUPP; - } - for (i = 0; keys[i].enctype != 0; i++) - krb5_free_keyblock_contents(kcontext, &keys[i]); - krb5_free_data(kcontext, key_data); - - /* Rebuild a copy of the client's request-body. If we were serious - * about doing this with any chance of working interoperability, we'd - * extract the structure directly from the req_pkt structure. This - * will probably work if it's us on both ends, though. */ - req_body = NULL; - if ((*server_get_entry_data)(kcontext, request, client, - krb5plugin_preauth_request_body, - &req_body) != 0) { - krb5_free_keyblock(kcontext, key); - stats->failures++; - return KRB5KDC_ERR_PREAUTH_FAILED; - } - -#ifdef DEBUG - fprintf(stderr, "AS key type %d, checksum type %d, %d bytes.\n", - key->enctype, checksum.checksum_type, req_body->length); -#endif - - /* Verify the checksum itself. */ - checksum.contents = data->contents + 4; - valid = FALSE; - status = krb5_c_verify_checksum(kcontext, key, - KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, - req_body, &checksum, &valid); - - /* Clean up. */ - krb5_free_data(kcontext, req_body); - krb5_free_keyblock(kcontext, key); - - /* Evaluate our results. */ - if ((status != 0) || (!valid)) { -#ifdef DEBUG - if (status != 0) { - fprintf(stderr, "Error in checksum verification.\n"); - } else { - fprintf(stderr, "Checksum mismatch.\n"); - } -#endif - stats->failures++; - return KRB5KDC_ERR_PREAUTH_FAILED; - } - - /* Note that preauthentication succeeded. */ - enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; - stats->successes++; - return 0; -} - -/* Create the response for a client. */ -static krb5_error_code -server_return(krb5_context kcontext, - krb5_pa_data *padata, - struct _krb5_db_entry_new *client, - krb5_data *req_pkt, - krb5_kdc_req *request, - krb5_kdc_rep *reply, - struct _krb5_key_data *client_key, - krb5_keyblock *encrypting_key, - krb5_pa_data **send_pa, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - void **pa_request_context) -{ - /* We don't need to send data back on the return trip. */ - *send_pa = NULL; - return 0; -} - -static int -server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) -{ - return PA_SUFFICIENT; -} - -static krb5_preauthtype supported_client_pa_types[] = { - KRB5_PADATA_CKSUM_BODY_REQ, 0, -}; -static krb5_preauthtype supported_server_pa_types[] = { - KRB5_PADATA_CKSUM_BODY_REQ, 0, -}; - -struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = { - "cksum_body", - &supported_client_pa_types[0], - NULL, - NULL, - NULL, - client_get_flags, - NULL, - client_process, - NULL, -}; - -struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = { - "cksum_body", - &supported_server_pa_types[0], - server_init, - server_fini, - server_get_flags, - server_get_edata, - server_verify, - server_return, - NULL -}; diff --git a/src/plugins/preauth/wpse/Makefile.in b/src/plugins/preauth/wpse/Makefile.in index 6b18a7c06..6c2830f50 100644 --- a/src/plugins/preauth/wpse/Makefile.in +++ b/src/plugins/preauth/wpse/Makefile.in @@ -9,7 +9,7 @@ PROG_RPATH=$(KRB5_LIBDIR) MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR) DEFS=@DEFS@ -LOCALINCLUDES = -I../../../include/krb5 +LOCALINCLUDES = -I../../../include/krb5 -I. LIBBASE=wpse LIBMAJOR=0 @@ -25,9 +25,9 @@ SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS) SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) STOBJLISTS=OBJS.ST -STLIBOBJS=src/wpse.o +STLIBOBJS=wpse_main.o -SRCS= $(srcdir)/src/wpse.c +SRCS=wpse_main.c all-unix:: $(LIBBASE)$(SO_EXT) install-unix:: install-libs diff --git a/src/plugins/preauth/wpse/src/wpse.c b/src/plugins/preauth/wpse/src/wpse.c deleted file mode 100644 index 07c52d95a..000000000 --- a/src/plugins/preauth/wpse/src/wpse.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2006 Red Hat, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Red Hat, Inc., nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Worst. Preauthentication. Scheme. Ever. */ - -#ident "$Id$" - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include -#include - -#include -#include - -/* This is not a standardized value. It's defined here only to make it easier - * to change in this module. */ -#define KRB5_PADATA_WPSE_REQ 131 - -static int -client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) -{ - return PA_REAL; -} - -static krb5_error_code -client_init(krb5_context kcontext, krb5_preauthtype pa_type, void **ctx) -{ - int *mctx; - - mctx = malloc(sizeof(int)); - if (mctx == NULL) - return ENOMEM; - *mctx = 0; - *ctx = mctx; - return 0; -} - -static void -client_fini(krb5_context kcontext, krb5_preauthtype pa_type, void *ctx) -{ - int *mctx; - - mctx = ctx; - if (mctx) { -#ifdef DEBUG - fprintf(stderr, "wpse module called total of %d times\n", *mctx); -#endif - free(mctx); - } -} - -static krb5_error_code -client_process(krb5_context kcontext, - 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_pa_data *send_pa; - krb5_int32 nnonce, enctype; - krb5_keyblock *kb; - krb5_error_code status; - int *mctx; - -#ifdef DEBUG - fprintf(stderr, "%d bytes of preauthentication data (type %d)\n", - pa_data->length, pa_data->pa_type); -#endif - - mctx = module_context; - if (mctx) { - (*mctx)++; - } - - if (pa_data->length == 0) { - /* Create preauth data. */ - send_pa = malloc(sizeof(krb5_pa_data)); - if (send_pa == NULL) - return ENOMEM; - send_pa->pa_type = KRB5_PADATA_WPSE_REQ; - send_pa->length = 4; - send_pa->contents = malloc(4); - if (send_pa->contents == NULL) { - free(send_pa); - return ENOMEM; - } - /* Store the preauth data. */ - nnonce = htonl(request->nonce); - memcpy(send_pa->contents, &nnonce, 4); - *out_pa_data = send_pa; - /* Allocate a context. Useful for verifying that we do in fact - * do per-request cleanup. */ - if (*request_context == NULL) - *request_context = malloc(4); - } else { - /* A reply from the KDC. Conventionally this would be - * indicated by a different preauthentication type, but this - * mechanism/implementation doesn't do that. */ - if (pa_data->length > 4) { - memcpy(&enctype, pa_data->contents, 4); - kb = NULL; - status = krb5_init_keyblock(kcontext, ntohl(enctype), - pa_data->length - 4, &kb); - if (status != 0) - return status; - memcpy(kb->contents, pa_data->contents + 4, pa_data->length - 4); -#ifdef DEBUG - fprintf(stderr, "Recovered key type=%d, length=%d.\n", - kb->enctype, kb->length); -#endif - status = krb5_copy_keyblock_contents(kcontext, kb, as_key); - krb5_free_keyblock(kcontext, kb); - return status; - } - return KRB5KRB_ERR_GENERIC; - } - return 0; -} - -static void -client_cleanup(krb5_context kcontext, void *module_context, - void **request_context) -{ - if (*request_context != NULL) { - free(*request_context); - *request_context = NULL; - } - return; -} - -/* Free state. */ -static krb5_error_code -server_free_pa_request_context(krb5_context kcontext, void *module_context, - void **request_context) -{ - if (*request_context != NULL) { - free(*request_context); - *request_context = NULL; - } - return 0; -} - -/* Obtain and return any preauthentication data (which is destined for the - * client) which matches type data->pa_type. */ -static krb5_error_code -server_get_edata(krb5_context kcontext, - krb5_kdc_req *request, - struct _krb5_db_entry_new *client, - struct _krb5_db_entry_new *server, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - krb5_pa_data *data) -{ - /* Return zero bytes of data. */ - data->length = 0; - data->contents = NULL; - return 0; -} - -/* Verify a request from a client. */ -static krb5_error_code -server_verify(krb5_context kcontext, - struct _krb5_db_entry_new *client, - krb5_data *req_pkt, - krb5_kdc_req *request, - krb5_enc_tkt_part *enc_tkt_reply, - krb5_pa_data *data, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - void **pa_request_context) -{ - krb5_int32 nnonce; - /* Verify the preauth data. */ - if (data->length != 4) - return KRB5KDC_ERR_PREAUTH_FAILED; - memcpy(&nnonce, data->contents, 4); - nnonce = ntohl(nnonce); - if (memcmp(&nnonce, &request->nonce, 4) != 0) - return KRB5KDC_ERR_PREAUTH_FAILED; - /* Note that preauthentication succeeded. */ - enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; - enc_tkt_reply->flags |= TKT_FLG_HW_AUTH; - /* Allocate a context. Useful for verifying that we do in fact do - * per-request cleanup. */ - if (*pa_request_context == NULL) - *pa_request_context = malloc(4); - return 0; -} - -/* Create the response for a client. */ -static krb5_error_code -server_return(krb5_context kcontext, - krb5_pa_data *padata, - struct _krb5_db_entry_new *client, - krb5_data *req_pkt, - krb5_kdc_req *request, - krb5_kdc_rep *reply, - struct _krb5_key_data *client_key, - krb5_keyblock *encrypting_key, - krb5_pa_data **send_pa, - preauth_get_entry_data_proc server_get_entry_data, - void *pa_module_context, - void **pa_request_context) -{ - /* This module does a couple of dumb things. It tags its reply with - * the same type as the initial challenge (expecting the client to sort - * out whether there's anything useful in there). Oh, and it replaces - * the AS reply key with one which is sent in the clear. */ - krb5_keyblock *kb; - krb5_int32 enctype; - int i; - - *send_pa = NULL; - - /* We'll want a key with the first supported enctype. */ - for (i = 0; i < request->nktypes; i++) { - kb = NULL; - if (krb5_init_keyblock(kcontext, request->ktype[i], 0, &kb) == 0) { - break; - } - } - if (i >= request->nktypes) { - /* No matching cipher type found. */ - return 0; - } - - /* Randomize a key and save it for the client. */ - if (krb5_c_make_random_key(kcontext, request->ktype[i], kb) != 0) { - krb5_free_keyblock(kcontext, kb); - return 0; - } -#ifdef DEBUG - fprintf(stderr, "Generated random key, type=%d, length=%d.\n", - kb->enctype, kb->length); -#endif - - *send_pa = malloc(sizeof(krb5_pa_data)); - if (*send_pa == NULL) { - krb5_free_keyblock(kcontext, kb); - return ENOMEM; - } - (*send_pa)->pa_type = KRB5_PADATA_WPSE_REQ; - (*send_pa)->length = 4 + kb->length; - (*send_pa)->contents = malloc(4 + kb->length); - if ((*send_pa)->contents == NULL) { - free(*send_pa); - *send_pa = NULL; - krb5_free_keyblock(kcontext, kb); - return ENOMEM; - } - - /* Store the preauth data. */ - enctype = htonl(kb->enctype); - memcpy((*send_pa)->contents, &enctype, 4); - memcpy((*send_pa)->contents + 4, kb->contents, kb->length); - krb5_copy_keyblock_contents(kcontext, kb, encrypting_key); - - /* Clean up. */ - krb5_free_keyblock(kcontext, kb); - - return 0; -} - -static int -server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) -{ - return PA_HARDWARE | PA_REPLACES_KEY; -} - -static krb5_preauthtype supported_client_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0}; -static krb5_preauthtype supported_server_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0}; - -struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = { - "wpse", - &supported_client_pa_types[0], - NULL, - client_init, - client_fini, - client_get_flags, - client_cleanup, - client_process, - NULL, -}; - -struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = { - "wpse", - &supported_server_pa_types[0], - NULL, - NULL, - server_get_flags, - server_get_edata, - server_verify, - server_return, - server_free_pa_request_context, -}; diff --git a/src/plugins/preauth/wpse/wpse_main.c b/src/plugins/preauth/wpse/wpse_main.c new file mode 100644 index 000000000..e7d7b6d55 --- /dev/null +++ b/src/plugins/preauth/wpse/wpse_main.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2006 Red Hat, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Red Hat, Inc., nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Worst. Preauthentication. Scheme. Ever. */ + +#ident "$Id$" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include + +#include +#include + +/* This is not a standardized value. It's defined here only to make it easier + * to change in this module. */ +#define KRB5_PADATA_WPSE_REQ 131 + +static int +client_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) +{ + return PA_REAL; +} + +static krb5_error_code +client_init(krb5_context kcontext, void **ctx) +{ + int *pctx; + + pctx = malloc(sizeof(int)); + if (pctx == NULL) + return ENOMEM; + *pctx = 0; + *ctx = pctx; + return 0; +} + +static void +client_fini(krb5_context kcontext, void *ctx) +{ + int *pctx; + + pctx = ctx; + if (pctx) { +#ifdef DEBUG + fprintf(stderr, "wpse module called total of %d times\n", *pctx); +#endif + free(pctx); + } +} + +static krb5_error_code +client_process(krb5_context kcontext, + void *plugin_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, + void *gak_data, + krb5_data *salt, krb5_data *s2kparams, + krb5_keyblock *as_key, + krb5_pa_data **out_pa_data) +{ + krb5_pa_data *send_pa; + krb5_int32 nnonce, enctype; + krb5_keyblock *kb; + krb5_error_code status; + int *pctx; + +#ifdef DEBUG + fprintf(stderr, "%d bytes of preauthentication data (type %d)\n", + pa_data->length, pa_data->pa_type); +#endif + + pctx = plugin_context; + if (pctx) { + (*pctx)++; + } + + if (pa_data->length == 0) { + /* Create preauth data. */ + send_pa = malloc(sizeof(krb5_pa_data)); + if (send_pa == NULL) + return ENOMEM; + send_pa->pa_type = KRB5_PADATA_WPSE_REQ; + send_pa->length = 4; + send_pa->contents = malloc(4); + if (send_pa->contents == NULL) { + free(send_pa); + return ENOMEM; + } + /* Store the preauth data. */ + nnonce = htonl(request->nonce); + memcpy(send_pa->contents, &nnonce, 4); + *out_pa_data = send_pa; + } else { + /* A reply from the KDC. Conventionally this would be + * indicated by a different preauthentication type, but this + * mechanism/implementation doesn't do that. */ + if (pa_data->length > 4) { + memcpy(&enctype, pa_data->contents, 4); + kb = NULL; + status = krb5_init_keyblock(kcontext, ntohl(enctype), + pa_data->length - 4, &kb); + if (status != 0) + return status; + memcpy(kb->contents, pa_data->contents + 4, pa_data->length - 4); +#ifdef DEBUG + fprintf(stderr, "Recovered key type=%d, length=%d.\n", + kb->enctype, kb->length); +#endif + status = krb5_copy_keyblock_contents(kcontext, kb, as_key); + krb5_free_keyblock(kcontext, kb); + return status; + } + return KRB5KRB_ERR_GENERIC; + } + return 0; +} + +#define WPSE_MAGIC 0x77707365 +typedef struct _wpse_req_ctx +{ + int magic; + int value; +} wpse_req_ctx; + +static void +client_req_init(krb5_context kcontext, void *plugin_context, void **req_context_p) +{ + wpse_req_ctx *ctx; + + *req_context_p = NULL; + + /* Allocate a request context. Useful for verifying that we do in fact + * do per-request cleanup. */ + ctx = (wpse_req_ctx *) malloc(sizeof(*ctx)); + if (ctx == NULL) + return; + ctx->magic = WPSE_MAGIC; + ctx->value = 0xc0dec0de; + + *req_context_p = ctx; +} + +static void +client_req_cleanup(krb5_context kcontext, void *plugin_context, void *req_context) +{ + wpse_req_ctx *ctx = (wpse_req_ctx *)req_context; + + if (ctx) { +#ifdef DEBUG + fprintf(stderr, "client_req_cleanup: req_ctx at %p has magic %x and value %x\n", + ctx, ctx->magic, ctx->value); +#endif + if (ctx->magic != WPSE_MAGIC) { +#ifdef DEBUG + fprintf(stderr, "client_req_cleanup: req_context at %p has bad magic value %x\n", + ctx, ctx->magic); +#endif + return; + } + free(ctx); + } + return; +} + +/* Free state. */ +static krb5_error_code +server_free_pa_request_context(krb5_context kcontext, void *plugin_context, + void **request_context) +{ + if (*request_context != NULL) { + free(*request_context); + *request_context = NULL; + } + return 0; +} + +/* Obtain and return any preauthentication data (which is destined for the + * client) which matches type data->pa_type. */ +static krb5_error_code +server_get_edata(krb5_context kcontext, + krb5_kdc_req *request, + struct _krb5_db_entry_new *client, + struct _krb5_db_entry_new *server, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + krb5_pa_data *data) +{ + /* Return zero bytes of data. */ + data->length = 0; + data->contents = NULL; + return 0; +} + +/* Verify a request from a client. */ +static krb5_error_code +server_verify(krb5_context kcontext, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_enc_tkt_part *enc_tkt_reply, + krb5_pa_data *data, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + void **pa_request_context) +{ + krb5_int32 nnonce; + /* Verify the preauth data. */ + if (data->length != 4) + return KRB5KDC_ERR_PREAUTH_FAILED; + memcpy(&nnonce, data->contents, 4); + nnonce = ntohl(nnonce); + if (memcmp(&nnonce, &request->nonce, 4) != 0) + return KRB5KDC_ERR_PREAUTH_FAILED; + /* Note that preauthentication succeeded. */ + enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; + enc_tkt_reply->flags |= TKT_FLG_HW_AUTH; + /* Allocate a context. Useful for verifying that we do in fact do + * per-request cleanup. */ + if (*pa_request_context == NULL) + *pa_request_context = malloc(4); + return 0; +} + +/* Create the response for a client. */ +static krb5_error_code +server_return(krb5_context kcontext, + krb5_pa_data *padata, + struct _krb5_db_entry_new *client, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_kdc_rep *reply, + struct _krb5_key_data *client_key, + krb5_keyblock *encrypting_key, + krb5_pa_data **send_pa, + preauth_get_entry_data_proc server_get_entry_data, + void *pa_module_context, + void **pa_request_context) +{ + /* This module does a couple of dumb things. It tags its reply with + * the same type as the initial challenge (expecting the client to sort + * out whether there's anything useful in there). Oh, and it replaces + * the AS reply key with one which is sent in the clear. */ + krb5_keyblock *kb; + krb5_int32 enctype; + int i; + + *send_pa = NULL; + + /* We'll want a key with the first supported enctype. */ + for (i = 0; i < request->nktypes; i++) { + kb = NULL; + if (krb5_init_keyblock(kcontext, request->ktype[i], 0, &kb) == 0) { + break; + } + } + if (i >= request->nktypes) { + /* No matching cipher type found. */ + return 0; + } + + /* Randomize a key and save it for the client. */ + if (krb5_c_make_random_key(kcontext, request->ktype[i], kb) != 0) { + krb5_free_keyblock(kcontext, kb); + return 0; + } +#ifdef DEBUG + fprintf(stderr, "Generated random key, type=%d, length=%d.\n", + kb->enctype, kb->length); +#endif + + *send_pa = malloc(sizeof(krb5_pa_data)); + if (*send_pa == NULL) { + krb5_free_keyblock(kcontext, kb); + return ENOMEM; + } + (*send_pa)->pa_type = KRB5_PADATA_WPSE_REQ; + (*send_pa)->length = 4 + kb->length; + (*send_pa)->contents = malloc(4 + kb->length); + if ((*send_pa)->contents == NULL) { + free(*send_pa); + *send_pa = NULL; + krb5_free_keyblock(kcontext, kb); + return ENOMEM; + } + + /* Store the preauth data. */ + enctype = htonl(kb->enctype); + memcpy((*send_pa)->contents, &enctype, 4); + memcpy((*send_pa)->contents + 4, kb->contents, kb->length); + krb5_copy_keyblock_contents(kcontext, kb, encrypting_key); + + /* Clean up. */ + krb5_free_keyblock(kcontext, kb); + + return 0; +} + +static int +server_get_flags(krb5_context kcontext, krb5_preauthtype pa_type) +{ + return PA_HARDWARE | PA_REPLACES_KEY; +} + +static krb5_preauthtype supported_client_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0}; +static krb5_preauthtype supported_server_pa_types[] = {KRB5_PADATA_WPSE_REQ, 0}; + +struct krb5plugin_preauth_client_ftable_v0 preauthentication_client_0 = { + "wpse", /* name */ + &supported_client_pa_types[0], /* pa_type_list */ + NULL, /* enctype_list */ + client_init, /* plugin init function */ + client_fini, /* plugin fini function */ + client_get_flags, /* get flags function */ + client_req_init, /* request init function */ + client_req_cleanup, /* request fini function */ + client_process, /* process function */ + NULL, /* try_again function */ +}; + +struct krb5plugin_preauth_server_ftable_v0 preauthentication_server_0 = { + "wpse", + &supported_server_pa_types[0], + NULL, + NULL, + server_get_flags, + server_get_edata, + server_verify, + server_return, + server_free_pa_request_context, +}; -- cgit