|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* tests/unlockiter.c - test program for unlocked iteration */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright (C) 2014 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
* All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions
|
|
Packit |
fd8b60 |
* are met:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* * Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* * Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
fd8b60 |
* the documentation and/or other materials provided with the
|
|
Packit |
fd8b60 |
* distribution.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
fd8b60 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
fd8b60 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
Packit |
fd8b60 |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
Packit |
fd8b60 |
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
Packit |
fd8b60 |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
Packit |
fd8b60 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
fd8b60 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
fd8b60 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit |
fd8b60 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
fd8b60 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
Packit |
fd8b60 |
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Test unlocked KDB iteration.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <sys/types.h>
|
|
Packit |
fd8b60 |
#include <sys/select.h>
|
|
Packit |
fd8b60 |
#include <sys/time.h>
|
|
Packit |
fd8b60 |
#include <sys/wait.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <errno.h>
|
|
Packit |
fd8b60 |
#include <krb5.h>
|
|
Packit |
fd8b60 |
#include <kadm5/admin.h>
|
|
Packit |
fd8b60 |
#include <signal.h>
|
|
Packit |
fd8b60 |
#include <stdlib.h>
|
|
Packit |
fd8b60 |
#include <string.h> /* Some platforms need memset() for FD_ZERO */
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct cb_arg {
|
|
Packit |
fd8b60 |
int inpipe;
|
|
Packit |
fd8b60 |
int outpipe;
|
|
Packit |
fd8b60 |
int timeout;
|
|
Packit |
fd8b60 |
int done;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Helper function for cb(): read a sync byte (with possible timeout), then
|
|
Packit |
fd8b60 |
* write a sync byte. */
|
|
Packit |
fd8b60 |
static int
|
|
Packit |
fd8b60 |
syncpair_rw(const char *name, struct cb_arg *arg, char *cp, int timeout)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct timeval tv;
|
|
Packit |
fd8b60 |
fd_set rset;
|
|
Packit |
fd8b60 |
int nfds;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
FD_ZERO(&rset);
|
|
Packit |
fd8b60 |
FD_SET(arg->inpipe, &rset);
|
|
Packit |
fd8b60 |
tv.tv_sec = timeout;
|
|
Packit |
fd8b60 |
tv.tv_usec = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
printf("cb: waiting for %s sync pair\n", name);
|
|
Packit |
fd8b60 |
nfds = select(arg->inpipe + 1, &rset,
|
|
Packit |
fd8b60 |
NULL, NULL, (timeout == 0) ? NULL : &tv;;
|
|
Packit |
fd8b60 |
if (nfds < 0)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
if (nfds == 0) {
|
|
Packit |
fd8b60 |
errno = ETIMEDOUT;
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (read(arg->inpipe, cp, 1) < 0)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
printf("cb: writing %s sync pair\n", name);
|
|
Packit |
fd8b60 |
if (write(arg->outpipe, cp, 1) < 0)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* On the first iteration only, receive and send sync bytes to the locking
|
|
Packit |
fd8b60 |
* child to drive its locking activities. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
cb(void *argin, krb5_db_entry *ent)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct cb_arg *arg = argin;
|
|
Packit |
fd8b60 |
char c = '\0';
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (arg->done)
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (syncpair_rw("first", arg, &c, 0) < 0) {
|
|
Packit |
fd8b60 |
com_err("cb", errno, "first sync pair");
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (syncpair_rw("second", arg, &c, arg->timeout) < 0) {
|
|
Packit |
fd8b60 |
com_err("cb", errno, "second sync pair");
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
printf("cb: waiting for final sync byte\n");
|
|
Packit |
fd8b60 |
if (read(arg->inpipe, &c, 1) < 0) {
|
|
Packit |
fd8b60 |
com_err("cb", errno, "final sync byte");
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
arg->done = 1;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Parent process: iterate over the KDB, using a callback that synchronizes
|
|
Packit |
fd8b60 |
* with the locking child. */
|
|
Packit |
fd8b60 |
static int
|
|
Packit |
fd8b60 |
iterator(struct cb_arg *cb_arg, char **db_args, pid_t child)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krb5_context ctx;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, &ctx;;
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_db_open(ctx, db_args,
|
|
Packit |
fd8b60 |
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_db_iterate(ctx, NULL, cb, cb_arg, 0);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_db_fini(ctx);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
krb5_free_context(ctx);
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
com_err("iterator", retval, "");
|
|
Packit |
fd8b60 |
kill(child, SIGTERM);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Helper function for locker(): write, then receive a sync byte. */
|
|
Packit |
fd8b60 |
static int
|
|
Packit |
fd8b60 |
syncpair_wr(const char *name, int inpipe, int outpipe, unsigned char *cp)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
printf("locker: writing %s sync pair\n", name);
|
|
Packit |
fd8b60 |
if (write(outpipe, cp, 1) < 0)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
printf("locker: waiting for %s sync pair\n", name);
|
|
Packit |
fd8b60 |
if (read(inpipe, cp, 1) < 0)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Child process: acquire and release a write lock on the KDB, synchronized
|
|
Packit |
fd8b60 |
* with parent. */
|
|
Packit |
fd8b60 |
static int
|
|
Packit |
fd8b60 |
locker(int inpipe, int outpipe, char **db_args)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
unsigned char c = '\0';
|
|
Packit |
fd8b60 |
krb5_context ctx;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, &ctx;;
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = krb5_db_open(ctx, db_args,
|
|
Packit |
fd8b60 |
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (syncpair_wr("first", inpipe, outpipe, &c) < 0) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
printf("locker: acquiring lock...\n");
|
|
Packit |
fd8b60 |
retval = krb5_db_lock(ctx, KRB5_DB_LOCKMODE_EXCLUSIVE);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
printf("locker: acquired lock\n");
|
|
Packit |
fd8b60 |
if (syncpair_wr("second", inpipe, outpipe, &c) < 0) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_db_unlock(ctx);
|
|
Packit |
fd8b60 |
printf("locker: released lock\n");
|
|
Packit |
fd8b60 |
printf("locker: writing final sync byte\n");
|
|
Packit |
fd8b60 |
if (write(outpipe, &c, 1) < 0) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto cleanup;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
retval = krb5_db_fini(ctx);
|
|
Packit |
fd8b60 |
cleanup:
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
com_err("locker", retval, "");
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_free_context(ctx);
|
|
Packit |
fd8b60 |
exit(retval != 0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
usage(const char *prog)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
fprintf(stderr, "usage: %s [-lu] [-t timeout]\n", prog);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int
|
|
Packit |
fd8b60 |
main(int argc, char *argv[])
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct cb_arg cb_arg;
|
|
Packit |
fd8b60 |
pid_t child;
|
|
Packit |
fd8b60 |
char *db_args[2] = { NULL, NULL };
|
|
Packit |
fd8b60 |
int c;
|
|
Packit |
fd8b60 |
int cstatus;
|
|
Packit |
fd8b60 |
int pipe_to_locker[2], pipe_to_iterator[2];
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cb_arg.timeout = 1;
|
|
Packit |
fd8b60 |
cb_arg.done = 0;
|
|
Packit |
fd8b60 |
while ((c = getopt(argc, argv, "lt:u")) != -1) {
|
|
Packit |
fd8b60 |
switch (c) {
|
|
Packit |
fd8b60 |
case 'l':
|
|
Packit |
fd8b60 |
db_args[0] = "lockiter";
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 't':
|
|
Packit |
fd8b60 |
cb_arg.timeout = atoi(optarg);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'u':
|
|
Packit |
fd8b60 |
db_args[0] = "unlockiter";
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
usage(argv[0]);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (pipe(pipe_to_locker) < 0) {
|
|
Packit |
fd8b60 |
com_err(argv[0], errno, "pipe(p_il)");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (pipe(pipe_to_iterator) < 0) {
|
|
Packit |
fd8b60 |
com_err(argv[0], errno, "pipe(p_li)");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
cb_arg.inpipe = pipe_to_iterator[0];
|
|
Packit |
fd8b60 |
cb_arg.outpipe = pipe_to_locker[1];
|
|
Packit |
fd8b60 |
child = fork();
|
|
Packit |
fd8b60 |
switch (child) {
|
|
Packit |
fd8b60 |
case -1:
|
|
Packit |
fd8b60 |
com_err(argv[0], errno, "fork");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 0:
|
|
Packit |
fd8b60 |
locker(pipe_to_locker[0], pipe_to_iterator[1], db_args);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
if (iterator(&cb_arg, db_args, child))
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
if (wait(&cstatus) < 0) {
|
|
Packit |
fd8b60 |
com_err(argv[0], errno, "wait");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (WIFSIGNALED(cstatus))
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
if (WIFEXITED(cstatus) && WEXITSTATUS(cstatus) != 0) {
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
exit(0);
|
|
Packit |
fd8b60 |
}
|