#include "k5-platform.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <krb5.h>
static const int iterations = 200;
static const char *ccname, *server_name, *client_name;
static void
check(krb5_error_code code)
{
if (code)
abort();
}
static krb5_boolean
get_cred(krb5_context context)
{
krb5_error_code ret;
krb5_ccache cc;
krb5_principal client, server;
krb5_creds mcred, *cred;
check(krb5_cc_resolve(context, ccname, &cc));
check(krb5_parse_name(context, client_name, &client));
check(krb5_parse_name(context, server_name, &server));
memset(&mcred, 0, sizeof(mcred));
mcred.client = client;
mcred.server = server;
ret = krb5_get_credentials(context, 0, cc, &mcred, &cred);
krb5_free_creds(context, cred);
krb5_free_principal(context, client);
krb5_free_principal(context, server);
krb5_cc_close(context, cc);
return ret == 0;
}
static krb5_boolean
refresh_cache(krb5_context context)
{
krb5_error_code ret;
krb5_ccache cc;
krb5_principal client;
krb5_get_init_creds_opt *opt;
krb5_creds cred;
check(krb5_cc_resolve(context, ccname, &cc));
check(krb5_parse_name(context, client_name, &client));
check(krb5_get_init_creds_opt_alloc(context, &opt));
check(krb5_get_init_creds_opt_set_out_ccache(context, opt, cc));
ret = krb5_get_init_creds_keytab(context, &cred, client, NULL, 0, NULL,
opt);
krb5_get_init_creds_opt_free(context, opt);
krb5_free_cred_contents(context, &cred);
krb5_free_principal(context, client);
krb5_cc_close(context, cc);
return ret == 0;
}
static pid_t
spawn_cred_subprocess(void)
{
krb5_context context;
pid_t pid;
int i;
pid = fork();
assert(pid >= 0);
if (pid > 0)
return pid;
check(krb5_init_context(&context));
for (i = 0; i < iterations; i++) {
if (!get_cred(context)) {
fprintf(stderr, "cred worker failed after %d successes\n", i);
exit(1);
}
}
krb5_free_context(context);
exit(0);
}
static pid_t
spawn_refresh_subprocess(void)
{
krb5_context context;
pid_t pid;
int i;
pid = fork();
assert(pid >= 0);
if (pid > 0)
return pid;
check(krb5_init_context(&context));
for (i = 0; i < iterations; i++) {
if (!refresh_cache(context)) {
fprintf(stderr, "refresh worker failed after %d successes\n", i);
exit(1);
}
}
krb5_free_context(context);
exit(0);
}
int
main(int argc, char *argv[])
{
krb5_context context;
pid_t cred_pid, refresh_pid, pid;
int cstatus, rstatus;
assert(argc == 4);
ccname = argv[1];
client_name = argv[2];
server_name = argv[3];
check(krb5_init_context(&context));
refresh_cache(context);
krb5_free_context(context);
cred_pid = spawn_cred_subprocess();
refresh_pid = spawn_refresh_subprocess();
pid = waitpid(cred_pid, &cstatus, 0);
if (pid == -1)
abort();
pid = waitpid(refresh_pid, &rstatus, 0);
if (pid == -1)
abort();
if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus) != 0)
return 1;
if (!WIFEXITED(rstatus) || WEXITSTATUS(rstatus) != 0)
return 1;
return 0;
}