#include "k5-int.h"
#include <krb5/clpreauth_plugin.h>
#include "common.h"
static krb5_preauthtype pa_types[] = { TEST_PA_TYPE, 0 };
struct client_state {
char *indicators;
krb5_boolean fail_optimistic;
krb5_boolean fail_2rt;
krb5_boolean fail_tryagain;
krb5_boolean disable_fallback;
};
struct client_request_state {
krb5_boolean second_round_trip;
};
static krb5_error_code
test_init(krb5_context context, krb5_clpreauth_moddata *moddata_out)
{
struct client_state *st;
st = malloc(sizeof(*st));
assert(st != NULL);
st->indicators = NULL;
st->fail_optimistic = st->fail_2rt = st->fail_tryagain = FALSE;
st->disable_fallback = FALSE;
*moddata_out = (krb5_clpreauth_moddata)st;
return 0;
}
static void
test_fini(krb5_context context, krb5_clpreauth_moddata moddata)
{
struct client_state *st = (struct client_state *)moddata;
free(st->indicators);
free(st);
}
static void
test_request_init(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_clpreauth_modreq *modreq_out)
{
struct client_request_state *reqst;
reqst = malloc(sizeof(*reqst));
assert(reqst != NULL);
reqst->second_round_trip = FALSE;
*modreq_out = (krb5_clpreauth_modreq)reqst;
}
static void
test_request_fini(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_clpreauth_modreq modreq)
{
free(modreq);
}
static krb5_error_code
test_process(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
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,
krb5_pa_data ***out_pa_data)
{
struct client_state *st = (struct client_state *)moddata;
struct client_request_state *reqst = (struct client_request_state *)modreq;
krb5_error_code ret;
krb5_keyblock *k;
krb5_enc_data enc;
krb5_data plain;
const char *indstr;
if (pa_data->length == 0) {
if (st->fail_optimistic) {
k5_setmsg(context, KRB5_PREAUTH_FAILED, "induced optimistic fail");
return KRB5_PREAUTH_FAILED;
}
*out_pa_data = make_pa_list("optimistic", 10);
if (st->disable_fallback)
cb->disable_fallback(context, rock);
return 0;
} else if (reqst->second_round_trip) {
printf("2rt: %.*s\n", pa_data->length, pa_data->contents);
if (st->fail_2rt) {
k5_setmsg(context, KRB5_PREAUTH_FAILED, "induced 2rt fail");
return KRB5_PREAUTH_FAILED;
}
} else if (pa_data->length == 6 &&
memcmp(pa_data->contents, "no key", 6) == 0) {
printf("no key\n");
} else {
ret = cb->get_as_key(context, rock, &k);
if (ret)
return ret;
ret = alloc_data(&plain, pa_data->length);
assert(!ret);
enc.enctype = k->enctype;
enc.ciphertext = make_data(pa_data->contents, pa_data->length);
ret = krb5_c_decrypt(context, k, 1024, NULL, &enc, &plain);
assert(!ret);
printf("%.*s\n", plain.length, plain.data);
free(plain.data);
}
reqst->second_round_trip = TRUE;
indstr = (st->indicators != NULL) ? st->indicators : "";
*out_pa_data = make_pa_list(indstr, strlen(indstr));
if (st->disable_fallback)
cb->disable_fallback(context, rock);
return 0;
}
static krb5_error_code
test_tryagain(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
krb5_kdc_req *request, krb5_data *enc_req, krb5_data *enc_prev,
krb5_preauthtype pa_type, krb5_error *error,
krb5_pa_data **padata, krb5_prompter_fct prompter,
void *prompter_data, krb5_pa_data ***padata_out)
{
struct client_state *st = (struct client_state *)moddata;
int i;
*padata_out = NULL;
if (st->fail_tryagain) {
k5_setmsg(context, KRB5_PREAUTH_FAILED, "induced tryagain fail");
return KRB5_PREAUTH_FAILED;
}
if (error->error != KDC_ERR_ENCTYPE_NOSUPP)
return KRB5_PREAUTH_FAILED;
for (i = 0; padata[i] != NULL; i++) {
if (padata[i]->pa_type == TEST_PA_TYPE)
printf("tryagain: %.*s\n", padata[i]->length, padata[i]->contents);
}
*padata_out = make_pa_list("tryagain", 8);
return 0;
}
static krb5_error_code
test_gic_opt(krb5_context kcontext, krb5_clpreauth_moddata moddata,
krb5_get_init_creds_opt *opt, const char *attr, const char *value)
{
struct client_state *st = (struct client_state *)moddata;
if (strcmp(attr, "indicators") == 0) {
free(st->indicators);
st->indicators = strdup(value);
assert(st->indicators != NULL);
} else if (strcmp(attr, "fail_optimistic") == 0) {
st->fail_optimistic = TRUE;
} else if (strcmp(attr, "fail_2rt") == 0) {
st->fail_2rt = TRUE;
} else if (strcmp(attr, "fail_tryagain") == 0) {
st->fail_tryagain = TRUE;
} else if (strcmp(attr, "disable_fallback") == 0) {
st->disable_fallback = TRUE;
}
return 0;
}
krb5_error_code
clpreauth_test_initvt(krb5_context context, int maj_ver,
int min_ver, krb5_plugin_vtable vtable);
krb5_error_code
clpreauth_test_initvt(krb5_context context, int maj_ver,
int min_ver, krb5_plugin_vtable vtable)
{
krb5_clpreauth_vtable vt;
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
vt = (krb5_clpreauth_vtable)vtable;
vt->name = "test";
vt->pa_type_list = pa_types;
vt->init = test_init;
vt->fini = test_fini;
vt->request_init = test_request_init;
vt->request_fini = test_request_fini;
vt->process = test_process;
vt->tryagain = test_tryagain;
vt->gic_opts = test_gic_opt;
return 0;
}