#include <krb5/preauth_plugin.h>
+#define CLIENT_ROCK_MAGIC 0x4352434b
+/* This structure is passed into the client preauth functions and passed
+ * back to the "get_data_proc" function so that it can locate the
+ * requested information. It is opaque to the plugin code and can be
+ * expanded in the future as new types of requests are defined which
+ * may require other things to be passed through. */
+typedef struct _krb5_preauth_client_rock {
+ krb5_magic magic;
+ krb5_kdc_rep *as_reply;
+} krb5_preauth_client_rock;
+
/* 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. */
krb5_error_code (*client_process)(krb5_context context,
void *plugin_context,
void *request_context,
+ preauth_get_client_data_proc get_data_proc,
+ krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
krb5_error_code (*client_tryagain)(krb5_context context,
void *plugin_context,
void *request_context,
+ preauth_get_client_data_proc get_data_proc,
+ krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
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_gic_get_as_key_fct gak_fct, void *gak_data,
+ krb5_preauth_client_rock *get_data_rock);
krb5_error_code KRB5_CALLCONV krb5_do_preauth_tryagain
(krb5_context context,
krb5_kdc_req *request,
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_gic_get_as_key_fct gak_fct, void *gak_data,
+ krb5_preauth_client_rock *get_data_rock);
void KRB5_CALLCONV krb5_init_preauth_context
(krb5_context);
void KRB5_CALLCONV krb5_free_preauth_context
*/
struct _krb5_db_entry_new;
struct _krb5_key_data;
+struct _krb5_preauth_client_rock;
/*
* Preauth mechanism property flags, unified from previous definitions in the
krb5_int32 request_type,
krb5_data **);
+/*
+ * A client module's callback functions are allowed to request various
+ * information to enable it to process a request.
+ */
+enum krb5plugin_preauth_client_request_type {
+ /* The returned krb5_data item holds the enctype used to encrypt the
+ * encrypted portion of the AS_REP packet. */
+ krb5plugin_preauth_client_get_etype = 1,
+ /* Free the data returned from krb5plugin_preauth_client_req_get_etype */
+ krb5plugin_preauth_client_free_etype = 2,
+};
+typedef krb5_error_code
+(*preauth_get_client_data_proc)(krb5_context,
+ struct _krb5_preauth_client_rock *,
+ krb5_int32 request_type,
+ krb5_data **);
+
/*
* A callback which will obtain the user's long-term AS key by prompting the
* user for the password, then salting it properly, and so on. For the moment,
krb5_error_code (*process)(krb5_context context,
void *plugin_context,
void *request_context,
+ preauth_get_client_data_proc get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
krb5_error_code (*tryagain)(krb5_context context,
void *plugin_context,
void *request_context,
+ preauth_get_client_data_proc get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
krb5_kdc_rep *local_as_reply;
krb5_timestamp time_now;
krb5_enctype etype = 0;
+ krb5_preauth_client_rock get_data_rock;
/* initialize everything which will be freed at cleanup */
if (ret)
goto cleanup;
+ get_data_rock.magic = CLIENT_ROCK_MAGIC;
+ get_data_rock.as_reply = NULL;
+
/* now, loop processing preauth data and talking to the kdc */
for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
if (!err_reply) {
preauth_to_use, &request.padata,
&salt, &s2kparams, &etype, &as_key,
prompter, prompter_data,
- gak_fct, gak_data)))
+ gak_fct, gak_data,
+ &get_data_rock)))
goto cleanup;
} else {
/* retrying after an error other than PREAUTH_NEEDED, using e-data
err_reply,
&salt, &s2kparams, &etype, &as_key,
prompter, prompter_data,
- gak_fct, gak_data)) {
+ gak_fct, gak_data,
+ &get_data_rock)) {
/* couldn't come up with anything better */
ret = err_reply->error + ERROR_TABLE_BASE_krb5;
krb5_free_error(context, err_reply);
if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
local_as_reply->padata)))
goto cleanup;
+ get_data_rock.as_reply = local_as_reply;
if ((ret = krb5_do_preauth(context,
&request,
encoded_request_body, encoded_previous_request,
local_as_reply->padata, &kdc_padata,
&salt, &s2kparams, &etype, &as_key, prompter,
- prompter_data, gak_fct, gak_data)))
+ prompter_data, gak_fct, gak_data,
+ &get_data_rock)))
goto cleanup;
/* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
return 0;
}
+/*
+ * Retrieve a specific piece of information required by the plugin and
+ * return it in a new krb5_data item. There are separate request_types
+ * to obtain the data and free it.
+ *
+ * This may require massaging data into a contrived format, but it will
+ * hopefully keep us from having to reveal library-internal functions
+ * or data to the plugin modules.
+ */
+
+static krb5_error_code
+client_data_proc(krb5_context kcontext,
+ krb5_preauth_client_rock *rock,
+ krb5_int32 request_type,
+ krb5_data **retdata)
+{
+ krb5_data *ret;
+ char *data;
+
+ if (rock->magic != CLIENT_ROCK_MAGIC)
+ return EINVAL;
+ if (retdata == NULL)
+ return EINVAL;
+
+ switch (request_type) {
+ case krb5plugin_preauth_client_get_etype:
+ {
+ krb5_enctype *eptr;
+ if (rock->as_reply == NULL)
+ return ENOENT;
+ ret = malloc(sizeof(krb5_data));
+ if (ret == NULL)
+ return ENOMEM;
+ data = malloc(sizeof(krb5_enctype));
+ if (data == NULL) {
+ free(ret);
+ return ENOMEM;
+ }
+ ret->data = data;
+ ret->length = sizeof(krb5_enctype);
+ eptr = (krb5_enctype *)data;
+ *eptr = rock->as_reply->enc_part.enctype;
+ *retdata = ret;
+ return 0;
+ }
+ break;
+ case krb5plugin_preauth_client_free_etype:
+ ret = *retdata;
+ if (ret == NULL)
+ return 0;
+ if (ret->data)
+ free(ret->data);
+ free(ret);
+ return 0;
+ break;
+ default:
+ return EINVAL;
+ }
+}
+
/* Tweak the request body, for now adding any enctypes which the module claims
* to add support for to the list, but in the future perhaps doing more
* involved things. */
krb5_data *salt,
krb5_data *s2kparams,
void *gak_data,
+ krb5_preauth_client_rock *get_data_rock,
krb5_keyblock *as_key,
krb5_pa_data ***out_pa_list,
int *out_pa_list_size,
ret = module->client_process(kcontext,
module->plugin_context,
module->request_context,
+ client_data_proc,
+ get_data_rock,
request,
encoded_request_body,
encoded_previous_request,
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_gic_get_as_key_fct gak_fct, void *gak_data,
+ krb5_preauth_client_rock *get_data_rock)
{
krb5_error_code ret;
krb5_pa_data *out_padata;
if ((*module->client_tryagain)(kcontext,
module->plugin_context,
module->request_context,
+ client_data_proc,
+ get_data_rock,
request,
encoded_request_body,
encoded_previous_request,
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_gic_get_as_key_fct gak_fct, void *gak_data,
+ krb5_preauth_client_rock *get_data_rock)
{
int h, i, j, out_pa_list_size;
int seen_etype_info2 = 0;
gak_fct,
salt, s2kparams,
gak_data,
+ get_data_rock,
as_key,
&out_pa_list,
&out_pa_list_size,
client_process(krb5_context kcontext,
void *client_plugin_context,
void *client_request_context,
+ preauth_get_client_data_proc client_get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,
client_process(krb5_context kcontext,
void *plugin_context,
void *request_context,
+ preauth_get_client_data_proc client_get_data_proc,
+ struct _krb5_preauth_client_rock *rock,
krb5_kdc_req *request,
krb5_data *encoded_request_body,
krb5_data *encoded_previous_request,