gss: Add threaded testing of GSS-API!
This commit is contained in:
@@ -82,6 +82,8 @@ static int token_split = 0;
|
||||
static int version_flag = 0;
|
||||
static int verbose_flag = 0;
|
||||
static int help_flag = 0;
|
||||
static int threaded_flag = 0;
|
||||
static int num_threads = 8;
|
||||
static int i_channel_bound = 0;
|
||||
static char *i_channel_bindings = NULL;
|
||||
static char *a_channel_bindings = NULL;
|
||||
@@ -932,6 +934,8 @@ static struct getargs args[] = {
|
||||
{"token-split", 0, arg_integer, &token_split, "bytes", NULL },
|
||||
{"on-behalf-of", 0, arg_string, &on_behalf_of_string, "principal",
|
||||
"send authenticator authz-data AD-ON-BEHALF-OF" },
|
||||
{"threaded", 0, arg_flag, &threaded_flag, "run threaded test", NULL },
|
||||
{"num-threads", 0, arg_integer, &num_threads, "number of threads for --threaded", NULL },
|
||||
{"version", 0, arg_flag, &version_flag, "print version", NULL },
|
||||
{"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
|
||||
{"help", 0, arg_flag, &help_flag, NULL, NULL }
|
||||
@@ -945,6 +949,98 @@ usage (int ret)
|
||||
exit (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Threaded test for exercising concurrent GSS context establishment.
|
||||
* This helps detect race conditions in context/credential handling.
|
||||
*/
|
||||
|
||||
struct threaded_test_args {
|
||||
gss_OID mechoid;
|
||||
gss_OID nameoid;
|
||||
const char *target;
|
||||
gss_cred_id_t client_cred;
|
||||
int thread_num;
|
||||
int iterations;
|
||||
int failed;
|
||||
};
|
||||
|
||||
static void *
|
||||
threaded_test_worker(void *arg)
|
||||
{
|
||||
struct threaded_test_args *ta = arg;
|
||||
gss_ctx_id_t sctx = GSS_C_NO_CONTEXT;
|
||||
gss_ctx_id_t cctx = GSS_C_NO_CONTEXT;
|
||||
gss_OID actual_mech = GSS_C_NO_OID;
|
||||
gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
|
||||
OM_uint32 min_stat;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ta->iterations; i++) {
|
||||
if (verbose_flag)
|
||||
printf("thread %d: iteration %d/%d\n",
|
||||
ta->thread_num, i + 1, ta->iterations);
|
||||
|
||||
sctx = GSS_C_NO_CONTEXT;
|
||||
cctx = GSS_C_NO_CONTEXT;
|
||||
deleg_cred = GSS_C_NO_CREDENTIAL;
|
||||
|
||||
loop(ta->mechoid, ta->nameoid, ta->target, ta->client_cred,
|
||||
&sctx, &cctx, &actual_mech, &deleg_cred);
|
||||
|
||||
gss_delete_sec_context(&min_stat, &cctx, NULL);
|
||||
gss_delete_sec_context(&min_stat, &sctx, NULL);
|
||||
gss_release_cred(&min_stat, &deleg_cred);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
run_threaded_test(gss_OID mechoid, gss_OID nameoid, const char *target,
|
||||
gss_cred_id_t client_cred, int nthreads, int iterations)
|
||||
{
|
||||
HEIMDAL_THREAD_ID *threads;
|
||||
struct threaded_test_args *thread_args;
|
||||
int i, ret = 0;
|
||||
|
||||
if (verbose_flag)
|
||||
printf("running threaded test: %d threads, %d iterations each\n",
|
||||
nthreads, iterations);
|
||||
|
||||
threads = calloc(nthreads, sizeof(*threads));
|
||||
thread_args = calloc(nthreads, sizeof(*thread_args));
|
||||
if (threads == NULL || thread_args == NULL)
|
||||
errx(1, "out of memory");
|
||||
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
thread_args[i].mechoid = mechoid;
|
||||
thread_args[i].nameoid = nameoid;
|
||||
thread_args[i].target = target;
|
||||
thread_args[i].client_cred = client_cred;
|
||||
thread_args[i].thread_num = i;
|
||||
thread_args[i].iterations = iterations;
|
||||
thread_args[i].failed = 0;
|
||||
|
||||
if (HEIMDAL_THREAD_create(&threads[i], threaded_test_worker,
|
||||
&thread_args[i]) != 0)
|
||||
errx(1, "HEIMDAL_THREAD_create failed for thread %d", i);
|
||||
}
|
||||
|
||||
for (i = 0; i < nthreads; i++) {
|
||||
HEIMDAL_THREAD_join(threads[i], NULL);
|
||||
if (thread_args[i].failed)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
free(threads);
|
||||
free(thread_args);
|
||||
|
||||
if (verbose_flag)
|
||||
printf("threaded test %s\n", ret ? "FAILED" : "completed");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@@ -1177,6 +1273,21 @@ main(int argc, char **argv)
|
||||
gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
|
||||
}
|
||||
|
||||
if (threaded_flag) {
|
||||
int iterations = max_loops > 0 ? max_loops : 10;
|
||||
int ret;
|
||||
|
||||
ret = run_threaded_test(mechoid, nameoid, argv[0], client_cred,
|
||||
num_threads, iterations);
|
||||
gss_release_cred(&min_stat, &client_cred);
|
||||
gss_release_oid_set(&min_stat, &actual_mechs);
|
||||
if (mechoids != GSS_C_NO_OID_SET && mechoids != &mechoid_descs)
|
||||
gss_release_oid_set(&min_stat, &mechoids);
|
||||
empty_release();
|
||||
krb5_free_context(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
loop(mechoid, nameoid, argv[0], client_cred,
|
||||
&sctx, &cctx, &actual_mech, &deleg_cred);
|
||||
|
||||
|
||||
@@ -607,6 +607,26 @@ ${context} \
|
||||
host/long.test.h5l.se || \
|
||||
{ eval "$testfailed"; }
|
||||
|
||||
test_section "threaded context establishment"
|
||||
test_section "Getting client initial tickets for threaded test"
|
||||
test_run ${kinit} --password-file=${objdir}/foopassword user1@${R}
|
||||
|
||||
test_section "threaded gss context (krb5)"
|
||||
test_run ${context} \
|
||||
--mech-type=krb5 \
|
||||
--threaded \
|
||||
--num-threads=4 \
|
||||
--max-loops=5 \
|
||||
--name-type=hostbased-service host@lucid.test.h5l.se
|
||||
|
||||
test_section "threaded gss context (spnego)"
|
||||
test_run ${context} \
|
||||
--mech-type=spnego \
|
||||
--threaded \
|
||||
--num-threads=4 \
|
||||
--max-loops=5 \
|
||||
--name-type=hostbased-service host@lucid.test.h5l.se
|
||||
|
||||
trap "" EXIT
|
||||
|
||||
echo "killing kdc (${kdcpid})"
|
||||
|
||||
Reference in New Issue
Block a user