kstart-4.1/0000755000175000000000000000000011702213052007643 500000000000000kstart-4.1/framework.c0000644000175000000000000003100211702213030011714 00000000000000/* * Shared framework between k5start and krenew. * * Both k5start and krenew have a similar structure and sequence of actions: * * 1. Parse command-line options and initialize parameters. * 2. Do an initial authentication or ticket renewal, reporting errors. * 3. Run the aklog command, if any. * 4. Background and write out PID files if necessary. * 5. Spawn the external command, if any. * 6. If running a command or as a daemon, loop and reauthenticate as needed. * * They also support a variety of common options, such as how frequently to * wake up when running as a daemon, the aklog command, the happy ticket * handling, and so forth. * * This framework tries to handle all the shared code between the two * programs. It is configured via the options struct, which stores the shared * information between k5start and krenew. The code specific to one or the * other is handled via callbacks. * * Written by Russ Allbery * Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 * The Board of Trustees of the Leland Stanford Junior University * * See LICENSE for licensing terms. */ #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #include /* * The number of seconds of fudge to add to the check for whether we need to * obtain a new ticket. This is here to make sure that we don't wake up just * as the ticket is expiring. */ #define EXPIRE_FUDGE (2 * 60) /* * Set when the program receives SIGALRM, which indicates that it should wake * up immediately and reauthenticate. */ static volatile sig_atomic_t alarm_signaled = 0; /* * Set when the program receives SIGHUP or SIGTERM to do cleanup and exit. * These signal handlers are only used when we're not running a command, since * running a command provides its own signal handlers. */ static volatile sig_atomic_t exit_signaled = 0; /* * Convert from a string to a number, checking errors, and return -1 on any * error or for any negative number. This doesn't really belong here, but * it's a tiny function used by both k5start and krenew. */ long convert_number(const char *string, int base) { long number; char *end; errno = 0; number = strtol(string, &end, base); if (errno != 0 || *end != '\0') return -1; return number; } /* * Signal handler for SIGALRM. Just sets the global sentinel variable. */ static void alarm_handler(int s UNUSED) { alarm_signaled = 1; } /* * Signal handler for SIGHUP and SIGTERM. Just sets the global sentinel * variable. */ static void exit_handler(int s UNUSED) { exit_signaled = 1; } /* * Get the principal name for the krbtgt ticket for the local realm. The * caller is responsible for freeing the principal. Takes an existing * principal to get the realm from and returns a Kerberos error on failure. */ static krb5_error_code get_krbtgt_princ(krb5_context ctx, krb5_principal user, krb5_principal *princ) { const char *realm; realm = krb5_principal_get_realm(ctx, user); if (realm == NULL) return KRB5_CONFIG_NODEFREALM; return krb5_build_principal(ctx, princ, strlen(realm), realm, "krbtgt", realm, (const char *) NULL); } /* * Check whether a ticket will expire within the given number of minutes. * Takes the cache and the number of minutes. Returns a Kerberos status code * which will be 0 if the ticket won't expire, KRB5KRB_AP_ERR_TKT_EXPIRED if * it will expire and can be renewed, or another error code for any other * situation. * * Don't report any errors here, since k5start doesn't want to warn about any * of these problems. Just return the status code. krenew will separately * report an error if appropriate. */ static krb5_error_code ticket_expired(krb5_context ctx, struct config *config) { krb5_ccache ccache = NULL; krb5_creds increds, *outcreds = NULL; bool increds_valid = false; time_t now, then, offset; krb5_error_code code; /* Obtain the ticket. */ memset(&increds, 0, sizeof(increds)); code = krb5_cc_resolve(ctx, config->cache, &ccache); if (code != 0) goto done; if (config->client != NULL) increds.client = config->client; else { code = krb5_cc_get_principal(ctx, ccache, &increds.client); if (code != 0) goto done; } code = get_krbtgt_princ(ctx, increds.client, &increds.server); if (code != 0) goto done; code = krb5_get_credentials(ctx, 0, ccache, &increds, &outcreds); if (code != 0) goto done; increds_valid = true; /* Check the expiration time and renewal limit. */ if (code == 0) { now = time(NULL); then = outcreds->times.endtime; if (config->happy_ticket > 0) offset = 60 * config->happy_ticket; else offset = 60 * config->keep_ticket + EXPIRE_FUDGE; if (then < now + offset) code = KRB5KRB_AP_ERR_TKT_EXPIRED; /* * The error code for an inability to renew the ticket for long enough * is arbitrary. It just needs to be different than the error code * that indicates we can renew the ticket and coordinated with the * check in krenew's authentication callback. * * If the ticket is not going to expire, we skip this check. * Otherwise, krenew -H 1 would fail even if the ticket had plenty of * remaining lifespan if it was not renewable. */ if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) { then = outcreds->times.renew_till; if (then < now + offset) code = KRB5KDC_ERR_KEY_EXP; } } done: if (increds.client == config->client) increds.client = NULL; if (ccache != NULL) krb5_cc_close(ctx, ccache); if (increds_valid) krb5_free_cred_contents(ctx, &increds); else { if (increds.client != NULL) krb5_free_principal(ctx, increds.client); if (increds.server != NULL) krb5_free_principal(ctx, increds.server); } if (outcreds != NULL) krb5_free_creds(ctx, outcreds); return code; } /* * Write out a PID file given the path to the file and the PID to write. * Errors are reported but otherwise ignored. */ static void write_pidfile(const char *path, pid_t pid) { FILE *file; file = fopen(path, "w"); if (file == NULL) { syswarn("cannot create PID file %s", path); return; } if (fprintf(file, "%lu\n", (unsigned long) pid) < 0) syswarn("cannot write to PID file %s", path); if (fclose(file) == EOF) syswarn("cannot flush PID file %s", path); } /* * Add a signal handler, exiting if there was a failure. */ static void add_handler(krb5_context ctx, struct config *config, void (*handler)(int), int sig, const char *name) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; if (sigaction(sig, &sa, NULL) < 0) { syswarn("cannot set %s handler", name); exit_cleanup(ctx, config, 1); } } /* * The primary entry point of the framework. Both k5start and krenew call * this function after setting up the options and configuration to do the real * work. This function never returns. */ void run_framework(krb5_context ctx, struct config *config) { const char *aklog; krb5_error_code code = 0; pid_t child = 0; int result; int status = 0; /* Set aklog from AKLOG, KINIT_PROG, or the compiled-in default. */ aklog = getenv("AKLOG"); if (aklog == NULL) aklog = getenv("KINIT_PROG"); if (aklog == NULL) aklog = PATH_AKLOG; if (aklog[0] == '\0' && config->do_aklog) { warn("set AKLOG to specify the path to aklog"); exit_cleanup(ctx, config, 1); } /* * If built with setpag support and we're running a command, create the * new PAG now before the first authentication. */ if (config->command != NULL && config->do_aklog) { if (k_hasafs()) { if (k_setpag() < 0) { syswarn("unable to create PAG"); exit_cleanup(ctx, config, 1); } } else { warn("cannot create PAG: AFS support is not available"); exit_cleanup(ctx, config, 1); } } /* * Do the authentication once even if not necessary so that we can check * for any problems while we still have standard error. If -H wasn't set, * always authenticate. If -H was set, authenticate only if the ticket * isn't expired. */ if (config->happy_ticket == 0) code = config->auth(ctx, config, code); else { code = ticket_expired(ctx, config); if (code != 0) code = config->auth(ctx, config, code); } if (code != 0) status = 1; if (code != 0 && !config->ignore_errors) exit_cleanup(ctx, config, status); /* If requested, run the aklog program. */ if (config->do_aklog) command_run(aklog, config->verbose); /* * If told to background, background ourselves. We do this late so that * we can report initial errors. We have to do this before spawning the * command, though, since we want to background the command as well and * since otherwise we wouldn't be able to wait for the child process. */ if (config->background) daemon(0, 0); /* Write out the PID file. */ if (config->pidfile != NULL) write_pidfile(config->pidfile, getpid()); /* Spawn the external command, if we were told to run one. */ if (config->command != NULL) { child = command_start(config->command[0], config->command); if (child < 0) { syswarn("unable to run command %s", config->command[0]); exit_cleanup(ctx, config, 1); } if (config->keep_ticket == 0) config->keep_ticket = 60; if (config->childfile != NULL) write_pidfile(config->childfile, child); config->child = child; } /* Loop if we're running as a daemon. */ if (config->keep_ticket > 0) { struct timeval timeout; code = 0; add_handler(ctx, config, alarm_handler, SIGALRM, "SIGALRM"); if (config->command == NULL) { add_handler(ctx, config, exit_handler, SIGHUP, "SIGHUP"); add_handler(ctx, config, exit_handler, SIGTERM, "SIGTERM"); } while (1) { if (config->command != NULL) { result = command_finish(child, &status); if (result < 0) { syswarn("waitpid for %lu failed", (unsigned long) child); exit_cleanup(ctx, config, 1); } if (result > 0) { config->child = 0; break; } } timeout.tv_sec = (code == 0) ? config->keep_ticket * 60 : 60; timeout.tv_usec = 0; select(0, NULL, NULL, NULL, &timeout); if (exit_signaled) exit_cleanup(ctx, config, 0); code = ticket_expired(ctx, config); if (alarm_signaled || code != 0) { code = config->auth(ctx, config, code); if (code != 0 && config->exit_errors) exit_cleanup(ctx, config, 1); if (code == 0 && config->do_aklog) command_run(aklog, config->verbose); } alarm_signaled = 0; } } /* All done. */ exit_cleanup(ctx, config, status); } /* * Handles cleanup when exiting a program. This takes care of removing PID * files, destroying the ticket cache if desired, and so forth, and then calls * exit with the given status. */ void exit_cleanup(krb5_context ctx, struct config *config, int status) { krb5_error_code code; krb5_ccache ccache; if (config->cleanup != NULL) config->cleanup(ctx, config, status); if (config->clean_cache) { code = krb5_cc_resolve(ctx, config->cache, &ccache); if (code == 0) code = krb5_cc_destroy(ctx, ccache); if (code != 0) warn_krb5(ctx, code, "cannot destroy ticket cache"); } if (config->pidfile != NULL) unlink(config->pidfile); if (config->childfile != NULL) unlink(config->childfile); krb5_free_context(ctx); exit(status); } kstart-4.1/m4/0000755000175000000000000000000011702213052010163 500000000000000kstart-4.1/m4/lib-pathname.m40000644000175000000000000000514311702213030012705 00000000000000dnl Determine the library path name. dnl dnl Red Hat systems and some other Linux systems use lib64 and lib32 rather dnl than just lib in some circumstances. This file provides an Autoconf dnl macro, RRA_SET_LDFLAGS, which given a variable, a prefix, and an optional dnl suffix, adds -Lprefix/lib, -Lprefix/lib32, or -Lprefix/lib64 to the dnl variable depending on which directories exist and the size of a long in dnl the compilation environment. If a suffix is given, a slash and that dnl suffix will be appended, to allow for adding a subdirectory of the library dnl directory. dnl dnl This file also provides the Autoconf macro RRA_SET_LIBDIR, which sets the dnl libdir variable to PREFIX/lib{,32,64} as appropriate. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. dnl Probe for the alternate library name that we should attempt on this dnl architecture, given the size of an int, and set rra_lib_arch_name to that dnl name. Separated out so that it can be AC_REQUIRE'd and not run multiple dnl times. dnl dnl There is an unfortunate abstraction violation here where we assume we know dnl the cache variable name used by Autoconf. Unfortunately, Autoconf doesn't dnl provide any other way of getting at that information in shell that I can dnl see. AC_DEFUN([_RRA_LIB_ARCH_NAME], [rra_lib_arch_name=lib AC_CHECK_SIZEOF([long]) AS_IF([test "$ac_cv_sizeof_long" -eq 4 && test -d /usr/lib32], [rra_lib_arch_name=lib32], [AS_IF([test "$ac_cv_sizeof_long" -eq 8 && test -d /usr/lib64], [rra_lib_arch_name=lib64])])]) dnl Set VARIABLE to -LPREFIX/lib{,32,64} or -LPREFIX/lib{,32,64}/SUFFIX as dnl appropriate. AC_DEFUN([RRA_SET_LDFLAGS], [AC_REQUIRE([_RRA_LIB_ARCH_NAME]) AS_IF([test -d "$2/$rra_lib_arch_name"], [AS_IF([test x"$3" = x], [$1="[$]$1 -L$2/${rra_lib_arch_name}"], [$1="[$]$1 -L$2/${rra_lib_arch_name}/$3"])], [AS_IF([test x"$3" = x], [$1="[$]$1 -L$2/lib"], [$1="[$]$1 -L$2/lib/$3"])]) $1=`echo "[$]$1" | sed -e 's/^ *//'`]) dnl Set libdir to PREFIX/lib{,32,64} as appropriate. AC_DEFUN([RRA_SET_LIBDIR], [AC_REQUIRE([_RRA_LIB_ARCH_NAME]) AS_IF([test -d "$1/$rra_lib_arch_name"], [libdir="$1/${rra_lib_arch_name}"], [libdir="$1/lib"])]) kstart-4.1/m4/snprintf.m40000644000175000000000000000372711702213030012215 00000000000000dnl Test for a working C99 snprintf. dnl dnl Check for a working snprintf. Some systems have an snprintf that doesn't dnl nul-terminate if the buffer isn't large enough. Others return -1 if the dnl string doesn't fit into the buffer instead of returning the number of dnl characters that would have been formatted. Still others don't support dnl NULL as the buffer argument (just to get a count of the formatted length). dnl dnl Provides RRA_FUNC_SNPRINTF, which adds snprintf.o to LIBOBJS unless a dnl fully working snprintf is found. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2006, 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. dnl Source used by RRA_FUNC_SNPRINTF. AC_DEFUN([_RRA_FUNC_SNPRINTF_SOURCE], [[ #include #include char buf[2]; int test(char *format, ...) { va_list args; int count; va_start(args, format); count = vsnprintf(buf, sizeof buf, format, args); va_end(args); return count; } int main() { return ((test("%s", "abcd") == 4 && buf[0] == 'a' && buf[1] == '\0' && snprintf(NULL, 0, "%s", "abcd") == 4) ? 0 : 1); } ]]) dnl The user-callable test. AC_DEFUN([RRA_FUNC_SNPRINTF], [AC_CACHE_CHECK([for working snprintf], [rra_cv_func_snprintf_works], [AC_RUN_IFELSE([AC_LANG_SOURCE([_RRA_FUNC_SNPRINTF_SOURCE])], [rra_cv_func_snprintf_works=yes], [rra_cv_func_snprintf_works=no], [rra_cv_func_snprintf_works=no])]) AS_IF([test x"$rra_cv_func_snprintf_works" = xyes], [AC_DEFINE([HAVE_SNPRINTF], 1, [Define if your system has a working snprintf function.])], [AC_LIBOBJ([snprintf])])]) kstart-4.1/m4/lib-depends.m40000644000175000000000000000240511702213030012530 00000000000000dnl Provides option to change library probes. dnl dnl This file provides RRA_ENABLE_REDUCED_DEPENDS, which adds the configure dnl option --enable-reduced-depends to request that library probes assume dnl shared libraries are in use and dependencies of libraries should not be dnl probed. If this option is given, the shell variable rra_reduced_depends dnl is set to true; otherwise, it is set to false. dnl dnl This macro doesn't do much but is defined separately so that other macros dnl can require it with AC_REQUIRE. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2005, 2006, 2007 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. AC_DEFUN([RRA_ENABLE_REDUCED_DEPENDS], [rra_reduced_depends=false AC_ARG_ENABLE([reduced-depends], [AS_HELP_STRING([--enable-reduced-depends], [Try to minimize shared library dependencies])], [AS_IF([test x"$enableval" = xyes], [rra_reduced_depends=true])])]) kstart-4.1/m4/kafs.m40000644000175000000000000002430211702213030011266 00000000000000dnl Test for a libkafs library or replacement. dnl dnl Check for a working libkafs library, and if not present, check how we can dnl simulate what one would do ourselves, adding the appropriate things to dnl LIBOBJS. Provides the --with-libkafs configure option specify a dnl non-standard path to libkafs or (as --without-libkafs) to force use of the dnl internal implementation; --with-libkafs-include and --with-libkafs-lib to dnl specify paths at a more granular level; and --with-afs, dnl --with-afs-include, and --with-afs-lib configure options to specify the dnl location of the AFS libraries. dnl dnl Provides the macro RRA_LIB_KAFS and sets the substition variables dnl KAFS_CPPFLAGS, KAFS_LDFLAGS, and KAFS_LIBS. If Kerberos libraries may be dnl needed, LIBS and LDFLAGS must already be set appropriately before calling dnl this. Also provides RRA_LIB_KAFS_SWITCH to set CPPFLAGS, LDFLAGS, and dnl LIBS to include libkafs, saving the current values first, and dnl RRA_LIB_KAFS_RESTORE to restore those settings to before the last dnl RRA_LIB_KFS_SWITCH. dnl dnl Sets HAVE_K_HASAFS if the k_hasafs function was found in a libkafs dnl library. Sets HAVE_LSETPAG if building against the AFS libraries and the dnl lsetpag function is present. Sets HAVE_KAFS_REPLACEMENT if building the dnl replacement kafs library. Defines HAVE_KAFS_DARWIN8, HAVE_KAFS_DARWIN10, dnl HAVE_KAFS_LINUX, HAVE_KAFS_SOLARIS, or HAVE_KAFS_SYSCALL as appropriate if dnl the replacement kafs library is needed. dnl dnl If building a replacement library is needed, sets rra_build_kafs to true. dnl Otherwise, sets it to false. This is intended for use with an Automake dnl conditional, but the Automake conditional isn't set directly by this macro dnl since AFS support may be optional in the larger package. dnl dnl Depends on RRA_SET_LDFLAGS. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2008, 2009, 2010 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to dnl versions that include the libkafs flags. Used as a wrapper, with dnl RRA_LIB_KAFS_RESTORE, around tests. AC_DEFUN([RRA_LIB_KAFS_SWITCH], [rra_kafs_save_CPPFLAGS="$CPPFLAGS" rra_kafs_save_LDFLAGS="$LDFLAGS" rra_kafs_save_LIBS="$LIBS" CPPFLAGS="$KAFS_CPPFLAGS $CPPFLAGS" LDFLAGS="$KAFS_LDFLAGS $LDFLAGS" LIBS="$KAFS_LIBS $LIBS"]) dnl Restore CPPFLAGS, LDFLAGS, and LIBS to their previous values (before dnl RRA_LIB_KAFS_SWITCH was called). AC_DEFUN([RRA_LIB_KAFS_RESTORE], [CPPFLAGS="$rra_kafs_save_CPPFLAGS" LDFLAGS="$rra_kafs_save_LDFLAGS" LIBS="$rra_kafs_save_LIBS"]) dnl Set KAFS_CPPFLAGS and KAFS_LDFLAGS based on rra_kafs_root, dnl rra_kafs_libdir, rra_kafs_includedir, rra_afs_root, rra_afs_libdir, and dnl rra_afs_includedir. AC_DEFUN([_RRA_LIB_KAFS_PATHS], [KAFS_LDFLAGS= AS_IF([test x"$rra_kafs_libdir" != x], [KAFS_LDFLAGS="-L$rra_kafs_libdir"], [AS_IF([test x"$rra_kafs_root" != x], [RRA_SET_LDFLAGS([KAFS_LDFLAGS], [$rra_kafs_root])])]) AS_IF([test x"$rra_kafs_includedir" != x], [KAFS_CPPFLAGS="-I$rra_kafs_includedir"], [AS_IF([test x"$rra_kafs_root" != x], [AS_IF([test x"$rra_kafs_root" != x/usr], [KAFS_CPPFLAGS="-I${rra_kafs_root}/include"])])]) AS_IF([test x"$rra_afs_libdir" != x], [KAFS_LDFLAGS="$KAFS_LDFLAGS -L$rra_afs_libdir"], [AS_IF([test x"$rra_afs_root" != x], [RRA_SET_LDFLAGS([KAFS_LDFLAGS], [$rra_afs_root])]) RRA_SET_LDFLAGS([KAFS_LDFLAGS], [$rra_afs_root], [afs])]) AS_IF([test x"$rra_afs_includedir" != x], [KAFS_CPPFLAGS="-I$rra_afs_includedir"], [AS_IF([test x"$rra_afs_root" != x], [AS_IF([test x"$rra_afs_root" != x/usr], [KAFS_CPPFLAGS="$KAFS_CPPFLAGS -I${rra_afs_root}/include"])])])]) dnl Probe for lsetpag in the AFS libraries. This is required on AIX and IRIX dnl since we can't use the regular syscall interface there. AC_DEFUN([_RRA_LIB_KAFS_LSETPAG], [RRA_LIB_KAFS_SWITCH LIBS= AC_SEARCH_LIBS([pthread_getspecific], [pthread]) AC_SEARCH_LIBS([res_search], [resolv], [], [AC_SEARCH_LIBS([__res_search], [resolv])]) AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([socket], [socket], [], [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], [], [-lsocket])]) rra_kafs_extra="$LIBS" LIBS="$rra_kafs_save_LIBS" AC_CHECK_LIB([afsauthent], [lsetpag], [KAFS_LIBS="-lafsauthent -lafsrpc $rra_kafs_extra" AC_DEFINE([HAVE_LSETPAG], [1], [Define to 1 if you have the OpenAFS lsetpag function.])], [AC_CHECK_LIB([sys], [lsetpag], [KAFS_LIBS="-lsys $rra_kafs_extra" AC_DEFINE([HAVE_LSETPAG], [1], [Define to 1 if you have the OpenAFS lsetpag function.])], [], [$rra_kafs_extra])], [-lafsrpc $rra_kafs_extra]) AC_CHECK_HEADERS([afs/afssyscalls.h]) RRA_LIB_KAFS_RESTORE]) dnl The public entry point. Sets up the --with options and then decides what dnl to do based on the system. Either RRA_LIB_KRB5 or RRA_LIB_KRB5_OPTIONAL dnl must be called before this function or the Heimdal libkafs may not be dnl available. AC_DEFUN([RRA_LIB_KAFS], [AC_REQUIRE([AC_CANONICAL_HOST]) rra_libkafs=true rra_build_kafs=false KAFS_CPPFLAGS= KAFS_LDFLAGS= KAFS_LIBS= AC_SUBST([KAFS_CPPFLAGS]) AC_SUBST([KAFS_LDFLAGS]) AC_SUBST([KAFS_LIBS]) dnl In addition to the normal path-finding options, support --without-libkafs dnl to force always using the internal AFS syscall code. AC_ARG_WITH([libkafs], AC_HELP_STRING([--with-libkafs=DIR], [Location of kafs headers and libraries]), [AS_IF([test x"$withval" = xno], [rra_libkafs=false], [AS_IF([test x"$withval" != xyes], [rra_krb5_root="$withval"])])]) AC_ARG_WITH([libkafs-include], [AS_HELP_STRING([--with-libkafs-include=DIR], [Location of kafs headers])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_kafs_includedir="$withval"])]) AC_ARG_WITH([libkafs-lib], [AS_HELP_STRING([--with-libkafs-lib=DIR], [Location of kafs libraries])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_kafs_libdir="$withval"])]) dnl The location of the AFS headers and libraries. We may not use these dnl results, but configure always includes the prompt, so always handle them. dnl This should probably be in a separate macro file. AC_ARG_WITH([afs], [AC_HELP_STRING([--with-afs=DIR], [Location of AFS headers and libraries])], [AS_IF([test x"$withval" != xno && test x"$withval" != xyes], [rra_afs_root="$withval"])]) AC_ARG_WITH([afs-include], [AS_HELP_STRING([--with-afs-include=DIR], [Location of AFS headers])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_afs_includedir="$withval"])]) AC_ARG_WITH([afs-lib], [AS_HELP_STRING([--with-afs-lib=DIR], [Location of AFS libraries])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_afs_libdir="$withval"])]) dnl If we may use the system libkafs, see if we can find one. Enable the dnl Kerberos libraries if we found any, in case libkafs depends on Kerberos. AC_CHECK_HEADERS([sys/ioccom.h]) AS_IF([test x"$rra_libkafs" != xfalse], [_RRA_LIB_KAFS_PATHS AS_IF([test x"$rra_use_kerberos" = xtrue], [RRA_LIB_KRB5_SWITCH]) RRA_LIB_KAFS_SWITCH AC_CHECK_LIB([kafs], [k_hasafs], [KAFS_LIBS="-lkafs" AC_CHECK_HEADERS([kafs.h])], [AC_CHECK_LIB([kopenafs], [k_hasafs], [KAFS_LIBS="-lkopenafs" AC_CHECK_HEADERS([kopenafs.h])], [rra_libkafs=false])]) RRA_LIB_KAFS_RESTORE RRA_LIB_KAFS_SWITCH AC_CHECK_FUNCS([k_pioctl]) AC_REPLACE_FUNCS([k_haspag]) RRA_LIB_KAFS_RESTORE AS_IF([test x"$rra_use_kerberos" = xtrue], [RRA_LIB_KRB5_RESTORE])]) dnl If we found a libkafs, we have k_hasafs. Set the appropriate dnl preprocessor define. Otherwise, we'll use our portability layer. AS_IF([test x"$rra_libkafs" = xtrue], [AC_DEFINE([HAVE_K_HASAFS], 1, [Define to 1 if you have the k_hasafs function.])], [AC_LIBOBJ([k_haspag]) AS_CASE([$host], [[*-apple-darwin[89]*]], [rra_build_kafs=true AC_DEFINE([HAVE_KAFS_REPLACEMENT], [1], [Define to 1 if the libkafs replacement is built.]) AC_DEFINE([HAVE_KAFS_DARWIN8], [1], [Define to 1 to use the Mac OS X 10.4 /dev interface.])], [*-apple-darwin1*], [rra_build_kafs=true AC_DEFINE([HAVE_KAFS_REPLACEMENT], [1], [Define to 1 if the libkafs replacement is built.]) AC_DEFINE([HAVE_KAFS_DARWIN10], [1], [Define to 1 to use the Mac OS X 10.6 /dev interface.])], [*-aix*|*-irix*], [_RRA_LIB_KAFS_LSETPAG], [*-linux*], [rra_build_kafs=true AC_DEFINE([HAVE_KAFS_REPLACEMENT], [1], [Define to 1 if the libkafs replacement is built.]) AC_DEFINE([HAVE_KAFS_LINUX], [1], [Define to 1 to use the Linux AFS /proc interface.])], [[*-solaris2.1[12345678]*]], [rra_build_kafs=true AC_DEFINE([HAVE_KAFS_REPLACEMENT], [1], [Define to 1 if the libkafs replacement is built.]) AC_DEFINE([HAVE_KAFS_SOLARIS], [1], [Define to 1 to use the Solaris 11 /dev interface.]) AC_DEFINE([_REENTRANT], [1], [Define to 1 on Solaris for threaded errno handling.])], [*], [rra_build_kafs=true _RRA_LIB_KAFS_PATHS RRA_LIB_KAFS_SWITCH AC_CHECK_HEADERS([afs/param.h], [], [AC_MSG_ERROR([need afs/param.h to build libkafs replacement])]) RRA_LIB_KAFS_RESTORE AC_DEFINE([HAVE_KAFS_REPLACEMENT], [1], [Define to 1 if the libkafs replacement is built.]) AC_DEFINE([HAVE_KAFS_SYSCALL], [1], [Define to 1 to use the AFS syscall interface.]) AC_DEFINE([_REENTRANT], [1], [Define to 1 on Solaris for threaded errno handling.])])])]) kstart-4.1/m4/vamacros.m40000644000175000000000000000425311702213030012160 00000000000000dnl Check for support for variadic macros. dnl dnl This file defines two macros for probing for compiler support for variadic dnl macros. Provided are RRA_C_C99_VAMACROS, which checks for support for the dnl C99 variadic macro syntax, namely: dnl dnl #define macro(...) fprintf(stderr, __VA_ARGS__) dnl dnl and RRA_C_GNU_VAMACROS, which checks for support for the older GNU dnl variadic macro syntax, namely: dnl dnl #define macro(args...) fprintf(stderr, args) dnl dnl They set HAVE_C99_VAMACROS or HAVE_GNU_VAMACROS as appropriate. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2006, 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. AC_DEFUN([_RRA_C_C99_VAMACROS_SOURCE], [[ #include #define error(...) fprintf(stderr, __VA_ARGS__) int main(void) { error("foo"); error("foo %d", 0); return 0; } ]]) AC_DEFUN([RRA_C_C99_VAMACROS], [AC_CACHE_CHECK([for C99 variadic macros], [rra_cv_c_c99_vamacros], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_RRA_C_C99_VAMACROS_SOURCE])], [rra_cv_c_c99_vamacros=yes], [rra_cv_c_c99_vamacros=no])]) AS_IF([test x"$rra_cv_c_c99_vamacros" = xyes], [AC_DEFINE([HAVE_C99_VAMACROS], 1, [Define if the compiler supports C99 variadic macros.])])]) AC_DEFUN([_RRA_C_GNU_VAMACROS_SOURCE], [[ #include #define error(args...) fprintf(stderr, args) int main(void) { error("foo"); error("foo %d", 0); return 0; } ]]) AC_DEFUN([RRA_C_GNU_VAMACROS], [AC_CACHE_CHECK([for GNU-style variadic macros], [rra_cv_c_gnu_vamacros], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_RRA_C_GNU_VAMACROS_SOURCE])], [rra_cv_c_gnu_vamacros=yes], [rra_cv_c_gnu_vamacros=no])]) AS_IF([test x"$rra_cv_c_gnu_vamacros" = xyes], [AC_DEFINE([HAVE_GNU_VAMACROS], 1, [Define if the compiler supports GNU-style variadic macros.])])]) kstart-4.1/m4/krb5.m40000644000175000000000000003401511702213030011207 00000000000000dnl Find the compiler and linker flags for Kerberos. dnl dnl Finds the compiler and linker flags for linking with Kerberos libraries. dnl Provides the --with-krb5, --with-krb5-include, and --with-krb5-lib dnl configure options to specify non-standard paths to the Kerberos libraries. dnl Uses krb5-config where available unless reduced dependencies is requested dnl or --with-krb5-include or --with-krb5-lib are given. dnl dnl Provides the macro RRA_LIB_KRB5 and sets the substitution variables dnl KRB5_CPPFLAGS, KRB5_LDFLAGS, and KRB5_LIBS. Also provides dnl RRA_LIB_KRB5_SWITCH to set CPPFLAGS, LDFLAGS, and LIBS to include the dnl Kerberos libraries, saving the current values first, and dnl RRA_LIB_KRB5_RESTORE to restore those settings to before the last dnl RRA_LIB_KRB5_SWITCH. HAVE_KERBEROS will always be defined if RRA_LIB_KRB5 dnl is used. dnl dnl If KRB5_CPPFLAGS, KRB5_LDFLAGS, or KRB5_LIBS are set before calling these dnl macros, their values will be added to whatever the macros discover. dnl dnl Provides the RRA_LIB_KRB5_OPTIONAL macro, which should be used if Kerberos dnl support is optional. This macro will still always set the substitution dnl variables, but they'll be empty unless --with-krb5 is given. Also, dnl HAVE_KERBEROS will be defined if --with-krb5 is given and dnl $rra_use_kerberos will be set to "true". dnl dnl Sets the Automake conditional KRB5_USES_COM_ERR saying whether we use dnl com_err, since if we're also linking with AFS libraries, we may have to dnl change library ordering in that case. dnl dnl Depends on RRA_ENABLE_REDUCED_DEPENDS and RRA_SET_LDFLAGS. dnl dnl Also provides RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS, which checks dnl whether krb5_get_init_creds_opt_free takes one argument or two. Defines dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments. dnl dnl Also provides RRA_INCLUDES_KRB5, which are the headers to include when dnl probing the Kerberos library properties. dnl dnl The canonical version of this file is maintained in the rra-c-util dnl package, available at . dnl dnl Written by Russ Allbery dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 dnl The Board of Trustees of the Leland Stanford Junior University dnl dnl This file is free software; the authors give unlimited permission to copy dnl and/or distribute it, with or without modifications, as long as this dnl notice is preserved. dnl Headers to include when probing for Kerberos library properties. AC_DEFUN([RRA_INCLUDES_KRB5], [[ #if HAVE_KRB5_H # include #else # include #endif ]]) dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to dnl versions that include the Kerberos flags. Used as a wrapper, with dnl RRA_LIB_KRB5_RESTORE, around tests. AC_DEFUN([RRA_LIB_KRB5_SWITCH], [rra_krb5_save_CPPFLAGS="$CPPFLAGS" rra_krb5_save_LDFLAGS="$LDFLAGS" rra_krb5_save_LIBS="$LIBS" CPPFLAGS="$KRB5_CPPFLAGS $CPPFLAGS" LDFLAGS="$KRB5_LDFLAGS $LDFLAGS" LIBS="$KRB5_LIBS $LIBS"]) dnl Restore CPPFLAGS, LDFLAGS, and LIBS to their previous values (before dnl RRA_LIB_KRB5_SWITCH was called). AC_DEFUN([RRA_LIB_KRB5_RESTORE], [CPPFLAGS="$rra_krb5_save_CPPFLAGS" LDFLAGS="$rra_krb5_save_LDFLAGS" LIBS="$rra_krb5_save_LIBS"]) dnl Set KRB5_CPPFLAGS and KRB5_LDFLAGS based on rra_krb5_root, dnl rra_krb5_libdir, and rra_krb5_includedir. AC_DEFUN([_RRA_LIB_KRB5_PATHS], [AS_IF([test x"$rra_krb5_libdir" != x], [KRB5_LDFLAGS="-L$rra_krb5_libdir"], [AS_IF([test x"$rra_krb5_root" != x], [RRA_SET_LDFLAGS([KRB5_LDFLAGS], [$rra_krb5_root])])]) AS_IF([test x"$rra_krb5_includedir" != x], [KRB5_CPPFLAGS="-I$rra_krb5_includedir"], [AS_IF([test x"$rra_krb5_root" != x], [AS_IF([test x"$rra_krb5_root" != x/usr], [KRB5_CPPFLAGS="-I${rra_krb5_root}/include"])])])]) dnl Does the appropriate library checks for reduced-dependency Kerberos dnl linkage. The single argument, if true, says to fail if Kerberos could not dnl be found. AC_DEFUN([_RRA_LIB_KRB5_REDUCED], [RRA_LIB_KRB5_SWITCH AC_CHECK_LIB([krb5], [krb5_init_context], [KRB5_LIBS="-lkrb5"], [AS_IF([test x"$1" = xtrue], [AC_MSG_ERROR([cannot find usable Kerberos library])])]) LIBS="$KRB5_LIBS $LIBS" AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) AC_CHECK_FUNCS([krb5_get_error_message], [AC_CHECK_FUNCS([krb5_free_error_message])], [AC_CHECK_FUNCS([krb5_get_error_string], [], [AC_CHECK_FUNCS([krb5_get_err_txt], [], [AC_CHECK_LIB([ksvc], [krb5_svc_get_msg], [KRB5_LIBS="$KRB5_LIBS -lksvc" AC_DEFINE([HAVE_KRB5_SVC_GET_MSG], [1]) AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], [RRA_INCLUDES_KRB5])], [AC_CHECK_LIB([com_err], [com_err], [KRB5_LIBS="$KRB5_LIBS -lcom_err"], [AC_MSG_ERROR([cannot find usable com_err library])]) AC_CHECK_HEADERS([et/com_err.h])])])])]) RRA_LIB_KRB5_RESTORE]) dnl Does the appropriate library checks for Kerberos linkage when we don't dnl have krb5-config or reduced dependencies. The single argument, if true, dnl says to fail if Kerberos could not be found. AC_DEFUN([_RRA_LIB_KRB5_MANUAL], [RRA_LIB_KRB5_SWITCH rra_krb5_extra= LIBS= AC_SEARCH_LIBS([res_search], [resolv], [], [AC_SEARCH_LIBS([__res_search], [resolv])]) AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([socket], [socket], [], [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], [], [-lsocket])]) AC_SEARCH_LIBS([crypt], [crypt]) AC_SEARCH_LIBS([rk_simple_execve], [roken]) rra_krb5_extra="$LIBS" LIBS="$rra_krb5_save_LIBS" AC_CHECK_LIB([krb5], [krb5_init_context], [KRB5_LIBS="-lkrb5 -lasn1 -lcom_err -lcrypto $rra_krb5_extra"], [AC_CHECK_LIB([krb5support], [krb5int_getspecific], [rra_krb5_extra="-lkrb5support $rra_krb5_extra"], [AC_CHECK_LIB([pthreads], [pthread_setspecific], [rra_krb5_pthread="-lpthreads"], [AC_CHECK_LIB([pthread], [pthread_setspecific], [rra_krb5_pthread="-lpthread"])]) AC_CHECK_LIB([krb5support], [krb5int_setspecific], [rra_krb5_extra="-lkrb5support $rra_krb5_extra $rra_krb5_pthread"], [], [$rra_krb5_pthread $rra_krb5_extra])], [$rra_krb5_extra]) AC_CHECK_LIB([com_err], [error_message], [rra_krb5_extra="-lcom_err $rra_krb5_extra"], [], [$rra_krb5_extra]) AC_CHECK_LIB([ksvc], [krb5_svc_get_msg], [rra_krb5_extra="-lksvc $rra_krb5_extra"], [], [$rra_krb5_extra]) AC_CHECK_LIB([k5crypto], [krb5int_hash_md5], [rra_krb5_extra="-lk5crypto $rra_krb5_extra"], [], [$rra_krb5_extra]) AC_CHECK_LIB([k5profile], [profile_get_values], [rra_krb5_extra="-lk5profile $rra_krb5_extra"], [], [$rra_krb5_extra]) AC_CHECK_LIB([krb5], [krb5_cc_default], [KRB5_LIBS="-lkrb5 $rra_krb5_extra"], [AS_IF([test x"$1" = xtrue], [AC_MSG_ERROR([cannot find usable Kerberos library])])], [$rra_krb5_extra])], [-lasn1 -lcom_err -lcrypto $rra_krb5_extra]) LIBS="$KRB5_LIBS $LIBS" AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) AC_CHECK_FUNCS([krb5_get_error_message], [AC_CHECK_FUNCS([krb5_free_error_message])], [AC_CHECK_FUNCS([krb5_get_error_string], [], [AC_CHECK_FUNCS([krb5_get_err_txt], [], [AC_CHECK_FUNCS([krb5_svc_get_msg], [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], [RRA_INCLUDES_KRB5])], [AC_CHECK_HEADERS([et/com_err.h])])])])]) RRA_LIB_KRB5_RESTORE]) dnl Sanity-check the results of krb5-config and be sure we can really link a dnl Kerberos program. If that fails, clear KRB5_CPPFLAGS and KRB5_LIBS so dnl that we know we don't have usable flags and fall back on the manual dnl check. AC_DEFUN([_RRA_LIB_KRB5_CHECK], [RRA_LIB_KRB5_SWITCH AC_CHECK_FUNC([krb5_init_context], [RRA_LIB_KRB5_RESTORE], [RRA_LIB_KRB5_RESTORE KRB5_CPPFLAGS= KRB5_LIBS= _RRA_LIB_KRB5_PATHS _RRA_LIB_KRB5_MANUAL([$1])])]) dnl Determine Kerberos compiler and linker flags from krb5-config. Does the dnl additional probing we need to do to uncover error handling features, and dnl falls back on the manual checks. AC_DEFUN([_RRA_LIB_KRB5_CONFIG], [AC_ARG_VAR([PATH_KRB5_CONFIG], [Path to krb5-config]) AS_IF([test x"$rra_krb5_root" != x && test -z "$PATH_KRB5_CONFIG"], [AS_IF([test -x "${rra_krb5_root}/bin/krb5-config"], [PATH_KRB5_CONFIG="${rra_krb5_root}/bin/krb5-config"])], [AC_PATH_PROG([PATH_KRB5_CONFIG], [krb5-config], [], [${PATH}:/usr/kerberos/bin])]) AS_IF([test x"$PATH_KRB5_CONFIG" != x && test -x "$PATH_KRB5_CONFIG"], [AC_CACHE_CHECK([for krb5 support in krb5-config], [rra_cv_lib_krb5_config], [AS_IF(["$PATH_KRB5_CONFIG" 2>&1 | grep krb5 >/dev/null 2>&1], [rra_cv_lib_krb5_config=yes], [rra_cv_lib_krb5_config=no])]) AS_IF([test x"$rra_cv_lib_krb5_config" = xyes], [KRB5_CPPFLAGS=`"$PATH_KRB5_CONFIG" --cflags krb5 2>/dev/null` KRB5_LIBS=`"$PATH_KRB5_CONFIG" --libs krb5 2>/dev/null`], [KRB5_CPPFLAGS=`"$PATH_KRB5_CONFIG" --cflags 2>/dev/null` KRB5_LIBS=`"$PATH_KRB5_CONFIG" --libs 2>/dev/null`]) KRB5_CPPFLAGS=`echo "$KRB5_CPPFLAGS" | sed 's%-I/usr/include %%'` KRB5_CPPFLAGS=`echo "$KRB5_CPPFLAGS" | sed 's%-I/usr/include$%%'` _RRA_LIB_KRB5_CHECK([$1]) RRA_LIB_KRB5_SWITCH AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) AC_CHECK_FUNCS([krb5_get_error_message], [AC_CHECK_FUNCS([krb5_free_error_message])], [AC_CHECK_FUNCS([krb5_get_error_string], [], [AC_CHECK_FUNCS([krb5_get_err_txt], [], [AC_CHECK_FUNCS([krb5_svc_get_msg], [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], [RRA_INCLUDES_KRB5])], [AC_CHECK_HEADERS([et/com_err.h])])])])]) RRA_LIB_KRB5_RESTORE], [_RRA_LIB_KRB5_PATHS _RRA_LIB_KRB5_MANUAL([$1])])]) dnl The core of the library checking, shared between RRA_LIB_KRB5 and dnl RRA_LIB_KRB5_OPTIONAL. The single argument, if "true", says to fail if dnl Kerberos could not be found. AC_DEFUN([_RRA_LIB_KRB5_INTERNAL], [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) AS_IF([test x"$rra_reduced_depends" = xtrue], [_RRA_LIB_KRB5_PATHS _RRA_LIB_KRB5_REDUCED([$1])], [AS_IF([test x"$rra_krb5_includedir" = x && test x"$rra_krb5_libdir" = x], [_RRA_LIB_KRB5_CONFIG([$1])], [_RRA_LIB_KRB5_PATHS _RRA_LIB_KRB5_MANUAL([$1])])]) rra_krb5_uses_com_err=false AS_CASE([$LIBS], [*-lcom_err*], [rra_krb5_uses_com_err=true]) AM_CONDITIONAL([KRB5_USES_COM_ERR], [test x"$rra_krb5_uses_com_err" = xtrue])]) dnl The main macro for packages with mandatory Kerberos support. AC_DEFUN([RRA_LIB_KRB5], [rra_krb5_root= rra_krb5_libdir= rra_krb5_includedir= rra_use_kerberos=true AC_SUBST([KRB5_CPPFLAGS]) AC_SUBST([KRB5_LDFLAGS]) AC_SUBST([KRB5_LIBS]) AC_ARG_WITH([krb5], [AS_HELP_STRING([--with-krb5=DIR], [Location of Kerberos headers and libraries])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_krb5_root="$withval"])]) AC_ARG_WITH([krb5-include], [AS_HELP_STRING([--with-krb5-include=DIR], [Location of Kerberos headers])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_krb5_includedir="$withval"])]) AC_ARG_WITH([krb5-lib], [AS_HELP_STRING([--with-krb5-lib=DIR], [Location of Kerberos libraries])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_krb5_libdir="$withval"])]) _RRA_LIB_KRB5_INTERNAL([true]) AC_DEFINE([HAVE_KERBEROS], 1, [Define to enable Kerberos features.])]) dnl The main macro for packages with optional Kerberos support. AC_DEFUN([RRA_LIB_KRB5_OPTIONAL], [rra_krb5_root= rra_krb5_libdir= rra_krb5_includedir= rra_use_kerberos= AC_SUBST([KRB5_CPPFLAGS]) AC_SUBST([KRB5_LDFLAGS]) AC_SUBST([KRB5_LIBS]) AC_ARG_WITH([krb5], [AS_HELP_STRING([--with-krb5@<:@=DIR@:>@], [Location of Kerberos headers and libraries])], [AS_IF([test x"$withval" = xno], [rra_use_kerberos=false], [AS_IF([test x"$withval" != xyes], [rra_krb5_root="$withval"]) rra_use_kerberos=true])]) AC_ARG_WITH([krb5-include], [AS_HELP_STRING([--with-krb5-include=DIR], [Location of Kerberos headers])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_krb5_includedir="$withval"])]) AC_ARG_WITH([krb5-lib], [AS_HELP_STRING([--with-krb5-lib=DIR], [Location of Kerberos libraries])], [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], [rra_krb5_libdir="$withval"])]) AS_IF([test x"$rra_use_kerberos" != xfalse], [AS_IF([test x"$rra_use_kerberos" = xtrue], [_RRA_LIB_KRB5_INTERNAL([true])], [_RRA_LIB_KRB5_INTERNAL([false])])], [AM_CONDITIONAL([KRB5_USES_COM_ERR], [false])]) AS_IF([test x"$KRB5_LIBS" != x], [AC_DEFINE([HAVE_KERBEROS], 1, [Define to enable Kerberos features.])])]) dnl Source used by RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS. AC_DEFUN([_RRA_FUNC_KRB5_OPT_FREE_ARGS_SOURCE], [RRA_INCLUDES_KRB5] [[ int main(void) { krb5_get_init_creds_opt *opts; krb5_context c; krb5_get_init_creds_opt_free(c, opts); } ]]) dnl Check whether krb5_get_init_creds_opt_free takes one argument or two. dnl Early Heimdal used to take a single argument. Defines dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments. dnl dnl Should be called with RRA_LIB_KRB5_SWITCH active. AC_DEFUN([RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS], [AC_CACHE_CHECK([if krb5_get_init_creds_opt_free takes two arguments], [rra_cv_func_krb5_get_init_creds_opt_free_args], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_RRA_FUNC_KRB5_OPT_FREE_ARGS_SOURCE])], [rra_cv_func_krb5_get_init_creds_opt_free_args=yes], [rra_cv_func_krb5_get_init_creds_opt_free_args=no])]) AS_IF([test $rra_cv_func_krb5_get_init_creds_opt_free_args = yes], [AC_DEFINE([HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS], 1, [Define if krb5_get_init_creds_opt_free takes two arguments.])])]) kstart-4.1/tests/0000755000175000000000000000000011702213052011005 500000000000000kstart-4.1/tests/libtest.pl0000644000175000000000000000613111702213030012725 00000000000000# Shared Perl functions for tests. # # Collects a set of useful utility functions for tests, used by the Perl test # suite programs. These are intentionally put into the main package rather # than in a separate namespace. # # Written by Russ Allbery # Copyright 2007, 2008, 2009 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. require 5.006; use strict; use Test::More; # Make a call to a command with the given arguments. Returns the standard # output, the standard error, and the exit status as a list. sub command { my ($command, @args) = @_; my $pid = fork; if (not defined $pid) { BAIL_OUT ("cannot fork: $!"); } elsif ($pid == 0) { open (STDOUT, '>', 'command.out') or BAIL_OUT ("cannot create command.out: $!"); open (STDERR, '>', 'command.err') or BAIL_OUT ("cannot create command.err: $!"); exec ($command, @args) or BAIL_OUT ("cannot run $command: $!"); } else { waitpid ($pid, 0); } my $status = ($? >> 8); local $/; open (OUT, '<', 'command.out') or BAIL_OUT ("cannot open command.out: $!"); my $output = ; close OUT; open (ERR, '<', 'command.err') or BAIL_OUT ("cannot open command.err: $!"); my $error = ; close ERR; unlink ('command.out', 'command.err'); return ($output, $error, $status); } # Returns the one-line contents of a file as a string, removing the newline. sub contents { my ($file) = @_; open (FILE, '<', $file) or BAIL_OUT ("cannot open $file: $!"); my $data = ; close FILE; chomp $data; return $data; } # Given a keytab file, a principal, and additional options for kinit, try # authenticating with kinit. This is used to do things like get renewable # tickets. Returns true if successful, false otherwise. sub kinit { my ($file, $principal, @opts) = @_; my @commands = ( "kinit -k -t $file @opts $principal ", "kinit -t $file @opts $principal ", "kinit -T /bin/true -k -K $file @opts $principal", ); for my $command (@commands) { if (system ("$command >/dev/null 2>&1 &1`; return unless $? == 0; my ($default) = ($output =~ /^(?:Default p|\s*P)rincipal: (\S+)/m); my ($service) = ($output =~ / Service principal\n(?:\S+\s+){4}(\S+)/); unless ($service) { ($service) = ($output =~ / Principal\n(?:\S+\s+){7}(\S+)/); } my ($flags) = ($output =~ /\sFlags: (\S+)/); unless ($flags) { ($flags) = ($output =~ / Flags\s+Principal\n(?:\S+\s+){6}(\S+)/); } return ($default, $service, $flags); } # Run tokens and return true if we have an AFS token, false otherwise. sub tokens { my $output = `tokens 2>&1`; return unless $? == 0; return ($output =~ /^(User\'s \([^\)]+\) )?[Tt]okens for /m) ? 1 : 0; } kstart-4.1/tests/runtests.c0000644000175000000000000010747411702213030012771 00000000000000/* * Run a set of tests, reporting results. * * Usage: * * runtests [-b ] [-s ] * runtests -o [-b ] [-s ] * * In the first case, expects a list of executables located in the given file, * one line per executable. For each one, runs it as part of a test suite, * reporting results. Test output should start with a line containing the * number of tests (numbered from 1 to this number), optionally preceded by * "1..", although that line may be given anywhere in the output. Each * additional line should be in the following format: * * ok * not ok * ok # skip * not ok # todo * * where is the number of the test. An optional comment is permitted * after the number if preceded by whitespace. ok indicates success, not ok * indicates failure. "# skip" and "# todo" are a special cases of a comment, * and must start with exactly that formatting. They indicate the test was * skipped for some reason (maybe because it doesn't apply to this platform) * or is testing something known to currently fail. The text following either * "# skip" or "# todo" and whitespace is the reason. * * As a special case, the first line of the output may be in the form: * * 1..0 # skip some reason * * which indicates that this entire test case should be skipped and gives a * reason. * * Any other lines are ignored, although for compliance with the TAP protocol * all lines other than the ones in the above format should be sent to * standard error rather than standard output and start with #. * * This is a subset of TAP as documented in Test::Harness::TAP or * TAP::Parser::Grammar, which comes with Perl. * * If the -o option is given, instead run a single test and display all of its * output. This is intended for use with failing tests so that the person * running the test suite can get more details about what failed. * * If built with the C preprocessor symbols SOURCE and BUILD defined, C TAP * Harness will export those values in the environment so that tests can find * the source and build directory and will look for tests under both * directories. These paths can also be set with the -b and -s command-line * options, which will override anything set at build time. * * Any bug reports, bug fixes, and improvements are very much welcome and * should be sent to the e-mail address below. This program is part of C TAP * Harness . * * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011 * Russ Allbery * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* Required for fdopen(), getopt(), and putenv(). */ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* sys/time.h must be included before sys/resource.h on some platforms. */ #include /* AIX doesn't have WCOREDUMP. */ #ifndef WCOREDUMP # define WCOREDUMP(status) ((unsigned)(status) & 0x80) #endif /* * The source and build versions of the tests directory. This is used to set * the SOURCE and BUILD environment variables and find test programs, if set. * Normally, this should be set as part of the build process to the test * subdirectories of $(abs_top_srcdir) and $(abs_top_builddir) respectively. */ #ifndef SOURCE # define SOURCE NULL #endif #ifndef BUILD # define BUILD NULL #endif /* Test status codes. */ enum test_status { TEST_FAIL, TEST_PASS, TEST_SKIP, TEST_INVALID }; /* Indicates the state of our plan. */ enum plan_status { PLAN_INIT, /* Nothing seen yet. */ PLAN_FIRST, /* Plan seen before any tests. */ PLAN_PENDING, /* Test seen and no plan yet. */ PLAN_FINAL /* Plan seen after some tests. */ }; /* Error exit statuses for test processes. */ #define CHILDERR_DUP 100 /* Couldn't redirect stderr or stdout. */ #define CHILDERR_EXEC 101 /* Couldn't exec child process. */ #define CHILDERR_STDERR 102 /* Couldn't open stderr file. */ /* Structure to hold data for a set of tests. */ struct testset { char *file; /* The file name of the test. */ char *path; /* The path to the test program. */ enum plan_status plan; /* The status of our plan. */ unsigned long count; /* Expected count of tests. */ unsigned long current; /* The last seen test number. */ unsigned int length; /* The length of the last status message. */ unsigned long passed; /* Count of passing tests. */ unsigned long failed; /* Count of failing lists. */ unsigned long skipped; /* Count of skipped tests (passed). */ unsigned long allocated; /* The size of the results table. */ enum test_status *results; /* Table of results by test number. */ unsigned int aborted; /* Whether the set as aborted. */ int reported; /* Whether the results were reported. */ int status; /* The exit status of the test. */ unsigned int all_skipped; /* Whether all tests were skipped. */ char *reason; /* Why all tests were skipped. */ }; /* Structure to hold a linked list of test sets. */ struct testlist { struct testset *ts; struct testlist *next; }; /* * Usage message. Should be used as a printf format with two arguments: the * path to runtests, given twice. */ static const char usage_message[] = "\ Usage: %s [-b ] [-s ] \n\ %s -o [-b ] [-s ] \n\ \n\ Options:\n\ -b Set the build directory to \n\ -o Run a single test rather than a list of tests\n\ -s Set the source directory to \n\ \n\ runtests normally runs each test listed in a file whose path is given as\n\ its command-line argument. With the -o option, it instead runs a single\n\ test and shows its complete output.\n"; /* * Header used for test output. %s is replaced by the file name of the list * of tests. */ static const char banner[] = "\n\ Running all tests listed in %s. If any tests fail, run the failing\n\ test program with runtests -o to see more details.\n\n"; /* Header for reports of failed tests. */ static const char header[] = "\n\ Failed Set Fail/Total (%) Skip Stat Failing Tests\n\ -------------------------- -------------- ---- ---- ------------------------"; /* Include the file name and line number in malloc failures. */ #define xmalloc(size) x_malloc((size), __FILE__, __LINE__) #define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__) #define xstrdup(p) x_strdup((p), __FILE__, __LINE__) /* * Report a fatal error, including the results of strerror, and exit. */ static void sysdie(const char *format, ...) { int oerrno; va_list args; oerrno = errno; fflush(stdout); fprintf(stderr, "runtests: "); va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr, ": %s\n", strerror(oerrno)); exit(1); } /* * Allocate memory, reporting a fatal error and exiting on failure. */ static void * x_malloc(size_t size, const char *file, int line) { void *p; p = malloc(size); if (p == NULL) sysdie("failed to malloc %lu bytes at %s line %d", (unsigned long) size, file, line); return p; } /* * Reallocate memory, reporting a fatal error and exiting on failure. */ static void * x_realloc(void *p, size_t size, const char *file, int line) { p = realloc(p, size); if (p == NULL) sysdie("failed to realloc %lu bytes at %s line %d", (unsigned long) size, file, line); return p; } /* * Copy a string, reporting a fatal error and exiting on failure. */ static char * x_strdup(const char *s, const char *file, int line) { char *p; size_t len; len = strlen(s) + 1; p = malloc(len); if (p == NULL) sysdie("failed to strdup %lu bytes at %s line %d", (unsigned long) len, file, line); memcpy(p, s, len); return p; } /* * Given a struct timeval, return the number of seconds it represents as a * double. Use difftime() to convert a time_t to a double. */ static double tv_seconds(const struct timeval *tv) { return difftime(tv->tv_sec, 0) + tv->tv_usec * 1e-6; } /* * Given two struct timevals, return the difference in seconds. */ static double tv_diff(const struct timeval *tv1, const struct timeval *tv0) { return tv_seconds(tv1) - tv_seconds(tv0); } /* * Given two struct timevals, return the sum in seconds as a double. */ static double tv_sum(const struct timeval *tv1, const struct timeval *tv2) { return tv_seconds(tv1) + tv_seconds(tv2); } /* * Given a pointer to a string, skip any leading whitespace and return a * pointer to the first non-whitespace character. */ static const char * skip_whitespace(const char *p) { while (isspace((unsigned char)(*p))) p++; return p; } /* * Start a program, connecting its stdout to a pipe on our end and its stderr * to /dev/null, and storing the file descriptor to read from in the two * argument. Returns the PID of the new process. Errors are fatal. */ static pid_t test_start(const char *path, int *fd) { int fds[2], errfd; pid_t child; if (pipe(fds) == -1) { puts("ABORTED"); fflush(stdout); sysdie("can't create pipe"); } child = fork(); if (child == (pid_t) -1) { puts("ABORTED"); fflush(stdout); sysdie("can't fork"); } else if (child == 0) { /* In child. Set up our stdout and stderr. */ errfd = open("/dev/null", O_WRONLY); if (errfd < 0) _exit(CHILDERR_STDERR); if (dup2(errfd, 2) == -1) _exit(CHILDERR_DUP); close(fds[0]); if (dup2(fds[1], 1) == -1) _exit(CHILDERR_DUP); /* Now, exec our process. */ if (execl(path, path, (char *) 0) == -1) _exit(CHILDERR_EXEC); } else { /* In parent. Close the extra file descriptor. */ close(fds[1]); } *fd = fds[0]; return child; } /* * Back up over the output saying what test we were executing. */ static void test_backspace(struct testset *ts) { unsigned int i; if (!isatty(STDOUT_FILENO)) return; for (i = 0; i < ts->length; i++) putchar('\b'); for (i = 0; i < ts->length; i++) putchar(' '); for (i = 0; i < ts->length; i++) putchar('\b'); ts->length = 0; } /* * Read the plan line of test output, which should contain the range of test * numbers. We may initialize the testset structure here if we haven't yet * seen a test. Return true if initialization succeeded and the test should * continue, false otherwise. */ static int test_plan(const char *line, struct testset *ts) { unsigned long i; long n; /* * Accept a plan without the leading 1.. for compatibility with older * versions of runtests. This will only be allowed if we've not yet seen * a test result. */ line = skip_whitespace(line); if (strncmp(line, "1..", 3) == 0) line += 3; /* * Get the count, check it for validity, and initialize the struct. If we * have something of the form "1..0 # skip foo", the whole file was * skipped; record that. If we do skip the whole file, zero out all of * our statistics, since they're no longer relevant. strtol is called * with a second argument to advance the line pointer past the count to * make it simpler to detect the # skip case. */ n = strtol(line, (char **) &line, 10); if (n == 0) { line = skip_whitespace(line); if (*line == '#') { line = skip_whitespace(line + 1); if (strncasecmp(line, "skip", 4) == 0) { line = skip_whitespace(line + 4); if (*line != '\0') { ts->reason = xstrdup(line); ts->reason[strlen(ts->reason) - 1] = '\0'; } ts->all_skipped = 1; ts->aborted = 1; ts->count = 0; ts->passed = 0; ts->skipped = 0; ts->failed = 0; return 0; } } } if (n <= 0) { puts("ABORTED (invalid test count)"); ts->aborted = 1; ts->reported = 1; return 0; } if (ts->plan == PLAN_INIT && ts->allocated == 0) { ts->count = n; ts->allocated = n; ts->plan = PLAN_FIRST; ts->results = xmalloc(ts->count * sizeof(enum test_status)); for (i = 0; i < ts->count; i++) ts->results[i] = TEST_INVALID; } else if (ts->plan == PLAN_PENDING) { if ((unsigned long) n < ts->count) { printf("ABORTED (invalid test number %lu)\n", ts->count); ts->aborted = 1; ts->reported = 1; return 0; } ts->count = n; if ((unsigned long) n > ts->allocated) { ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); for (i = ts->allocated; i < ts->count; i++) ts->results[i] = TEST_INVALID; ts->allocated = n; } ts->plan = PLAN_FINAL; } return 1; } /* * Given a single line of output from a test, parse it and return the success * status of that test. Anything printed to stdout not matching the form * /^(not )?ok \d+/ is ignored. Sets ts->current to the test number that just * reported status. */ static void test_checkline(const char *line, struct testset *ts) { enum test_status status = TEST_PASS; const char *bail; char *end; long number; unsigned long i, current; int outlen; /* Before anything, check for a test abort. */ bail = strstr(line, "Bail out!"); if (bail != NULL) { bail = skip_whitespace(bail + strlen("Bail out!")); if (*bail != '\0') { size_t length; length = strlen(bail); if (bail[length - 1] == '\n') length--; test_backspace(ts); printf("ABORTED (%.*s)\n", (int) length, bail); ts->reported = 1; } ts->aborted = 1; return; } /* * If the given line isn't newline-terminated, it was too big for an * fgets(), which means ignore it. */ if (line[strlen(line) - 1] != '\n') return; /* If the line begins with a hash mark, ignore it. */ if (line[0] == '#') return; /* If we haven't yet seen a plan, look for one. */ if (ts->plan == PLAN_INIT && isdigit((unsigned char)(*line))) { if (!test_plan(line, ts)) return; } else if (strncmp(line, "1..", 3) == 0) { if (ts->plan == PLAN_PENDING) { if (!test_plan(line, ts)) return; } else { puts("ABORTED (multiple plans)"); ts->aborted = 1; ts->reported = 1; return; } } /* Parse the line, ignoring something we can't parse. */ if (strncmp(line, "not ", 4) == 0) { status = TEST_FAIL; line += 4; } if (strncmp(line, "ok", 2) != 0) return; line = skip_whitespace(line + 2); errno = 0; number = strtol(line, &end, 10); if (errno != 0 || end == line) number = ts->current + 1; current = number; if (number <= 0 || (current > ts->count && ts->plan == PLAN_FIRST)) { test_backspace(ts); printf("ABORTED (invalid test number %lu)\n", current); ts->aborted = 1; ts->reported = 1; return; } /* We have a valid test result. Tweak the results array if needed. */ if (ts->plan == PLAN_INIT || ts->plan == PLAN_PENDING) { ts->plan = PLAN_PENDING; if (current > ts->count) ts->count = current; if (current > ts->allocated) { unsigned long n; n = (ts->allocated == 0) ? 32 : ts->allocated * 2; if (n < current) n = current; ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); for (i = ts->allocated; i < n; i++) ts->results[i] = TEST_INVALID; ts->allocated = n; } } /* * Handle directives. We should probably do something more interesting * with unexpected passes of todo tests. */ while (isdigit((unsigned char)(*line))) line++; line = skip_whitespace(line); if (*line == '#') { line = skip_whitespace(line + 1); if (strncasecmp(line, "skip", 4) == 0) status = TEST_SKIP; if (strncasecmp(line, "todo", 4) == 0) status = (status == TEST_FAIL) ? TEST_SKIP : TEST_FAIL; } /* Make sure that the test number is in range and not a duplicate. */ if (ts->results[current - 1] != TEST_INVALID) { test_backspace(ts); printf("ABORTED (duplicate test number %lu)\n", current); ts->aborted = 1; ts->reported = 1; return; } /* Good results. Increment our various counters. */ switch (status) { case TEST_PASS: ts->passed++; break; case TEST_FAIL: ts->failed++; break; case TEST_SKIP: ts->skipped++; break; case TEST_INVALID: break; } ts->current = current; ts->results[current - 1] = status; test_backspace(ts); if (isatty(STDOUT_FILENO)) { outlen = printf("%lu/%lu", current, ts->count); ts->length = (outlen >= 0) ? outlen : 0; fflush(stdout); } } /* * Print out a range of test numbers, returning the number of characters it * took up. Takes the first number, the last number, the number of characters * already printed on the line, and the limit of number of characters the line * can hold. Add a comma and a space before the range if chars indicates that * something has already been printed on the line, and print ... instead if * chars plus the space needed would go over the limit (use a limit of 0 to * disable this). */ static unsigned int test_print_range(unsigned long first, unsigned long last, unsigned int chars, unsigned int limit) { unsigned int needed = 0; unsigned long n; for (n = first; n > 0; n /= 10) needed++; if (last > first) { for (n = last; n > 0; n /= 10) needed++; needed++; } if (chars > 0) needed += 2; if (limit > 0 && chars + needed > limit) { needed = 0; if (chars <= limit) { if (chars > 0) { printf(", "); needed += 2; } printf("..."); needed += 3; } } else { if (chars > 0) printf(", "); if (last > first) printf("%lu-", first); printf("%lu", last); } return needed; } /* * Summarize a single test set. The second argument is 0 if the set exited * cleanly, a positive integer representing the exit status if it exited * with a non-zero status, and a negative integer representing the signal * that terminated it if it was killed by a signal. */ static void test_summarize(struct testset *ts, int status) { unsigned long i; unsigned long missing = 0; unsigned long failed = 0; unsigned long first = 0; unsigned long last = 0; if (ts->aborted) { fputs("ABORTED", stdout); if (ts->count > 0) printf(" (passed %lu/%lu)", ts->passed, ts->count - ts->skipped); } else { for (i = 0; i < ts->count; i++) { if (ts->results[i] == TEST_INVALID) { if (missing == 0) fputs("MISSED ", stdout); if (first && i == last) last = i + 1; else { if (first) test_print_range(first, last, missing - 1, 0); missing++; first = i + 1; last = i + 1; } } } if (first) test_print_range(first, last, missing - 1, 0); first = 0; last = 0; for (i = 0; i < ts->count; i++) { if (ts->results[i] == TEST_FAIL) { if (missing && !failed) fputs("; ", stdout); if (failed == 0) fputs("FAILED ", stdout); if (first && i == last) last = i + 1; else { if (first) test_print_range(first, last, failed - 1, 0); failed++; first = i + 1; last = i + 1; } } } if (first) test_print_range(first, last, failed - 1, 0); if (!missing && !failed) { fputs(!status ? "ok" : "dubious", stdout); if (ts->skipped > 0) { if (ts->skipped == 1) printf(" (skipped %lu test)", ts->skipped); else printf(" (skipped %lu tests)", ts->skipped); } } } if (status > 0) printf(" (exit status %d)", status); else if (status < 0) printf(" (killed by signal %d%s)", -status, WCOREDUMP(ts->status) ? ", core dumped" : ""); putchar('\n'); } /* * Given a test set, analyze the results, classify the exit status, handle a * few special error messages, and then pass it along to test_summarize() for * the regular output. Returns true if the test set ran successfully and all * tests passed or were skipped, false otherwise. */ static int test_analyze(struct testset *ts) { if (ts->reported) return 0; if (ts->all_skipped) { if (ts->reason == NULL) puts("skipped"); else printf("skipped (%s)\n", ts->reason); return 1; } else if (WIFEXITED(ts->status) && WEXITSTATUS(ts->status) != 0) { switch (WEXITSTATUS(ts->status)) { case CHILDERR_DUP: if (!ts->reported) puts("ABORTED (can't dup file descriptors)"); break; case CHILDERR_EXEC: if (!ts->reported) puts("ABORTED (execution failed -- not found?)"); break; case CHILDERR_STDERR: if (!ts->reported) puts("ABORTED (can't open /dev/null)"); break; default: test_summarize(ts, WEXITSTATUS(ts->status)); break; } return 0; } else if (WIFSIGNALED(ts->status)) { test_summarize(ts, -WTERMSIG(ts->status)); return 0; } else if (ts->plan != PLAN_FIRST && ts->plan != PLAN_FINAL) { puts("ABORTED (no valid test plan)"); ts->aborted = 1; return 0; } else { test_summarize(ts, 0); return (ts->failed == 0); } } /* * Runs a single test set, accumulating and then reporting the results. * Returns true if the test set was successfully run and all tests passed, * false otherwise. */ static int test_run(struct testset *ts) { pid_t testpid, child; int outfd, status; unsigned long i; FILE *output; char buffer[BUFSIZ]; /* Run the test program. */ testpid = test_start(ts->path, &outfd); output = fdopen(outfd, "r"); if (!output) { puts("ABORTED"); fflush(stdout); sysdie("fdopen failed"); } /* Pass each line of output to test_checkline(). */ while (!ts->aborted && fgets(buffer, sizeof(buffer), output)) test_checkline(buffer, ts); if (ferror(output) || ts->plan == PLAN_INIT) ts->aborted = 1; test_backspace(ts); /* * Consume the rest of the test output, close the output descriptor, * retrieve the exit status, and pass that information to test_analyze() * for eventual output. */ while (fgets(buffer, sizeof(buffer), output)) ; fclose(output); child = waitpid(testpid, &ts->status, 0); if (child == (pid_t) -1) { if (!ts->reported) { puts("ABORTED"); fflush(stdout); } sysdie("waitpid for %u failed", (unsigned int) testpid); } if (ts->all_skipped) ts->aborted = 0; status = test_analyze(ts); /* Convert missing tests to failed tests. */ for (i = 0; i < ts->count; i++) { if (ts->results[i] == TEST_INVALID) { ts->failed++; ts->results[i] = TEST_FAIL; status = 0; } } return status; } /* Summarize a list of test failures. */ static void test_fail_summary(const struct testlist *fails) { struct testset *ts; unsigned int chars; unsigned long i, first, last, total; puts(header); /* Failed Set Fail/Total (%) Skip Stat Failing (25) -------------------------- -------------- ---- ---- -------------- */ for (; fails; fails = fails->next) { ts = fails->ts; total = ts->count - ts->skipped; printf("%-26.26s %4lu/%-4lu %3.0f%% %4lu ", ts->file, ts->failed, total, total ? (ts->failed * 100.0) / total : 0, ts->skipped); if (WIFEXITED(ts->status)) printf("%4d ", WEXITSTATUS(ts->status)); else printf(" -- "); if (ts->aborted) { puts("aborted"); continue; } chars = 0; first = 0; last = 0; for (i = 0; i < ts->count; i++) { if (ts->results[i] == TEST_FAIL) { if (first != 0 && i == last) last = i + 1; else { if (first != 0) chars += test_print_range(first, last, chars, 19); first = i + 1; last = i + 1; } } } if (first != 0) test_print_range(first, last, chars, 19); putchar('\n'); free(ts->file); free(ts->path); free(ts->results); if (ts->reason != NULL) free(ts->reason); free(ts); } } /* * Given the name of a test, a pointer to the testset struct, and the source * and build directories, find the test. We try first relative to the current * directory, then in the build directory (if not NULL), then in the source * directory. In each of those directories, we first try a "-t" extension and * then a ".t" extension. When we find an executable program, we fill in the * path member of the testset struct. If none of those paths are executable, * just fill in the name of the test with "-t" appended. * * The caller is responsible for freeing the path member of the testset * struct. */ static void find_test(const char *name, struct testset *ts, const char *source, const char *build) { char *path; const char *bases[4]; unsigned int i; bases[0] = "."; bases[1] = build; bases[2] = source; bases[3] = NULL; for (i = 0; i < 3; i++) { if (bases[i] == NULL) continue; path = xmalloc(strlen(bases[i]) + strlen(name) + 4); sprintf(path, "%s/%s-t", bases[i], name); if (access(path, X_OK) != 0) path[strlen(path) - 2] = '.'; if (access(path, X_OK) == 0) break; free(path); path = NULL; } if (path == NULL) { path = xmalloc(strlen(name) + 3); sprintf(path, "%s-t", name); } ts->path = path; } /* * Run a batch of tests from a given file listing each test on a line by * itself. Takes two additional parameters: the root of the source directory * and the root of the build directory. Test programs will be first searched * for in the current directory, then the build directory, then the source * directory. The file must be rewindable. Returns true iff all tests * passed. */ static int test_batch(const char *testlist, const char *source, const char *build) { FILE *tests; unsigned int length, i; unsigned int longest = 0; char buffer[BUFSIZ]; unsigned int line; struct testset ts, *tmp; struct timeval start, end; struct rusage stats; struct testlist *failhead = NULL; struct testlist *failtail = NULL; struct testlist *next; unsigned long total = 0; unsigned long passed = 0; unsigned long skipped = 0; unsigned long failed = 0; unsigned long aborted = 0; /* * Open our file of tests to run and scan it, checking for lines that * are too long and searching for the longest line. */ tests = fopen(testlist, "r"); if (!tests) sysdie("can't open %s", testlist); line = 0; while (fgets(buffer, sizeof(buffer), tests)) { line++; length = strlen(buffer) - 1; if (buffer[length] != '\n') { fprintf(stderr, "%s:%u: line too long\n", testlist, line); exit(1); } if (length > longest) longest = length; } if (fseek(tests, 0, SEEK_SET) == -1) sysdie("can't rewind %s", testlist); /* * Add two to longest and round up to the nearest tab stop. This is how * wide the column for printing the current test name will be. */ longest += 2; if (longest % 8) longest += 8 - (longest % 8); /* Start the wall clock timer. */ gettimeofday(&start, NULL); /* * Now, plow through our tests again, running each one. Check line * length again out of paranoia. */ line = 0; while (fgets(buffer, sizeof(buffer), tests)) { line++; length = strlen(buffer) - 1; if (buffer[length] != '\n') { fprintf(stderr, "%s:%u: line too long\n", testlist, line); exit(1); } buffer[length] = '\0'; fputs(buffer, stdout); for (i = length; i < longest; i++) putchar('.'); if (isatty(STDOUT_FILENO)) fflush(stdout); memset(&ts, 0, sizeof(ts)); ts.plan = PLAN_INIT; ts.file = xstrdup(buffer); find_test(buffer, &ts, source, build); ts.reason = NULL; if (test_run(&ts)) { free(ts.file); free(ts.path); free(ts.results); if (ts.reason != NULL) free(ts.reason); } else { tmp = xmalloc(sizeof(struct testset)); memcpy(tmp, &ts, sizeof(struct testset)); if (!failhead) { failhead = xmalloc(sizeof(struct testset)); failhead->ts = tmp; failhead->next = NULL; failtail = failhead; } else { failtail->next = xmalloc(sizeof(struct testset)); failtail = failtail->next; failtail->ts = tmp; failtail->next = NULL; } } aborted += ts.aborted; total += ts.count + ts.all_skipped; passed += ts.passed; skipped += ts.skipped + ts.all_skipped; failed += ts.failed; } total -= skipped; fclose(tests); /* Stop the timer and get our child resource statistics. */ gettimeofday(&end, NULL); getrusage(RUSAGE_CHILDREN, &stats); /* Print out our final results. */ if (failhead != NULL) { test_fail_summary(failhead); while (failhead != NULL) { next = failhead->next; free(failhead); failhead = next; } } putchar('\n'); if (aborted != 0) { if (aborted == 1) printf("Aborted %lu test set", aborted); else printf("Aborted %lu test sets", aborted); printf(", passed %lu/%lu tests", passed, total); } else if (failed == 0) fputs("All tests successful", stdout); else printf("Failed %lu/%lu tests, %.2f%% okay", failed, total, (total - failed) * 100.0 / total); if (skipped != 0) { if (skipped == 1) printf(", %lu test skipped", skipped); else printf(", %lu tests skipped", skipped); } puts("."); printf("Files=%u, Tests=%lu", line, total); printf(", %.2f seconds", tv_diff(&end, &start)); printf(" (%.2f usr + %.2f sys = %.2f CPU)\n", tv_seconds(&stats.ru_utime), tv_seconds(&stats.ru_stime), tv_sum(&stats.ru_utime, &stats.ru_stime)); return (failed == 0 && aborted == 0); } /* * Run a single test case. This involves just running the test program after * having done the environment setup and finding the test program. */ static void test_single(const char *program, const char *source, const char *build) { struct testset ts; memset(&ts, 0, sizeof(ts)); find_test(program, &ts, source, build); if (execl(ts.path, ts.path, (char *) 0) == -1) sysdie("cannot exec %s", ts.path); } /* * Main routine. Set the SOURCE and BUILD environment variables and then, * given a file listing tests, run each test listed. */ int main(int argc, char *argv[]) { int option; int status = 0; int single = 0; char *source_env = NULL; char *build_env = NULL; const char *list; const char *source = SOURCE; const char *build = BUILD; while ((option = getopt(argc, argv, "b:hos:")) != EOF) { switch (option) { case 'b': build = optarg; break; case 'h': printf(usage_message, argv[0], argv[0]); exit(0); break; case 'o': single = 1; break; case 's': source = optarg; break; default: exit(1); } } if (argc - optind != 1) { fprintf(stderr, usage_message, argv[0], argv[0]); exit(1); } argc -= optind; argv += optind; if (source != NULL) { source_env = xmalloc(strlen("SOURCE=") + strlen(source) + 1); sprintf(source_env, "SOURCE=%s", source); if (putenv(source_env) != 0) sysdie("cannot set SOURCE in the environment"); } if (build != NULL) { build_env = xmalloc(strlen("BUILD=") + strlen(build) + 1); sprintf(build_env, "BUILD=%s", build); if (putenv(build_env) != 0) sysdie("cannot set BUILD in the environment"); } if (single) test_single(argv[0], source, build); else { list = strrchr(argv[0], '/'); if (list == NULL) list = argv[0]; else list++; printf(banner, list); status = test_batch(argv[0], source, build) ? 0 : 1; } /* For valgrind cleanliness. */ if (source_env != NULL) { putenv((char *) "SOURCE="); free(source_env); } if (build_env != NULL) { putenv((char *) "BUILD="); free(build_env); } exit(status); } kstart-4.1/tests/docs/0000755000175000000000000000000011702213052011735 500000000000000kstart-4.1/tests/docs/pod-t0000755000175000000000000000105211702213030012620 00000000000000#!/usr/bin/perl -w # # Test formatting of POD documentation. # # Written by Russ Allbery # Copyright 2008, 2009, 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use strict; use Test::More; my @podfiles = qw(k5start.pod krenew.pod); eval 'use Test::Pod 1.00'; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; my $srcdir = "$ENV{SOURCE}"; $srcdir =~ s,[^/]+/*$,,; chdir "$srcdir" or die "$0: cannot chdir to $srcdir: $!\n"; all_pod_files_ok (@podfiles); kstart-4.1/tests/docs/pod-spelling-t0000755000175000000000000000475011702213030014443 00000000000000#!/usr/bin/perl -w # # Check for spelling errors in POD documentation # # Checks all POD files in the tree for spelling problems using Pod::Spell and # either aspell or ispell. aspell is preferred. This test is disabled unless # RRA_MAINTAINER_TESTS is set, since spelling dictionaries vary too much # between environments. # # Copyright 2008, 2009, 2011 Russ Allbery # # See LICENSE for licensing terms. use strict; use Test::More; # Skip all spelling tests unless the maintainer environment variable is set. plan skip_all => 'spelling tests only run for maintainer' unless $ENV{RRA_MAINTAINER_TESTS}; # Load required Perl modules. eval 'use Test::Pod 1.00'; plan skip_all => 'Test::Pod 1.00 required for testing POD' if $@; eval 'use Pod::Spell'; plan skip_all => 'Pod::Spell required to test POD spelling' if $@; # Locate a spell-checker. hunspell is not currently supported due to its lack # of support for contractions (at least in the version in Debian). my @spell; my %options = (aspell => [ qw(-d en_US --home-dir=./ list) ], ispell => [ qw(-d american -l -p /dev/null) ]); SEARCH: for my $program (qw/aspell ispell/) { for my $dir (split ':', $ENV{PATH}) { if (-x "$dir/$program") { @spell = ("$dir/$program", @{ $options{$program} }); } last SEARCH if @spell; } } plan skip_all => 'aspell or ispell required to test POD spelling' unless @spell; # Prerequisites are satisfied, so we're going to do some testing. Figure out # what POD files we have and from that develop our plan. $| = 1; my @pod = map { my $pod = "$ENV{SOURCE}/../" . $_; $pod =~ s,[^/.][^/]*/../,,g; $pod; } qw(k5start.pod krenew.pod); plan tests => scalar @pod; # Finally, do the checks. for my $pod (@pod) { my $child = open (CHILD, '-|'); if (not defined $child) { BAIL_OUT ("cannot fork: $!"); } elsif ($child == 0) { my $pid = open (SPELL, '|-', @spell) or BAIL_OUT ("cannot run @spell: $!"); open (POD, '<', $pod) or BAIL_OUT ("cannot open $pod: $!"); my $parser = Pod::Spell->new; $parser->parse_from_filehandle (\*POD, \*SPELL); close POD; close SPELL; exit ($? >> 8); } else { my @words = ; close CHILD; SKIP: { skip "@spell failed for $pod", 1 unless $? == 0; for (@words) { s/^\s+//; s/\s+$//; } is ("@words", '', $pod); } } } kstart-4.1/tests/portable/0000755000175000000000000000000011702213052012615 500000000000000kstart-4.1/tests/portable/daemon.c0000644000175000000000000000005711702213030014142 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/asprintf.c0000644000175000000000000000006111702213030014520 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/strlcat.c0000644000175000000000000000006011702213030014345 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/mkstemp.c0000644000175000000000000000006011702213030014351 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/snprintf.c0000644000175000000000000000006111702213030014535 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/asprintf-t.c0000644000175000000000000000365011702213030014770 00000000000000/* * asprintf and vasprintf test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include int test_asprintf(char **, const char *, ...) __attribute__((__format__(printf, 2, 3))); int test_vasprintf(char **, const char *, va_list); static int vatest(char **result, const char *format, ...) { va_list args; int status; va_start(args, format); status = test_vasprintf(result, format, args); va_end(args); return status; } int main(void) { char *result = NULL; plan(12); is_int(7, test_asprintf(&result, "%s", "testing"), "asprintf length"); is_string("testing", result, "asprintf result"); free(result); ok(3, "free asprintf"); is_int(0, test_asprintf(&result, "%s", ""), "asprintf empty length"); is_string("", result, "asprintf empty string"); free(result); ok(6, "free asprintf of empty string"); is_int(6, vatest(&result, "%d %s", 2, "test"), "vasprintf length"); is_string("2 test", result, "vasprintf result"); free(result); ok(9, "free vasprintf"); is_int(0, vatest(&result, "%s", ""), "vasprintf empty length"); is_string("", result, "vasprintf empty string"); free(result); ok(12, "free vasprintf of empty string"); return 0; } kstart-4.1/tests/portable/strndup-t.c0000644000175000000000000000277011702213030014643 00000000000000/* * strndup test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include #include char *test_strndup(const char *, size_t); int main(void) { char *result = NULL; plan(6); result = test_strndup("foo", 8); is_string("foo", result, "strndup longer than string"); free(result); result = test_strndup("foo", 2); is_string("fo", result, "strndup shorter than string"); free(result); result = test_strndup("foo", 3); is_string("foo", result, "strndup same size as string"); free(result); result = test_strndup("foo", 0); is_string("", result, "strndup of size 0"); free(result); errno = 0; result = test_strndup(NULL, 0); is_string(NULL, result, "strndup of NULL"); is_int(errno, EINVAL, "...and returns EINVAL"); return 0; } kstart-4.1/tests/portable/strndup.c0000644000175000000000000000006011702213030014370 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/setenv-t.c0000644000175000000000000000334311702213030014445 00000000000000/* * setenv test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include #include int test_setenv(const char *name, const char *value, int overwrite); static const char test_var[] = "SETENV_TEST"; static const char test_value1[] = "Do not taunt Happy Fun Ball."; static const char test_value2[] = "Do not use Happy Fun Ball on concrete."; int main(void) { plan(8); if (getenv(test_var)) bail("%s already in the environment!", test_var); ok(test_setenv(test_var, test_value1, 0) == 0, "set string 1"); is_string(test_value1, getenv(test_var), "...and getenv correct"); ok(test_setenv(test_var, test_value2, 0) == 0, "set string 2"); is_string(test_value1, getenv(test_var), "...and getenv unchanged"); ok(test_setenv(test_var, test_value2, 1) == 0, "overwrite string 2"); is_string(test_value2, getenv(test_var), "...and getenv changed"); ok(test_setenv(test_var, "", 1) == 0, "overwrite with empty string"); is_string("", getenv(test_var), "...and getenv correct"); return 0; } kstart-4.1/tests/portable/strlcat-t.c0000644000175000000000000000624511702213030014621 00000000000000/* * strlcat test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include size_t test_strlcat(char *, const char *, size_t); int main(void) { char buffer[10] = ""; plan(27); is_int(3, test_strlcat(buffer, "foo", sizeof(buffer)), "strlcat into empty buffer"); is_string("foo", buffer, "...with right output"); is_int(7, test_strlcat(buffer, " bar", sizeof(buffer)), "...and append more"); is_string("foo bar", buffer, "...and output is still correct"); is_int(9, test_strlcat(buffer, "!!", sizeof(buffer)), "...and append to buffer limit"); is_string("foo bar!!", buffer, "...output is still correct"); is_int(10, test_strlcat(buffer, "!", sizeof(buffer)), "...append one more character"); is_string("foo bar!!", buffer, "...and output didn't change"); ok(buffer[9] == '\0', "...buffer still nul-terminated"); buffer[0] = '\0'; is_int(11, test_strlcat(buffer, "hello world", sizeof(buffer)), "append single long string"); is_string("hello wor", buffer, "...string truncates properly"); ok(buffer[9] == '\0', "...buffer still nul-terminated"); buffer[0] = '\0'; is_int(7, test_strlcat(buffer, "sausage", 5), "lie about buffer length"); is_string("saus", buffer, "...contents are correct"); is_int(14, test_strlcat(buffer, "bacon eggs", sizeof(buffer)), "...add more up to real size"); is_string("sausbacon", buffer, "...and result is correct"); /* Make sure that with a size of 0, the destination isn't changed. */ is_int(11, test_strlcat(buffer, "!!", 0), "no change with size of 0"); is_string("sausbacon", buffer, "...and content is the same"); /* Now play with empty strings. */ is_int(9, test_strlcat(buffer, "", 0), "correct count when appending empty string"); is_string("sausbacon", buffer, "...and contents are unchanged"); buffer[0] = '\0'; is_int(0, test_strlcat(buffer, "", sizeof(buffer)), "correct count when appending empty string to empty buffer"); is_string("", buffer, "...and buffer content is correct"); is_int(3, test_strlcat(buffer, "foo", 2), "append to length 2 buffer"); is_string("f", buffer, "...and got only a single character"); ok(buffer[1] == '\0', "...and buffer is still nul-terminated"); is_int(1, test_strlcat(buffer, "", sizeof(buffer)), "append an empty string"); ok(buffer[1] == '\0', "...and buffer is still nul-terminated"); return 0; } kstart-4.1/tests/portable/setenv.c0000644000175000000000000000005711702213030014203 00000000000000#define TESTING 1 #include kstart-4.1/tests/portable/mkstemp-t.c0000644000175000000000000000542111702213030014620 00000000000000/* * mkstemp test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include #include #include int test_mkstemp(char *template); int main(void) { int fd; char template[] = "tsXXXXXXX"; char tooshort[] = "XXXXX"; char bad1[] = "/foo/barXXXXX"; char bad2[] = "/foo/barXXXXXX.out"; char buffer[256]; struct stat st1, st2; ssize_t length; plan(20); /* First, test a few error messages. */ errno = 0; is_int(-1, test_mkstemp(tooshort), "too short of template"); is_int(EINVAL, errno, "...with correct errno"); is_string("XXXXX", tooshort, "...and template didn't change"); errno = 0; is_int(-1, test_mkstemp(bad1), "bad template"); is_int(EINVAL, errno, "...with correct errno"); is_string("/foo/barXXXXX", bad1, "...and template didn't change"); errno = 0; is_int(-1, test_mkstemp(bad2), "template doesn't end in XXXXXX"); is_int(EINVAL, errno, "...with correct errno"); is_string("/foo/barXXXXXX.out", bad2, "...and template didn't change"); errno = 0; /* Now try creating a real file. */ fd = test_mkstemp(template); ok(fd >= 0, "mkstemp works with valid template"); ok(strcmp(template, "tsXXXXXXX") != 0, "...and template changed"); ok(strncmp(template, "tsX", 3) == 0, "...and didn't touch first X"); ok(access(template, F_OK) == 0, "...and the file exists"); /* Make sure that it's the same file as template refers to now. */ ok(stat(template, &st1) == 0, "...and stat of template works"); ok(fstat(fd, &st2) == 0, "...and stat of open file descriptor works"); ok(st1.st_ino == st2.st_ino, "...and they're the same file"); unlink(template); /* Make sure the open mode is correct. */ length = strlen(template); is_int(length, write(fd, template, length), "write to open file works"); ok(lseek(fd, 0, SEEK_SET) == 0, "...and rewind works"); is_int(length, read(fd, buffer, length), "...and the data is there"); buffer[length] = '\0'; is_string(template, buffer, "...and matches what we wrote"); close(fd); return 0; } kstart-4.1/tests/portable/strlcpy-t.c0000644000175000000000000000534511702213030014645 00000000000000/* * strlcpy test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include size_t test_strlcpy(char *, const char *, size_t); int main(void) { char buffer[10]; plan(23); is_int(3, test_strlcpy(buffer, "foo", sizeof(buffer)), "simple strlcpy"); is_string("foo", buffer, "...result is correct"); is_int(9, test_strlcpy(buffer, "hello wor", sizeof(buffer)), "strlcpy exact length of buffer"); is_string("hello wor", buffer, "...result is correct"); is_int(10, test_strlcpy(buffer, "world hell", sizeof(buffer)), "strlcpy one more than buffer length"); is_string("world hel", buffer, "...result is correct"); ok(buffer[9] == '\0', "...buffer is nul-terminated"); is_int(11, test_strlcpy(buffer, "hello world", sizeof(buffer)), "strlcpy more than buffer length"); is_string("hello wor", buffer, "...result is correct"); ok(buffer[9] == '\0', "...buffer is nul-terminated"); /* Make sure that with a size of 0, the destination isn't changed. */ is_int(3, test_strlcpy(buffer, "foo", 0), "buffer unchanged if size 0"); is_string("hello wor", buffer, "...contents still the same"); /* Now play with empty strings. */ is_int(0, test_strlcpy(buffer, "", 0), "copy empty string with size 0"); is_string("hello wor", buffer, "...buffer unchanged"); is_int(0, test_strlcpy(buffer, "", sizeof(buffer)), "copy empty string into full buffer"); is_string("", buffer, "...buffer now empty string"); is_int(3, test_strlcpy(buffer, "foo", 2), "copy string into buffer of size 2"); is_string("f", buffer, "...got one character"); ok(buffer[1] == '\0', "...buffer is nul-terminated"); is_int(0, test_strlcpy(buffer, "", 1), "copy empty string into buffer of size 1"); ok(buffer[0] == '\0', "...buffer is empty string"); /* Finally, check using strlcpy as strlen. */ is_int(3, test_strlcpy(NULL, "foo", 0), "use strlcpy as strlen"); is_int(11, test_strlcpy(NULL, "hello world", 0), "...again"); return 0; } kstart-4.1/tests/portable/snprintf-t.c0000644000175000000000000001623711702213030015012 00000000000000/* * snprintf test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 * Russ Allbery * Copyright 2009, 2010 * The Board of Trustees of the Leland Stanford Junior University * Copyright 1995 Patrick Powell * Copyright 2001 Hrvoje Niksic * * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ #include #include #include /* * Disable the requirement that format strings be literals. We need variable * formats for easy testing. */ #pragma GCC diagnostic ignored "-Wformat-nonliteral" /* * Intentionally don't add the printf attribute here since we pass a * zero-length printf format during testing and don't want warnings. */ int test_snprintf(char *str, size_t count, const char *fmt, ...); int test_vsnprintf(char *str, size_t count, const char *fmt, va_list args); static const char string[] = "abcdefghijklmnopqrstuvwxyz0123456789"; static const char *const fp_formats[] = { "%-1.5f", "%1.5f", "%31.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%3.1f", "%3.2f", "%.0f", "%.1f", "%f", /* %e and %g formats aren't really implemented yet. */ #if 0 "%-1.5e", "%1.5e", "%31.9e", "%10.5e", "% 10.5e", "%+22.9e", "%+4.9e", "%01.3e", "%3.1e", "%3.2e", "%.0e", "%.1e", "%e", "%-1.5g", "%1.5g", "%31.9g", "%10.5g", "% 10.5g", "%+22.9g", "%+4.9g", "%01.3g", "%3.1g", "%3.2g", "%.0g", "%.1g", "%g", #endif NULL }; static const char *const int_formats[] = { "%-1.5d", "%1.5d", "%31.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.30d", "%01.3d", "%4d", "%d", "%ld", NULL }; static const char *const uint_formats[] = { "%-1.5lu", "%1.5lu", "%31.9lu", "%5.5lu", "%10.5lu", "% 10.5lu", "%+6.30lu", "%01.3lu", "%4lu", "%lu", "%4lx", "%4lX", "%01.3lx", "%1lo", NULL }; static const char *const llong_formats[] = { "%lld", "%-1.5lld", "%1.5lld", "%123.9lld", "%5.5lld", "%10.5lld", "% 10.5lld", "%+22.33lld", "%01.3lld", "%4lld", NULL }; static const char *const ullong_formats[] = { "%llu", "%-1.5llu", "%1.5llu", "%123.9llu", "%5.5llu", "%10.5llu", "% 10.5llu", "%+22.33llu", "%01.3llu", "%4llu", "%llx", "%llo", NULL }; static const double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 0.1, 0.01, 0.001, 10.1, 0 }; static long int_nums[] = { -1, 134, 91340, 341, 0203, 0 }; static unsigned long uint_nums[] = { (unsigned long) -1, 134, 91340, 341, 0203, 0 }; static long long llong_nums[] = { ~(long long) 0, /* All-1 bit pattern. */ (~(unsigned long long) 0) >> 1, /* Largest signed long long. */ -150, 134, 91340, 341, 0 }; static unsigned long long ullong_nums[] = { ~(unsigned long long) 0, /* All-1 bit pattern. */ (~(unsigned long long) 0) >> 1, /* Largest signed long long. */ 134, 91340, 341, 0 }; static void test_format(bool trunc, const char *expected, int count, const char *format, ...) { char buf[128]; int result; va_list args; va_start(args, format); result = test_vsnprintf(buf, trunc ? 32 : sizeof(buf), format, args); va_end(args); is_string(expected, buf, "format %s, wanted %s", format, expected); is_int(count, result, "...and output length correct"); } int main(void) { int i, count; unsigned int j; long lcount; char lgbuf[128]; plan(8 + (18 + (ARRAY_SIZE(fp_formats) - 1) * ARRAY_SIZE(fp_nums) + (ARRAY_SIZE(int_formats) - 1) * ARRAY_SIZE(int_nums) + (ARRAY_SIZE(uint_formats) - 1) * ARRAY_SIZE(uint_nums) + (ARRAY_SIZE(llong_formats) - 1) * ARRAY_SIZE(llong_nums) + (ARRAY_SIZE(ullong_formats) - 1) * ARRAY_SIZE(ullong_nums)) * 2); is_int(4, test_snprintf(NULL, 0, "%s", "abcd"), "simple string length"); is_int(2, test_snprintf(NULL, 0, "%d", 20), "number length"); is_int(7, test_snprintf(NULL, 0, "Test %.2s", "abcd"), "limited string"); is_int(1, test_snprintf(NULL, 0, "%c", 'a'), "character length"); is_int(0, test_snprintf(NULL, 0, ""), "empty format length"); test_format(true, "abcd", 4, "%s", "abcd"); test_format(true, "20", 2, "%d", 20); test_format(true, "Test ab", 7, "Test %.2s", "abcd"); test_format(true, "a", 1, "%c", 'a'); test_format(true, "", 0, ""); test_format(true, "abcdefghijklmnopqrstuvwxyz01234", 36, "%s", string); test_format(true, "abcdefghij", 10, "%.10s", string); test_format(true, " abcdefghij", 12, "%12.10s", string); test_format(true, " abcdefghijklmnopqrstuvwxyz0", 40, "%40s", string); test_format(true, "abcdefghij ", 14, "%-14.10s", string); test_format(true, " abcdefghijklmnopq", 50, "%50s", string); test_format(true, "%abcd%", 6, "%%%0s%%", "abcd"); test_format(true, "", 0, "%.0s", string); test_format(true, "abcdefghijklmnopqrstuvwxyz 444", 32, "%.26s %d", string, 4444); test_format(true, "abcdefghijklmnopqrstuvwxyz -2.", 32, "%.26s %.1f", string, -2.5); test_format(true, "abcdefghij4444", 14, "%.10s%n%d", string, &count, 4444); is_int(10, count, "correct output from %%n"); test_format(true, "abcdefghijklmnopqrstuvwxyz01234", 36, "%n%s%ln", &count, string, &lcount); is_int(0, count, "correct output from two %%n"); is_int(31, lcount, "correct output from long %%ln"); test_format(true, "(null)", 6, "%s", NULL); for (i = 0; fp_formats[i] != NULL; i++) for (j = 0; j < ARRAY_SIZE(fp_nums); j++) { count = sprintf(lgbuf, fp_formats[i], fp_nums[j]); test_format(false, lgbuf, count, fp_formats[i], fp_nums[j]); } for (i = 0; int_formats[i] != NULL; i++) for (j = 0; j < ARRAY_SIZE(int_nums); j++) { count = sprintf(lgbuf, int_formats[i], int_nums[j]); test_format(false, lgbuf, count, int_formats[i], int_nums[j]); } for (i = 0; uint_formats[i] != NULL; i++) for (j = 0; j < ARRAY_SIZE(uint_nums); j++) { count = sprintf(lgbuf, uint_formats[i], uint_nums[j]); test_format(false, lgbuf, count, uint_formats[i], uint_nums[j]); } for (i = 0; llong_formats[i] != NULL; i++) for (j = 0; j < ARRAY_SIZE(llong_nums); j++) { count = sprintf(lgbuf, llong_formats[i], llong_nums[j]); test_format(false, lgbuf, count, llong_formats[i], llong_nums[j]); } for (i = 0; ullong_formats[i] != NULL; i++) for (j = 0; j < ARRAY_SIZE(ullong_nums); j++) { count = sprintf(lgbuf, ullong_formats[i], ullong_nums[j]); test_format(false, lgbuf, count, ullong_formats[i], ullong_nums[j]); } return 0; } kstart-4.1/tests/portable/daemon-t.c0000644000175000000000000000716711702213030014414 00000000000000/* * daemon test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include #include #ifdef HAVE_SYS_SELECT_H # include #endif #include #include #include #include int test_daemon(int, int); /* * Create the sentinel file, used by the child to indicate when it's done. */ static void create_sentinel(void) { int fd; fd = open("daemon-sentinel", O_RDWR | O_CREAT, 0666); close(fd); } /* * Wait for a sentinel file to be created. Returns true if we saw it within * the expected length of time, and false otherwise. */ static int wait_sentinel(void) { int count = 20; int i; struct timeval tv; for (i = 0; i < count; i++) { if (access("daemon-sentinel", F_OK) == 0) { unlink("daemon-sentinel"); return 1; } tv.tv_sec = 0; tv.tv_usec = 100000; select(0, NULL, NULL, NULL, &tv); } if (access("daemon-sentinel", F_OK) == 0) { unlink("daemon-sentinel"); return 1; } return 0; } int main(void) { int fd, status; pid_t child; char start[BUFSIZ], dir[BUFSIZ]; plan(9); /* Get the current working directory. */ if (getcwd(start, sizeof(start)) == NULL) bail("cannot get current working directory"); /* First, some basic tests. */ child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { is_int(0, daemon(1, 1), "daemon(1, 1)"); fd = open("/dev/tty", O_RDONLY); ok(fd < 0, "...no tty"); is_string(start, getcwd(dir, sizeof(dir)), "...in same directory"); create_sentinel(); exit(42); } else { if (waitpid(child, &status, 0) < 0) bail("cannot wait for child: %s", strerror(errno)); testnum += 3; ok(wait_sentinel(), "...child exited"); is_int(0, status, "...successfully"); } /* Test chdir. */ child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { is_int(0, daemon(0, 1), "daemon(0, 1)"); is_string("/", getcwd(dir, sizeof(dir)), "...now in /"); if (chdir(start) != 0) sysbail("cannot chdir to %s", start); create_sentinel(); exit(0); } else { if (waitpid(child, &status, 0) < 0) sysbail("cannot wait for child"); testnum += 2; ok(wait_sentinel(), "...child exited"); } /* Test close. */ child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { daemon(0, 0); if (chdir(start) != 0) sysbail("cannot chdir to %s", start); ok(0, "output from child that should be hidden"); create_sentinel(); exit(0); } else { if (waitpid(child, &status, 0) < 0) sysbail("cannot wait for child"); ok(wait_sentinel(), "daemon(0, 0)"); } return 0; } kstart-4.1/tests/portable/strlcpy.c0000644000175000000000000000006011702213030014371 00000000000000#define TESTING 1 #include kstart-4.1/tests/TESTS0000644000175000000000000000072611702213030011553 00000000000000docs/pod docs/pod-spelling k5start/afs k5start/basic k5start/daemon k5start/errors k5start/flags k5start/keyring k5start/non-renewable k5start/perms k5start/sigchld kafs/basic kafs/haspag krenew/afs krenew/basic krenew/daemon krenew/errors krenew/keyring krenew/non-renewable portable/asprintf portable/daemon portable/mkstemp portable/setenv portable/snprintf portable/strlcat portable/strlcpy portable/strndup util/concat util/messages util/messages-krb5 util/xmalloc kstart-4.1/tests/k5start/0000755000175000000000000000000011702213052012402 500000000000000kstart-4.1/tests/k5start/flags-t0000755000175000000000000001201211702213030013575 00000000000000#!/usr/bin/perl -w # # Tests for basic k5start functionality. # # Written by Russ Allbery # Copyright 2008, 2009, 2010 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") { plan tests => 34; } else { plan skip_all => "no keytab configuration"; exit 0; } my $principal = contents ("$DATA/test.principal"); # We have to generate a local krb5.conf that gets forwardable and # proxiable tickets by default. Try to locate the local krb5.conf that # we're supposed to use and bail if we can't find one. my $krb5conf = $ENV{KRB5_CONFIG}; unless ($krb5conf) { for my $path ('/etc', '/usr/local/etc', "$ENV{BUILD}/data") { if (-r "$path/krb5.conf") { $krb5conf = "$path/krb5.conf"; last; } } } if ($krb5conf) { open (CONF, '<', $krb5conf) or BAIL_OUT ("cannot open $krb5conf: $!"); open (NEWCONF, '>', './krb5.conf') or BAIL_OUT ("cannot create krb5.conf: $!"); print NEWCONF ; close CONF; print NEWCONF "\n"; print NEWCONF "[libdefaults]\n"; print NEWCONF " forwardable = true\n"; print NEWCONF " proxiable = true\n"; close NEWCONF; $ENV{KRB5_CONFIG} = './krb5.conf'; } else { BAIL_OUT ("no krb5.conf found, set KRB5_CONFIG"); } # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Basic authentication test with forwardable and proxiable tickets. unlink 'krb5cc_test'; my ($out, $err, $status) = command ($K5START, '-f', "$DATA/test.keytab", $principal); is ($status, 0, 'Basic k5start command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); my ($default, $service, $flags) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); like ($flags, qr/F/, ' and has forwardable tickets'); like ($flags, qr/P/, ' and has proxiable tickets'); # Authentication without proxiable tickets. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-Pf', "$DATA/test.keytab", $principal); is ($status, 0, 'k5start -P command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service, $flags) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); like ($flags, qr/F/, ' and has forwardable tickets'); unlike ($flags, qr/P/, ' but not proxiable tickets'); # Authentication without forwardable tickets. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-F', '-f', "$DATA/test.keytab", $principal); is ($status, 0, 'k5start -F command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service, $flags) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); like ($flags, qr/P/, ' and has proxiable tickets'); unlike ($flags, qr/F/, ' but not forwardable tickets'); # Authentication with both flags flag. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-FPf', "$DATA/test.keytab", $principal); is ($status, 0, 'k5start -F -P command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service, $flags) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); unlike ($flags, qr/P/, ' but not proxiable tickets'); unlike ($flags, qr/F/, ' and not forwardable tickets'); # Test -k with a fully-qualified ticket cache name. unlink 'krb5cc_test', 'krb5cc_test2'; ($out, $err, $status) = command ($K5START, '-k', 'FILE:krb5cc_test2', '-f', "$DATA/test.keytab", $principal); is ($status, 0, 'k5start -k command with file succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ok (!-f 'krb5cc_test', ' and does not use KRB5CCNAME'); $ENV{KRB5CCNAME} = 'krb5cc_test2'; ($default, $service, $flags) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); $ENV{KRB5CCNAME} = 'krb5cc_test'; unlink 'krb5cc_test2'; # Clean up. unlink 'krb5cc_test', 'krb5.conf'; kstart-4.1/tests/k5start/keyring-t0000755000175000000000000000360411702213030014160 00000000000000#!/usr/bin/perl -w # # Tests for k5start support of keyrings. # # Written by Russ Allbery # Copyright 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. my $principal; if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'KEYRING:test'; unless (kinit ("$DATA/test.keytab", $principal) && !-f 'KEYRING:test') { plan skip_all => 'cannot use keyring caches'; exit 0; } plan tests => 14; } # Basic authentication test. my ($out, $err, $status) = command ($K5START, '-Uf', "$DATA/test.keytab"); is ($status, 0, 'Basic k5start command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); my ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); system ('kdestroy'); # We should get an error if we try to use a non-FILE keyring with -o, -g, or # -m. for my $flag (qw/-o -g -m/) { ($out, $err, $status) = command ($K5START, $flag, 640, '-Uf', "$DATA/test.keytab"); is ($status, 1, "k5start $flag with keyring fails"); is ($err, "k5start: cache type KEYRING not allowed with -o, -g, or -m\n", ' with correct error'); is ($out, '', ' and no output'); } system ('kdestroy'); kstart-4.1/tests/k5start/afs-t0000755000175000000000000000744111702213030013264 00000000000000#!/usr/bin/perl -w # # Tests for k5start with AFS. # # Written by Russ Allbery # Copyright 2008, 2009 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # The path to a shell script that just prints something out. our $FAKE_AKLOG = "$ENV{SOURCE}/data/fake-aklog"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Decide whether we have the configuration to run the tests. my ($principal, $out, $err, $status); if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } elsif (not tokens ()) { plan skip_all => 'no current AFS tokens'; exit 0; } else { $principal = contents ("$DATA/test.principal"); unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-tqUf', "$DATA/test.keytab", '--', 'tokens'); if ($err eq "k5start: cannot create PAG: AFS support is not available\n") { plan skip_all => 'not built with AFS support'; exit 0; } else { plan tests => 22; } } # Basic token test. is ($status, 0, 'k5start -t succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^(User\'s \([^\)]+\) )?[Tt]okens for /m, ' and the right output'); my ($default, $service) = klist (); is ($default, undef, ' and the normal ticket cache is untouched'); # Set the token program to something that doesn't obtain tokens. # Everything should still work, but we should have no tokens. $ENV{AKLOG} = '/bin/true'; ($out, $err, $status) = command ($K5START, '-tqUf', "$DATA/test.keytab", '--', 'tokens'); is ($status, 0, 'k5start -t succeeds with no aklog'); is ($err, '', ' with no errors'); unlike ($out, qr/^(User\'s \([^\)]+\) )?[Tt]okens for /m, ' and we have no tokens'); delete $ENV{AKLOG}; # Make sure that we run the right aklog program. $ENV{AKLOG} = $FAKE_AKLOG; ($out, $err, $status) = command ($K5START, '-tqUf', "$DATA/test.keytab", '--', 'true'); is ($status, 0, 'k5start -t succeeds with fake aklog'); is ($err, '', ' with no errors'); is ($out, "Running fake aklog\n", ' and we ran the fake aklog'); delete $ENV{AKLOG}; # AKLOG should override KINIT_PROG. $ENV{KINIT_PROG} = $FAKE_AKLOG; $ENV{AKLOG} = '/bin/true'; ($out, $err, $status) = command ($K5START, '-tqUf', "$DATA/test.keytab", '--', 'true'); is ($status, 0, 'k5start -t succeeds with /bin/true aklog'); is ($err, '', ' with no errors'); is ($out, '', ' and we did not run KINIT_PROG'); delete $ENV{AKLOG}; delete $ENV{KINIT_PROG}; # KINIT_PROG should still work. $ENV{KINIT_PROG} = $FAKE_AKLOG; ($out, $err, $status) = command ($K5START, '-tqUf', "$DATA/test.keytab", '--', 'true'); is ($status, 0, 'k5start -t succeeds with KINIT_PROG'); is ($err, '', ' with no errors'); is ($out, "Running fake aklog\n", ' and we ran the fake aklog'); delete $ENV{KINIT_PROG}; # First, get an existing ticket cache. Then, be sure that, even though # the ticket cache is good with -H, we still run aklog if -t was given. $ENV{KINIT_PROG} = $FAKE_AKLOG; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab"); is ($status, 0, 'k5start succeeds'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); ($out, $err, $status) = command ($K5START, '-tqU', '-H', '60', '-f', "$DATA/test.keytab"); is ($status, 0, ' and k5start -H 60 -t succeeds with KINIT_PROG'); is ($err, '', ' with no errors'); is ($out, "Running fake aklog\n", ' and we ran the fake aklog'); delete $ENV{KINIT_PROG}; # Clean up. unlink 'krb5cc_test'; kstart-4.1/tests/k5start/errors-t0000755000175000000000000000225011702213030014020 00000000000000#!/usr/bin/perl -w # # Tests for error handling in k5start. # # Written by Russ Allbery # Copyright 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Test invalid options. our @OPTIONS = ( [ [ qw/-H 0/ ], '-H limit argument 0 invalid' ], [ [ qw/-H -1/ ], '-H limit argument -1 invalid' ], [ [ qw/-H 4foo/ ], '-H limit argument 4foo invalid' ], [ [ qw/-K 4foo/ ], '-K interval argument 4foo invalid' ], [ [ qw/-H4 -Uf a a/ ], '-H option cannot be used with a command' ] ); # Test plan. plan tests => scalar (@OPTIONS) * 3; # Run the invalid option tests. for my $opt (@OPTIONS) { my ($out, $err, $status) = command ($K5START, @{ $opt->[0] }); is ($status, 1, "k5start @{ $opt->[0] } fails"); is ($out, '', ' with no output'); is ($err, 'k5start: ' . $opt->[1] . "\n", ' and correct error'); } kstart-4.1/tests/k5start/non-renewable-t0000755000175000000000000000460511702213030015246 00000000000000#!/usr/bin/perl -w # # Ensure that non-renewable tickets don't cause spurious failure. # # k5start 4.0 had a bug where if tickets weren't renewable, k5start -H 1 would # attempt to reauthenticate. Ensure that bug doesn't recur. # # Written by Russ Allbery # Copyright 2012 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # We have to generate a local krb5.conf that disables any attempt to get # renewable tickets. Try to locate the local krb5.conf that we're supposed to # use and skip if we can't find one. my $krb5conf = $ENV{KRB5_CONFIG}; unless ($krb5conf) { for my $path ('/etc', '/usr/local/etc', "$ENV{BUILD}/data") { if (-r "$path/krb5.conf") { $krb5conf = "$path/krb5.conf"; last; } } } if ($krb5conf) { open (CONF, '<', $krb5conf) or BAIL_OUT ("cannot open $krb5conf: $!"); open (NEWCONF, '>', './krb5.conf') or BAIL_OUT ("cannot create krb5.conf: $!"); while () { next if /^\s*renew_lifetime\b/; print NEWCONF $_; } close CONF; close NEWCONF; $ENV{KRB5_CONFIG} = './krb5.conf'; } else { plan skip_all => "no krb5.conf found, set KRB5_CONFIG"; exit 0; } # Decide whether we have the configuration to run the tests. my $principal; if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { unlink 'krb5.conf'; plan skip_all => "no keytab configuration"; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'krb5cc_test'; unlink 'krb5cc_test'; unless (kinit ("$DATA/test.keytab", $principal, '-l', '1h')) { unlink 'krb5.conf'; plan skip_all => 'cannot get non-renewable tickets'; exit 0; } plan tests => 3; } # Now, k5start should start without reauthenticating. my ($out, $err, $status) = command ($K5START, '-H', '20', '-f', '/nonexistent', $principal); is ($status, 0, 'k5start -H 20 succeeds without reauthenticating'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); # Clean up. unlink 'krb5cc_test', 'krb5.conf'; kstart-4.1/tests/k5start/basic-t0000755000175000000000000003022611702213030013571 00000000000000#!/usr/bin/perl -w # # Tests for basic k5start functionality. # # Written by Russ Allbery # Copyright 2008, 2009 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") { plan tests => 89; } else { plan skip_all => 'no keytab configuration'; exit 0; } # Get the test principal. my $principal = contents ("$DATA/test.principal"); # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Basic authentication test. unlink 'krb5cc_test'; my ($out, $err, $status) = command ($K5START, '-f', "$DATA/test.keytab", $principal); is ($status, 0, 'Basic k5start command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); my ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); # Specify the full principal with -u. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-u', $principal, '-f', "$DATA/test.keytab"); is ($status, 0, 'k5start -u succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); # If we have a principal with an instance, try -u and -i. my ($name, $inst) = ($principal =~ m%^([^/\@]+)(?:/([^\@]+))%); SKIP: { skip 'test principal has no instance', 5 unless $inst; unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-u', $name, '-i', $inst, '-f', "$DATA/test.keytab"); is ($status, 0, 'k5start -u -i succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); } # Now with -U it should figure out the principal itself. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-Uf', "$DATA/test.keytab"); is ($status, 0, 'k5start -U succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); # Test quiet and an explicit ticket cache. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-k', 'krb5cc_test2', '-qUf', "$DATA/test.keytab"); is ($status, 0, 'k5start -k -q succeeds'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); ($default, $service) = klist (); is ($default, undef, ' and the normal ticket cache is untouched'); $ENV{KRB5CCNAME} = 'krb5cc_test2'; ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' but the other has the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); unlink 'krb5cc_test2'; $ENV{KRB5CCNAME} = 'krb5cc_test'; # Test lifetime. Hopefully even a test principal can get a five minute # ticket lifetime. We don't bother to try to parse klist output to figure # out the lifetime, but instead check it using the -H option. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-l', '5m', '-qUf', "$DATA/test.keytab"); is ($status, 0, 'k5start -l 5m succeeds'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' and the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); ($out, $err, $status) = command ($K5START, '-H', '4', '-f', '/nonexistent', $principal); is ($status, 0, ' and k5start -H succeeds without reauthenticating'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); ($out, $err, $status) = command ($K5START, '-H', '10', '-f', '/nonexistent', $principal); is ($status, 1, ' but fails if we need a 10 minute ticket'); like ($err, qr/^k5start: error getting credentials: /, ' with the right error'); is ($out, '', ' and no output'); # Test obtaining new tickets with -H. ($out, $err, $status) = command ($K5START, '-qH', '10', '-Uf', "$DATA/test.keytab"); is ($status, 0, 'k5start -H succeeds with new tickets'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' and the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); ($out, $err, $status) = command ($K5START, '-H', '10', '-f', '/nonexistent', $principal); is ($status, 0, ' and k5start -H 10 succeeds without reauthenticating'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); # Attempt to authenticate as some other principal. This should fail even # though we have a valid ticket, since we don't have a valid ticket for the # principal we want. ($out, $err, $status) = command ($K5START, '-H', 10, '-f', '/nonexistent', 'bogus@EXAMPLE.COM'); is ($status, 1, ' and k5start -H 10 bogus tries to reauthenticate'); like ($err, qr/^k5start: error getting credentials: /, ' with correct error'); is ($out, '', ' and no output'); # Get a ticket for ourselves rather than a krbtgt and test verbose. We # need an instance here or we get weird results due to the defaults if -I # isn't provided. SKIP: { skip 'test principal has no instance', 8 unless $inst; unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-S', $name, '-I', $inst, '-vUf', "$DATA/test.keytab"); is ($status, 0, 'k5start -S -I succeeds'); is ($err, '', ' with no errors'); my $short = $principal; $short =~ s/\@stanford\.edu$//; like ($out, qr/^Kerberos\ initialization\ for\ \Q$principal\E(\@\S+)? \ for\ service\ \Q$short\E(\@\S+)?\n k5start:\ authenticating\ as\ \Q$principal\E(\@\S+)?\n k5start:\ getting\ tickets\ for \ \Q$principal\E(\@\S+)?\n\z/x, ' and the right output'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr/^\Q$principal\E(\@\S+)?\z/, ' and the right service'); # We now don't have a krbtgt ticket, so a regular k5start -H will attempt # to reauthenticate. ($out, $err, $status) = command ($K5START, '-H', 10, '-f', '/nonexistent', $principal); is ($status, 1, ' and k5start -H 10 tries to reauthenticate'); like ($err, qr/^k5start: error getting credentials: /, ' with correct error'); is ($out, '', ' and no output'); } # Test running a command without the principal. klist may fail if we have # no K4 tickets since we're not giving the -5 option; allow for that # (we'll catch real failures in the regex match on the output). unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab", 'klist'); ok ($status == 0 || $status == 1, 'k5start with command succeeds'); ok ($err eq '' || $err eq "klist: You have no tickets cached\n", ' with no or expected errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); my ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test running a command without the principal prefixed by --. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab", '--', 'klist', '-5'); is ($status, 0, 'k5start with command and -- succeeds'); is ($err, '', ' with no errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test running a command with the principal. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qf', "$DATA/test.keytab", $principal, 'klist'); ok ($status == 0 || $status == 1, 'k5start with command and principal succeeds'); ok ($err eq '' || $err eq "klist: You have no tickets cached\n", ' with no or expected errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test running a command with the principal and a command prefixed by --. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qf', "$DATA/test.keytab", $principal, '--', 'klist', '-5'); is ($status, 0, 'k5start with command, principal, and -- succeeds'); is ($err, '', ' with no errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test running a command with the principal specified with -u. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-u', $principal, '-qf', "$DATA/test.keytab", 'klist'); ok ($status == 0 || $status == 1, 'k5start with command and -u succeeds'); ok ($err eq '' || $err eq "klist: You have no tickets cached\n", ' with no or expected errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test running a command with the principal specified with -u and -- # before the command. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-u', $principal, '-qf', "$DATA/test.keytab", '--', 'klist', '-5'); is ($status, 0, 'k5start with command, -u, and -- succeeds'); is ($err, '', ' with no errors'); like ($out, qr,^(Credentials|Ticket)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); # Test propagation of exit status from a command. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-Uqf', "$DATA/test.keytab", '--', 'sh', '-c', 'exit 3'); is ($status, 3, 'k5start of exit 3 returns correct exit status'); is ($err, '', ' with no errors'); ok (!-f 'krb5cc_test', ' and the default cache file was not created'); # Clean up. unlink 'krb5cc_test'; kstart-4.1/tests/k5start/sigchld-t0000755000175000000000000000375311702213030014132 00000000000000#!/usr/bin/perl -w # # Test for proper SIGCHLD handling in k5start. # # Written by Russ Allbery # Copyright 2010 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use POSIX qw(SIGCHLD SIGCONT SIGSTOP SIGTERM); use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") { plan tests => 2; } else { plan skip_all => 'no keytab configuration'; exit 0; } # Get the test principal. my $principal = contents ("$DATA/test.principal"); # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # We're going to test multiple receipt of SIGCHLD and see if k5start loses # track of the signal handler and then keeps running until its timeout period. my $start = time; my $pid = fork; if (not defined $pid) { BAIL_OUT ("cannot fork: $!\n"); } elsif ($pid == 0) { exec ($K5START, '-qUf', "$DATA/test.keytab", '-K60', '-c', 'child-pid', '--', 'sleep', '100'); } else { sleep 1; kill (SIGCHLD, $pid) or BAIL_OUT ("cannot send SIGCHLD to child $pid\n"); } open (CHILD, '<', 'child-pid') or BAIL_OUT ("cannot open child-pid: $!\n"); my $child = ; close CHILD; chomp $child; unless (kill (0, $child)) { BAIL_OUT ("cannot locate child process $child\n"); } kill (SIGSTOP, $child) or BAIL_OUT ("cannot send SIGSTOP to child $child\n"); sleep 1; kill (SIGCONT, $child) or BAIL_OUT ("cannot send SIGCONT to child $child\n"); sleep 1; kill (SIGTERM, $child) or BAIL_OUT ("cannot send SIGTERM to child $child\n"); waitpid ($pid, 0); is ($?, 0, 'command succeeded'); ok (time < $start + 5, 'k5start got SIGCHLD and woke up properly'); unlink 'child-pid'; kstart-4.1/tests/k5start/daemon-t0000755000175000000000000002623411702213030013757 00000000000000#!/usr/bin/perl -w # # Tests for k5start daemon functionality. # # Written by Russ Allbery # Copyright 2008, 2009, 2011, 2012 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Cwd; use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # The path to our temporary directory used for test ticket caches and the # like. our $TMP = "$ENV{BUILD}/tmp"; unless (-d $TMP) { mkdir $TMP or BAIL_OUT ("cannot create $TMP: $!"); } # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") { plan tests => 76; } else { plan skip_all => "no keytab configuration"; exit 0; } # Get the test principal. my $principal = contents ("$DATA/test.principal"); # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = "$TMP/krb5cc_test"; # Start a k5start daemon and be sure it gets tickets and stays running. unlink "$TMP/krb5cc_test"; my $pid = fork; if (!defined $pid) { BAIL_OUT ("can't fork: $!"); } elsif ($pid == 0) { exec ($K5START, '-K', 1, '-f', "$DATA/test.keytab", '-p', "$TMP/pid", $principal) or BAIL_OUT ("can't run $K5START: $!"); } my $tries = 0; while (not -f "$TMP/krb5cc_test" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } my ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, 'Authentication succeeded for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); if (-f "$TMP/pid") { my $daemon = contents ("$TMP/pid"); is ($pid, $daemon, ' and the right PID is written'); $pid = $daemon if $daemon; } else { ok (0, ' and the right PID is written'); } ok (kill (0, $pid), ' and k5start is still running'); unlink "$TMP/krb5cc_test"; ok (! -f "$TMP/krb5cc_test", 'Ticket cache was deleted'); kill (14, $pid) or warn "Can't kill $pid: $!\n"; $tries = 0; while (not -f "$TMP/krb5cc_test" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } ok (kill (0, $pid), ' and k5start is still running after ALRM'); ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' and recreates cache with the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); kill (15, $pid) or warn "Can't kill $pid: $!\n"; is (waitpid ($pid, 0), $pid, ' and k5start dies after SIGTERM'); ok (!-f "$TMP/pid", ' and the PID file was removed'); # Try again with the -b flag. unlink "$TMP/krb5cc_test"; my ($out, $err, $status) = command ($K5START, '-bK', 1, '-f', "$DATA/test.keytab", '-p', "$TMP/pid", $principal); is ($status, 0, 'Backgrounding k5start works'); is ($err, '', ' with no error output'); is ($out, '', ' and -q was added implicitly'); $tries = 0; while (not -f "$TMP/krb5cc_test" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, 'Authentication succeeded for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); $pid = contents ("$TMP/pid"); ok (kill (0, $pid), ' and the PID file is correct'); kill (15, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!-f "$TMP/pid", ' and the PID file was removed'); # Check that k5start keeps running if the ticket cache directory is not # writeable. $pid = fork; if (!defined $pid) { BAIL_OUT ("can't fork: $!"); } elsif ($pid == 0) { open (STDERR, '>', "$TMP/k5start-errors") or BAIL_OUT ("can't create $TMP/k5start-errors: $!"); exec ($K5START, '-K', 1, '-Uf', "$DATA/test.keytab", '-p', "$TMP/pid") or BAIL_OUT ("can't run $K5START: $!"); } $tries = 0; while (not -f "$TMP/pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'k5start -K 1 started'); chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (kill (0, $pid), ' and it keeps running on a non-writeable cache'); chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); if (open (ERRORS, '<', "$TMP/k5start-errors")) { like (scalar (), qr/^k5start: error initializing ticket cache: /, ' and the correct error message'); } else { ok (0, ' and the correct error message'); } unlink "$TMP/k5start-errors"; kill (15, $pid) or warn "Can't kill $pid: $!\n"; is (waitpid ($pid, 0), $pid, ' and k5start dies after SIGTERM'); ok (!-f "$TMP/pid", ' and the PID file was removed'); # If we do that again with -x, k5start should exit. ($out, $err, $status) = command ($K5START, '-xbK', 1, '-f', "$DATA/test.keytab", '-p', "$TMP/pid", $principal); is ($status, 0, 'k5start -xb works'); is ($err, '', ' with no error output'); is ($out, '', ' and -q was added implicitly'); $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'k5start -xb started'); chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (!kill (0, $pid), ' and it exits on a non-writeable cache'); chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); unlink "$TMP/pid"; # Now, run a command in the background. unlink "$TMP/krb5cc_test", "$TMP/krb5cc_child", "$TMP/child-out"; ($out, $err, $status) = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f', "$DATA/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid", $principal, '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding k5start works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } ($default, $service) = klist (); is ($default, undef, 'The normal ticket cache is untouched'); $ENV{KRB5CCNAME} = "$TMP/krb5cc_child"; ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' but the other cache has the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'k5start is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } kill (1, $child) or warn "Cannot send HUP to child $child: $!\n"; select (undef, undef, undef, 0.1); kill (2, $child) or warn "Cannot send INT to child $child: $!\n"; select (undef, undef, undef, 0.1); kill (15, $child) or warn "Cannot send TERM to child $child: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'k5start is no longer running'); ok (!kill (0, $child), 'The child process is no longer running'); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); is (scalar (), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct'); is (scalar (), "got SIGHUP\n", 'SIGHUP was recorded'); is (scalar (), "got SIGINT\n", 'SIGINT was recorded'); is (scalar (), "got SIGTERM\n", 'SIGTERM was recorded'); ok (eof OUT, 'No more child output written'); close OUT; ok (!-f "$TMP/pid", 'PID file cleaned up'); ok (!-f "$TMP/child-pid", 'Child PID file cleaned up'); # Now, do that again, but test signal propagation from the parent to the # child. unlink "$TMP/krb5cc_child", "$TMP/child-out"; ($out, $err, $status) = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f', "$DATA/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid", $principal, '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding k5start works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'k5start is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } kill (1, $pid) or warn "Cannot send HUP to parent $pid: $!\n"; select (undef, undef, undef, 0.1); kill (2, $pid) or warn "Cannot send INT to parent $pid: $!\n"; select (undef, undef, undef, 0.1); kill (15, $pid) or warn "Cannot send TERM to parent $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'k5start is no longer running'); ok (!kill (0, $child), 'The child process is no longer running'); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); is (scalar (), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct'); is (scalar (), "got SIGHUP\n", 'SIGHUP was propagated'); is (scalar (), "got SIGINT\n", 'SIGINT was propagated'); is (scalar (), "got SIGTERM\n", 'SIGTERM was propagated'); ok (eof OUT, 'No more child output written'); close OUT; ok (!-f "$TMP/pid", 'PID file cleaned up'); ok (!-f "$TMP/child-pid", 'Child PID file cleaned up'); # One more time to test SIGQUIT. unlink "$TMP/krb5cc_child", "$TMP/child-out"; ($out, $err, $status) = command ($K5START, '-bK', 1, '-k', "$TMP/krb5cc_child", '-f', "$DATA/test.keytab", '-p', "$TMP/pid", '-c', "$TMP/child-pid", $principal, '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding k5start works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'k5start is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } kill (3, $pid) or warn "Cannot send QUIT to parent $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'k5start is no longer running'); ok (!kill (0, $child), 'The child process is no longer running'); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); is (scalar (), "FILE:$TMP/krb5cc_child\n", 'Child cache is correct'); is (scalar (), "got SIGQUIT\n", 'SIGQUIT was propagated'); ok (eof OUT, 'No more child output written'); close OUT; ok (!-f "$TMP/pid", 'PID file cleaned up'); ok (!-f "$TMP/child-pid", 'Child PID file cleaned up'); # Clean up. unlink "$TMP/krb5cc_child", "$TMP/child-out"; rmdir $TMP; kstart-4.1/tests/k5start/perms-t0000755000175000000000000001015511702213030013635 00000000000000#!/usr/bin/perl -w # # Tests for k5start handling of ticket permissions. # # Written by Russ Allbery # Copyright 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $K5START = "$ENV{BUILD}/../k5start"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # This test requires running under fakeroot, and therefore can't run unless # fakeroot is available (or it's run as root, although that's a bad idea). if ($> != 0) { if (defined $ENV{TRY_FAKEROOT}) { plan skip_all => 'fakeroot not available'; exit 0; } $ENV{TRY_FAKEROOT} = 'trying'; unless (exec ('fakeroot', "$ENV{SOURCE}/k5start/perms-t")) { plan skip_all => 'fakeroot not available'; exit 0; } } # Decide whether we have the configuration to run the tests. if (-f "$DATA/test.keytab" and -f "$DATA/test.principal") { plan tests => 34; } else { plan skip_all => 'no keytab configuration'; exit 0; } # Get the test principal. my $principal = contents ("$DATA/test.principal"); # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Basic authentication test. unlink 'krb5cc_test'; my ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab"); is ($status, 0, 'Basic k5start command succeeds'); is ($err, '', ' with no errors'); my ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0600, ' mode is correct'); is ($uid, 0, ' owner is correct'); is ($gid, 0, ' group is correct'); # Basic authentication test with -o, -g, and -m. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-Uf', "$DATA/test.keytab", '-o', 42, '-g', 42, '-m', 440); is ($status, 0, 'k5start -o 42 -g 42 -m 440 succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); my ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0440, ' mode is correct'); is ($uid, 42, ' owner is correct'); is ($gid, 42, ' group is correct'); # Just -o. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab", '-o', 42); is ($status, 0, 'k5start -o 42 succeeds'); is ($err, '', ' with no errors'); ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0600, ' mode is correct'); is ($uid, 42, ' owner is correct'); is ($gid, 0, ' group is correct'); # Just -g. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab", '-g', 42); is ($status, 0, 'k5start -g 42 succeeds'); is ($err, '', ' with no errors'); ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0600, ' mode is correct'); is ($uid, 0, ' owner is correct'); is ($gid, 42, ' group is correct'); # Just -m. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-qUf', "$DATA/test.keytab", '-m', 400); is ($status, 0, 'k5start -m 400 succeeds'); is ($err, '', ' with no errors'); ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0400, ' mode is correct'); is ($uid, 0, ' owner is correct'); is ($gid, 0, ' group is correct'); # Test handling of FILE: prefixes for the cache. unlink 'krb5cc_test'; ($out, $err, $status) = command ($K5START, '-Uf', "$DATA/test.keytab", '-o', 42, '-g', 42, '-m', 440, '-k', 'FILE:krb5cc_test'); is ($status, 0, 'k5start -o 42 -g 42 -m 440 -k succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^Kerberos initialization for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); ($mode, $uid, $gid) = (stat 'krb5cc_test')[2, 4, 5]; is (($mode & 0777), 0440, ' mode is correct'); is ($uid, 42, ' owner is correct'); is ($gid, 42, ' group is correct'); # Clean up. unlink 'krb5cc_test'; kstart-4.1/tests/tap/0000755000175000000000000000000011702213052011571 500000000000000kstart-4.1/tests/tap/basic.h0000644000175000000000000001363511702213030012747 00000000000000/* * Basic utility routines for the TAP protocol. * * This file is part of C TAP Harness. The current version plus supporting * documentation is at . * * Copyright 2009, 2010, 2011 Russ Allbery * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef TAP_BASIC_H #define TAP_BASIC_H 1 #include /* va_list */ #include /* size_t */ /* * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7 * could you use the __format__ form of the attributes, which is what we use * (to avoid confusion with other macros). */ #ifndef __attribute__ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) # define __attribute__(spec) /* empty */ # endif #endif /* * BEGIN_DECLS is used at the beginning of declarations so that C++ * compilers don't mangle their names. END_DECLS is used at the end. */ #undef BEGIN_DECLS #undef END_DECLS #ifdef __cplusplus # define BEGIN_DECLS extern "C" { # define END_DECLS } #else # define BEGIN_DECLS /* empty */ # define END_DECLS /* empty */ #endif /* * Used for iterating through arrays. ARRAY_SIZE returns the number of * elements in the array (useful for a < upper bound in a for loop) and * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it * legal to refer to such a pointer as long as it's never dereferenced). */ #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) #define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)]) BEGIN_DECLS /* * The test count. Always contains the number that will be used for the next * test status. */ extern unsigned long testnum; /* Print out the number of tests and set standard output to line buffered. */ void plan(unsigned long count); /* * Prepare for lazy planning, in which the plan will be printed automatically * at the end of the test program. */ void plan_lazy(void); /* Skip the entire test suite. Call instead of plan. */ void skip_all(const char *format, ...) __attribute__((__noreturn__, __format__(printf, 1, 2))); /* * Basic reporting functions. The okv() function is the same as ok() but * takes the test description as a va_list to make it easier to reuse the * reporting infrastructure when writing new tests. */ void ok(int success, const char *format, ...) __attribute__((__format__(printf, 2, 3))); void okv(int success, const char *format, va_list args); void skip(const char *reason, ...) __attribute__((__format__(printf, 1, 2))); /* Report the same status on, or skip, the next count tests. */ void ok_block(unsigned long count, int success, const char *format, ...) __attribute__((__format__(printf, 3, 4))); void skip_block(unsigned long count, const char *reason, ...) __attribute__((__format__(printf, 2, 3))); /* Check an expected value against a seen value. */ void is_int(long wanted, long seen, const char *format, ...) __attribute__((__format__(printf, 3, 4))); void is_double(double wanted, double seen, double epsilon, const char *format, ...) __attribute__((__format__(printf, 4, 5))); void is_string(const char *wanted, const char *seen, const char *format, ...) __attribute__((__format__(printf, 3, 4))); void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) __attribute__((__format__(printf, 3, 4))); /* Bail out with an error. sysbail appends strerror(errno). */ void bail(const char *format, ...) __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); void sysbail(const char *format, ...) __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); /* Report a diagnostic to stderr prefixed with #. */ void diag(const char *format, ...) __attribute__((__nonnull__, __format__(printf, 1, 2))); void sysdiag(const char *format, ...) __attribute__((__nonnull__, __format__(printf, 1, 2))); /* Allocate memory, reporting a fatal error with bail on failure. */ void *bcalloc(size_t, size_t) __attribute__((__alloc_size__(1, 2), __malloc__)); void *bmalloc(size_t) __attribute__((__alloc_size__(1), __malloc__)); void *brealloc(void *, size_t) __attribute__((__alloc_size__(2), __malloc__)); char *bstrdup(const char *) __attribute__((__malloc__, __nonnull__)); /* * Find a test file under BUILD or SOURCE, returning the full path. The * returned path should be freed with test_file_path_free(). */ char *test_file_path(const char *file) __attribute__((__malloc__, __nonnull__)); void test_file_path_free(char *path); /* * Create a temporary directory relative to BUILD and return the path. The * returned path should be freed with test_tmpdir_free. */ char *test_tmpdir(void) __attribute__((__malloc__)); void test_tmpdir_free(char *path); END_DECLS #endif /* TAP_BASIC_H */ kstart-4.1/tests/tap/libtap.sh0000644000175000000000000001562411702213030013324 00000000000000# Shell function library for test cases. # # This file provides a TAP-compatible shell function library useful for # writing test cases. It is part of C TAP Harness, which can be found at # . # # Written by Russ Allbery # Copyright 2009, 2010, 2011 Russ Allbery # Copyright 2006, 2007, 2008 # The Board of Trustees of the Leland Stanford Junior University # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # Print out the number of test cases we expect to run. plan () { count=1 planned="$1" failed=0 echo "1..$1" trap finish 0 } # Prepare for lazy planning. plan_lazy () { count=1 planned=0 failed=0 trap finish 0 } # Report the test status on exit. finish () { local highest looks highest=`expr "$count" - 1` if [ "$planned" = 0 ] ; then echo "1..$highest" planned="$highest" fi looks='# Looks like you' if [ "$planned" -gt 0 ] ; then if [ "$planned" -gt "$highest" ] ; then if [ "$planned" -gt 1 ] ; then echo "$looks planned $planned tests but only ran $highest" else echo "$looks planned $planned test but only ran $highest" fi elif [ "$planned" -lt "$highest" ] ; then local extra extra=`expr "$highest" - "$planned"` if [ "$planned" -gt 1 ] ; then echo "$looks planned $planned tests but ran $extra extra" else echo "$looks planned $planned test but ran $extra extra" fi elif [ "$failed" -gt 0 ] ; then if [ "$failed" -gt 1 ] ; then echo "$looks failed $failed tests of $planned" else echo "$looks failed $failed test of $planned" fi elif [ "$planned" -gt 1 ] ; then echo "# All $planned tests successful or skipped" else echo "# $planned test successful or skipped" fi fi } # Skip the entire test suite. Should be run instead of plan. skip_all () { local desc desc="$1" if [ -n "$desc" ] ; then echo "1..0 # skip $desc" else echo "1..0 # skip" fi exit 0 } # ok takes a test description and a command to run and prints success if that # command is successful, false otherwise. The count starts at 1 and is # updated each time ok is printed. ok () { local desc desc="$1" if [ -n "$desc" ] ; then desc=" - $desc" fi shift if "$@" ; then echo ok $count$desc else echo not ok $count$desc failed=`expr $failed + 1` fi count=`expr $count + 1` } # Skip the next test. Takes the reason why the test is skipped. skip () { echo "ok $count # skip $*" count=`expr $count + 1` } # Report the same status on a whole set of tests. Takes the count of tests, # the description, and then the command to run to determine the status. ok_block () { local end i desc i=$count end=`expr $count + $1` shift desc="$1" shift while [ "$i" -lt "$end" ] ; do ok "$desc" "$@" i=`expr $i + 1` done } # Skip a whole set of tests. Takes the count and then the reason for skipping # the test. skip_block () { local i end i=$count end=`expr $count + $1` shift while [ "$i" -lt "$end" ] ; do skip "$@" i=`expr $i + 1` done } # Portable variant of printf '%s\n' "$*". In the majority of cases, this # function is slower than printf, because the latter is often implemented # as a builtin command. The value of the variable IFS is ignored. puts () { cat << EOH $@ EOH } # Run a program expected to succeed, and print ok if it does and produces the # correct output. Takes the description, expected exit status, the expected # output, the command to run, and then any arguments for that command. # Standard output and standard error are combined when analyzing the output of # the command. # # If the command may contain system-specific error messages in its output, # add strip_colon_error before the command to post-process its output. ok_program () { local desc w_status w_output output status desc="$1" shift w_status="$1" shift w_output="$1" shift output=`"$@" 2>&1` status=$? if [ $status = $w_status ] && [ x"$output" = x"$w_output" ] ; then ok "$desc" true else echo "# saw: ($status) $output" echo "# not: ($w_status) $w_output" ok "$desc" false fi } # Strip a colon and everything after it off the output of a command, as long # as that colon comes after at least one whitespace character. (This is done # to avoid stripping the name of the program from the start of an error # message.) This is used to remove system-specific error messages (coming # from strerror, for example). strip_colon_error() { local output status output=`"$@" 2>&1` status=$? output=`puts "$output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'` puts "$output" return $status } # Bail out with an error message. bail () { echo 'Bail out!' "$@" exit 1 } # Output a diagnostic on standard error, preceded by the required # mark. diag () { echo '#' "$@" } # Search for the given file first in $BUILD and then in $SOURCE and echo the # path where the file was found, or the empty string if the file wasn't # found. test_file_path () { if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then puts "$BUILD/$1" elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then puts "$SOURCE/$1" else echo '' fi } # Create $BUILD/tmp for use by tests for storing temporary files and return # the path (via standard output). test_tmpdir () { local tmpdir if [ -z "$BUILD" ] ; then tmpdir="./tmp" else tmpdir="$BUILD"/tmp fi if [ ! -d "$tmpdir" ] ; then mkdir "$tmpdir" || bail "Error creating $tmpdir" fi puts "$tmpdir" } kstart-4.1/tests/tap/basic.c0000644000175000000000000003567311702213030012750 00000000000000/* * Some utility routines for writing tests. * * Here are a variety of utility routines for writing tests compatible with * the TAP protocol. All routines of the form ok() or is*() take a test * number and some number of appropriate arguments, check to be sure the * results match the expected output using the arguments, and print out * something appropriate for that test number. Other utility routines help in * constructing more complex tests, skipping tests, or setting up the TAP * output format. * * This file is part of C TAP Harness. The current version plus supporting * documentation is at . * * Copyright 2009, 2010, 2011 Russ Allbery * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* Required for isnan() and isinf(). */ #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif #include #include #include #include #include #include #ifdef _WIN32 # include #else # include #endif #include #include #include /* Windows provides mkdir and rmdir under different names. */ #ifdef _WIN32 # define mkdir(p, m) _mkdir(p) # define rmdir(p) _rmdir(p) #endif /* * The test count. Always contains the number that will be used for the next * test status. */ unsigned long testnum = 1; /* * Status information stored so that we can give a test summary at the end of * the test case. We store the planned final test and the count of failures. * We can get the highest test count from testnum. * * We also store the PID of the process that called plan() and only summarize * results when that process exits, so as to not misreport results in forked * processes. * * If _lazy is true, we're doing lazy planning and will print out the plan * based on the last test number at the end of testing. */ static unsigned long _planned = 0; static unsigned long _failed = 0; static pid_t _process = 0; static int _lazy = 0; /* * Our exit handler. Called on completion of the test to report a summary of * results provided we're still in the original process. */ static void finish(void) { unsigned long highest = testnum - 1; if (_planned == 0 && !_lazy) return; fflush(stderr); if (_process != 0 && getpid() == _process) { if (_lazy) { printf("1..%lu\n", highest); _planned = highest; } if (_planned > highest) printf("# Looks like you planned %lu test%s but only ran %lu\n", _planned, (_planned > 1 ? "s" : ""), highest); else if (_planned < highest) printf("# Looks like you planned %lu test%s but ran %lu extra\n", _planned, (_planned > 1 ? "s" : ""), highest - _planned); else if (_failed > 0) printf("# Looks like you failed %lu test%s of %lu\n", _failed, (_failed > 1 ? "s" : ""), _planned); else if (_planned > 1) printf("# All %lu tests successful or skipped\n", _planned); else printf("# %lu test successful or skipped\n", _planned); } } /* * Initialize things. Turns on line buffering on stdout and then prints out * the number of tests in the test suite. */ void plan(unsigned long count) { if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) fprintf(stderr, "# cannot set stdout to line buffered: %s\n", strerror(errno)); fflush(stderr); printf("1..%lu\n", count); testnum = 1; _planned = count; _process = getpid(); atexit(finish); } /* * Initialize things for lazy planning, where we'll automatically print out a * plan at the end of the program. Turns on line buffering on stdout as well. */ void plan_lazy(void) { if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) fprintf(stderr, "# cannot set stdout to line buffered: %s\n", strerror(errno)); testnum = 1; _process = getpid(); _lazy = 1; atexit(finish); } /* * Skip the entire test suite and exits. Should be called instead of plan(), * not after it, since it prints out a special plan line. */ void skip_all(const char *format, ...) { fflush(stderr); printf("1..0 # skip"); if (format != NULL) { va_list args; putchar(' '); va_start(args, format); vprintf(format, args); va_end(args); } putchar('\n'); exit(0); } /* * Print the test description. */ static void print_desc(const char *format, va_list args) { printf(" - "); vprintf(format, args); } /* * Takes a boolean success value and assumes the test passes if that value * is true and fails if that value is false. */ void ok(int success, const char *format, ...) { fflush(stderr); printf("%sok %lu", success ? "" : "not ", testnum++); if (!success) _failed++; if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } /* * Same as ok(), but takes the format arguments as a va_list. */ void okv(int success, const char *format, va_list args) { fflush(stderr); printf("%sok %lu", success ? "" : "not ", testnum++); if (!success) _failed++; if (format != NULL) print_desc(format, args); putchar('\n'); } /* * Skip a test. */ void skip(const char *reason, ...) { fflush(stderr); printf("ok %lu # skip", testnum++); if (reason != NULL) { va_list args; va_start(args, reason); putchar(' '); vprintf(reason, args); va_end(args); } putchar('\n'); } /* * Report the same status on the next count tests. */ void ok_block(unsigned long count, int status, const char *format, ...) { unsigned long i; fflush(stderr); for (i = 0; i < count; i++) { printf("%sok %lu", status ? "" : "not ", testnum++); if (!status) _failed++; if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } } /* * Skip the next count tests. */ void skip_block(unsigned long count, const char *reason, ...) { unsigned long i; fflush(stderr); for (i = 0; i < count; i++) { printf("ok %lu # skip", testnum++); if (reason != NULL) { va_list args; va_start(args, reason); putchar(' '); vprintf(reason, args); va_end(args); } putchar('\n'); } } /* * Takes an expected integer and a seen integer and assumes the test passes * if those two numbers match. */ void is_int(long wanted, long seen, const char *format, ...) { fflush(stderr); if (wanted == seen) printf("ok %lu", testnum++); else { printf("# wanted: %ld\n# seen: %ld\n", wanted, seen); printf("not ok %lu", testnum++); _failed++; } if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } /* * Takes a string and what the string should be, and assumes the test passes * if those strings match (using strcmp). */ void is_string(const char *wanted, const char *seen, const char *format, ...) { if (wanted == NULL) wanted = "(null)"; if (seen == NULL) seen = "(null)"; fflush(stderr); if (strcmp(wanted, seen) == 0) printf("ok %lu", testnum++); else { printf("# wanted: %s\n# seen: %s\n", wanted, seen); printf("not ok %lu", testnum++); _failed++; } if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } /* * Takes an expected double and a seen double and assumes the test passes if * those two numbers are within delta of each other. */ void is_double(double wanted, double seen, double epsilon, const char *format, ...) { fflush(stderr); if ((isnan(wanted) && isnan(seen)) || (isinf(wanted) && isinf(seen) && wanted == seen) || fabs(wanted - seen) <= epsilon) printf("ok %lu", testnum++); else { printf("# wanted: %g\n# seen: %g\n", wanted, seen); printf("not ok %lu", testnum++); _failed++; } if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } /* * Takes an expected unsigned long and a seen unsigned long and assumes the * test passes if the two numbers match. Otherwise, reports them in hex. */ void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) { fflush(stderr); if (wanted == seen) printf("ok %lu", testnum++); else { printf("# wanted: %lx\n# seen: %lx\n", (unsigned long) wanted, (unsigned long) seen); printf("not ok %lu", testnum++); _failed++; } if (format != NULL) { va_list args; va_start(args, format); print_desc(format, args); va_end(args); } putchar('\n'); } /* * Bail out with an error. */ void bail(const char *format, ...) { va_list args; fflush(stderr); fflush(stdout); printf("Bail out! "); va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); exit(1); } /* * Bail out with an error, appending strerror(errno). */ void sysbail(const char *format, ...) { va_list args; int oerrno = errno; fflush(stderr); fflush(stdout); printf("Bail out! "); va_start(args, format); vprintf(format, args); va_end(args); printf(": %s\n", strerror(oerrno)); exit(1); } /* * Report a diagnostic to stderr. */ void diag(const char *format, ...) { va_list args; fflush(stderr); fflush(stdout); printf("# "); va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); } /* * Report a diagnostic to stderr, appending strerror(errno). */ void sysdiag(const char *format, ...) { va_list args; int oerrno = errno; fflush(stderr); fflush(stdout); printf("# "); va_start(args, format); vprintf(format, args); va_end(args); printf(": %s\n", strerror(oerrno)); } /* * Allocate cleared memory, reporting a fatal error with bail on failure. */ void * bcalloc(size_t n, size_t size) { void *p; p = calloc(n, size); if (p == NULL) sysbail("failed to calloc %lu", (unsigned long)(n * size)); return p; } /* * Allocate memory, reporting a fatal error with bail on failure. */ void * bmalloc(size_t size) { void *p; p = malloc(size); if (p == NULL) sysbail("failed to malloc %lu", (unsigned long) size); return p; } /* * Reallocate memory, reporting a fatal error with bail on failure. */ void * brealloc(void *p, size_t size) { p = realloc(p, size); if (p == NULL) sysbail("failed to realloc %lu bytes", (unsigned long) size); return p; } /* * Copy a string, reporting a fatal error with bail on failure. */ char * bstrdup(const char *s) { char *p; size_t len; len = strlen(s) + 1; p = malloc(len); if (p == NULL) sysbail("failed to strdup %lu bytes", (unsigned long) len); memcpy(p, s, len); return p; } /* * Locate a test file. Given the partial path to a file, look under BUILD and * then SOURCE for the file and return the full path to the file. Returns * NULL if the file doesn't exist. A non-NULL return should be freed with * test_file_path_free(). * * This function uses sprintf because it attempts to be independent of all * other portability layers. The use immediately after a memory allocation * should be safe without using snprintf or strlcpy/strlcat. */ char * test_file_path(const char *file) { char *base; char *path = NULL; size_t length; const char *envs[] = { "BUILD", "SOURCE", NULL }; int i; for (i = 0; envs[i] != NULL; i++) { base = getenv(envs[i]); if (base == NULL) continue; length = strlen(base) + 1 + strlen(file) + 1; path = bmalloc(length); sprintf(path, "%s/%s", base, file); if (access(path, R_OK) == 0) break; free(path); path = NULL; } return path; } /* * Free a path returned from test_file_path(). This function exists primarily * for Windows, where memory must be freed from the same library domain that * it was allocated from. */ void test_file_path_free(char *path) { if (path != NULL) free(path); } /* * Create a temporary directory, tmp, under BUILD if set and the current * directory if it does not. Returns the path to the temporary directory in * newly allocated memory, and calls bail on any failure. The return value * should be freed with test_tmpdir_free. * * This function uses sprintf because it attempts to be independent of all * other portability layers. The use immediately after a memory allocation * should be safe without using snprintf or strlcpy/strlcat. */ char * test_tmpdir(void) { const char *build; char *path = NULL; size_t length; build = getenv("BUILD"); if (build == NULL) build = "."; length = strlen(build) + strlen("/tmp") + 1; path = bmalloc(length); sprintf(path, "%s/tmp", build); if (access(path, X_OK) < 0) if (mkdir(path, 0777) < 0) sysbail("error creating temporary directory %s", path); return path; } /* * Free a path returned from test_tmpdir() and attempt to remove the * directory. If we can't delete the directory, don't worry; something else * that hasn't yet cleaned up may still be using it. */ void test_tmpdir_free(char *path) { rmdir(path); if (path != NULL) free(path); } kstart-4.1/tests/tap/process.h0000644000175000000000000000522211702213030013335 00000000000000/* * Utility functions for tests that use subprocesses. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2009, 2010 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef TAP_PROCESS_H #define TAP_PROCESS_H 1 #include #include BEGIN_DECLS /* * Run a function in a subprocess and check the exit status and expected * output (stdout and stderr combined) against the provided values. Expects * the function to always exit (not die from a signal). data is optional data * that's passed into the function as its only argument. * * This reports as three separate tests: whether the function exited rather * than was killed, whether the exit status was correct, and whether the * output was correct. */ typedef void (*test_function_type)(void *); void is_function_output(test_function_type, void *data, int status, const char *output, const char *format, ...) __attribute__((__format__(printf, 5, 6), __nonnull__(1))); /* * Run a setup program. Takes the program to run and its arguments as an argv * vector, where argv[0] must be either the full path to the program or the * program name if the PATH should be searched. If the program does not exit * successfully, call bail, with the error message being the output from the * program. */ void run_setup(const char *const argv[]) __attribute__((__nonnull__)); END_DECLS #endif /* TAP_PROCESS_H */ kstart-4.1/tests/tap/process.c0000644000175000000000000001326611702213030013337 00000000000000/* * Utility functions for tests that use subprocesses. * * Provides utility functions for subprocess manipulation. Specifically, * provides a function, run_setup, which runs a command and bails if it fails, * using its error message as the bail output, and is_function_output, which * runs a function in a subprocess and checks its output and exit status * against expected values. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2002, 2004, 2005 Russ Allbery * Copyright 2009, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include /* * Given a function, an expected exit status, and expected output, runs that * function in a subprocess, capturing stdout and stderr via a pipe, and * returns the function output in newly allocated memory. Also captures the * process exit status. */ static void run_child_function(test_function_type function, void *data, int *status, char **output) { int fds[2]; pid_t child; char *buf; ssize_t count, ret, buflen; int rval; /* Flush stdout before we start to avoid odd forking issues. */ fflush(stdout); /* Set up the pipe and call the function, collecting its output. */ if (pipe(fds) == -1) sysbail("can't create pipe"); child = fork(); if (child == (pid_t) -1) { sysbail("can't fork"); } else if (child == 0) { /* In child. Set up our stdout and stderr. */ close(fds[0]); if (dup2(fds[1], 1) == -1) _exit(255); if (dup2(fds[1], 2) == -1) _exit(255); /* Now, run the function and exit successfully if it returns. */ (*function)(data); fflush(stdout); _exit(0); } else { /* * In the parent; close the extra file descriptor, read the output if * any, and then collect the exit status. */ close(fds[1]); buflen = BUFSIZ; buf = bmalloc(buflen); count = 0; do { ret = read(fds[0], buf + count, buflen - count - 1); if (ret > 0) count += ret; if (count >= buflen - 1) { buflen += BUFSIZ; buf = brealloc(buf, buflen); } } while (ret > 0); buf[count < 0 ? 0 : count] = '\0'; if (waitpid(child, &rval, 0) == (pid_t) -1) sysbail("waitpid failed"); } /* Store the output and return. */ *status = rval; *output = buf; } /* * Given a function, data to pass to that function, an expected exit status, * and expected output, runs that function in a subprocess, capturing stdout * and stderr via a pipe, and compare the combination of stdout and stderr * with the expected output and the exit status with the expected status. * Expects the function to always exit (not die from a signal). */ void is_function_output(test_function_type function, void *data, int status, const char *output, const char *format, ...) { char *buf, *msg; int rval; va_list args; run_child_function(function, data, &rval, &buf); /* Now, check the results against what we expected. */ va_start(args, format); bvasprintf(&msg, format, args); va_end(args); ok(WIFEXITED(rval), "%s (exited)", msg); is_int(status, WEXITSTATUS(rval), "%s (status)", msg); is_string(output, buf, "%s (output)", msg); free(buf); free(msg); } /* * A helper function for run_setup. This is a function to run an external * command, suitable for passing into run_child_function. The expected * argument must be an argv array, with argv[0] being the command to run. */ static void exec_command(void *data) { char *const *argv = data; execvp(argv[0], argv); } /* * Given a command expressed as an argv struct, with argv[0] the name or path * to the command, run that command. If it exits with a non-zero status, use * the part of its output up to the first newline as the error message when * calling bail. */ void run_setup(const char *const argv[]) { char *output, *p; int status; run_child_function(exec_command, (void *) argv, &status, &output); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { p = strchr(output, '\n'); if (p != NULL) *p = '\0'; bail("%s", output); } free(output); } kstart-4.1/tests/tap/string.c0000644000175000000000000000423511702213030013163 00000000000000/* * String utilities for the TAP protocol. * * Additional string utilities that can't be included with C TAP Harness * because they rely on additional portability code from rra-c-util. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Copyright 2011 Russ Allbery * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include /* * vsprintf into a newly allocated string, reporting a fatal error with bail * on failure. */ int bvasprintf(char **strp, const char *fmt, va_list args) { int status; status = vasprintf(strp, fmt, args); if (status < 0) sysbail("failed to allocate memory for vasprintf"); return status; } /* * sprintf into a newly allocated string, reporting a fatal error with bail on * failure. */ int basprintf(char **strp, const char *fmt, ...) { va_list args; int status; va_start(args, fmt); status = bvasprintf(strp, fmt, args); va_end(args); return status; } kstart-4.1/tests/tap/string.h0000644000175000000000000000362011702213030013165 00000000000000/* * String utilities for the TAP protocol. * * Additional string utilities that can't be included with C TAP Harness * because they rely on additional portability code from rra-c-util. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Copyright 2011 Russ Allbery * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef TAP_STRING_H #define TAP_STRING_H 1 #include #include #include /* va_list */ BEGIN_DECLS /* sprintf into an allocated string, calling bail on allocation failure. */ int basprintf(char **, const char *, ...) __attribute__((__nonnull__, __format__(printf, 2, 3))); int bvasprintf(char **, const char *, va_list) __attribute__((__nonnull__)); END_DECLS #endif /* !TAP_STRING_H */ kstart-4.1/tests/util/0000755000175000000000000000000011702213052011762 500000000000000kstart-4.1/tests/util/xmalloc.c0000644000175000000000000002160411702213030013504 00000000000000/* * Test suite for xmalloc and family. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Copyright 2000, 2001, 2006 Russ Allbery * Copyright 2008 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #line 1 "xmalloc.c" #include #include #include #include #include /* Linux requires sys/time.h be included before sys/resource.h. */ #include #include #include /* * A customized error handler for checking xmalloc's support of them. Prints * out the error message and exits with status 1. */ static void test_handler(const char *function, size_t size, const char *file, int line) { die("%s %lu %s %d", function, (unsigned long) size, file, line); } /* * Allocate the amount of memory given and write to all of it to make sure we * can, returning true if that succeeded and false on any sort of detectable * error. */ static int test_malloc(size_t size) { char *buffer; size_t i; buffer = xmalloc(size); if (buffer == NULL) return 0; if (size > 0) memset(buffer, 1, size); for (i = 0; i < size; i++) if (buffer[i] != 1) return 0; free(buffer); return 1; } /* * Allocate 10 bytes of memory given, write to it, then reallocate to the * desired size, writing to the rest and then checking it all. Returns true * on success, false on any failure. */ static int test_realloc(size_t size) { char *buffer; size_t i; buffer = xmalloc(10); if (buffer == NULL) return 0; memset(buffer, 1, 10); buffer = xrealloc(buffer, size); if (buffer == NULL) return 0; if (size > 0) memset(buffer + 10, 2, size - 10); for (i = 0; i < 10; i++) if (buffer[i] != 1) return 0; for (i = 10; i < size; i++) if (buffer[i] != 2) return 0; free(buffer); return 1; } /* * Generate a string of the size indicated, call xstrdup on it, and then * ensure the result matches. Returns true on success, false on any failure. */ static int test_strdup(size_t size) { char *string, *copy; int match; string = xmalloc(size); if (string == NULL) return 0; memset(string, 1, size - 1); string[size - 1] = '\0'; copy = xstrdup(string); if (copy == NULL) return 0; match = strcmp(string, copy); free(string); free(copy); return (match == 0); } /* * Generate a string of the size indicated plus some, call xstrndup on it, and * then ensure the result matches. Returns true on success, false on any * failure. */ static int test_strndup(size_t size) { char *string, *copy; int match, toomuch; string = xmalloc(size + 1); if (string == NULL) return 0; memset(string, 1, size - 1); string[size - 1] = 2; string[size] = '\0'; copy = xstrndup(string, size - 1); if (copy == NULL) return 0; match = strncmp(string, copy, size - 1); toomuch = strcmp(string, copy); free(string); free(copy); return (match == 0 && toomuch != 0); } /* * Allocate the amount of memory given and check that it's all zeroed, * returning true if that succeeded and false on any sort of detectable error. */ static int test_calloc(size_t size) { char *buffer; size_t i, nelems; nelems = size / 4; if (nelems * 4 != size) return 0; buffer = xcalloc(nelems, 4); if (buffer == NULL) return 0; for (i = 0; i < size; i++) if (buffer[i] != 0) return 0; free(buffer); return 1; } /* * Test asprintf with a large string (essentially using it as strdup). * Returns true if successful, false otherwise. */ static int test_asprintf(size_t size) { char *copy, *string; int status; size_t i; string = xmalloc(size); memset(string, 42, size - 1); string[size - 1] = '\0'; status = xasprintf(©, "%s", string); free(string); if (status < 0) return 0; for (i = 0; i < size - 1; i++) if (copy[i] != 42) return 0; if (copy[size - 1] != '\0') return 0; free(copy); return 1; } /* Wrapper around vasprintf to do the va_list stuff. */ static int xvasprintf_wrapper(char **strp, const char *format, ...) { va_list args; int status; va_start(args, format); status = xvasprintf(strp, format, args); va_end(args); return status; } /* * Test vasprintf with a large string (essentially using it as strdup). * Returns true if successful, false otherwise. */ static int test_vasprintf(size_t size) { char *copy, *string; int status; size_t i; string = xmalloc(size); memset(string, 42, size - 1); string[size - 1] = '\0'; status = xvasprintf_wrapper(©, "%s", string); free(string); if (status < 0) return 0; for (i = 0; i < size - 1; i++) if (copy[i] != 42) return 0; if (copy[size - 1] != '\0') return 0; free(copy); return 1; } /* * Take the amount of memory to allocate in bytes as a command-line argument * and call test_malloc with that amount of memory. */ int main(int argc, char *argv[]) { size_t size, max; size_t limit = 0; int willfail = 0; unsigned char code; if (argc < 3) die("Usage error. Type, size, and limit must be given."); errno = 0; size = strtol(argv[2], 0, 10); if (size == 0 && errno != 0) sysdie("Invalid size"); errno = 0; limit = strtol(argv[3], 0, 10); if (limit == 0 && errno != 0) sysdie("Invalid limit"); /* If the code is capitalized, install our customized error handler. */ code = argv[1][0]; if (isupper(code)) { xmalloc_error_handler = test_handler; code = tolower(code); } /* * Decide if the allocation should fail. If it should, set willfail to 2, * so that if it unexpectedly succeeds, we exit with a status indicating * that the test should be skipped. */ max = size; if (code == 's' || code == 'n' || code == 'a' || code == 'v') { max += size; if (limit > 0) limit += size; } if (limit > 0 && max > limit) willfail = 2; /* * If a memory limit was given and we can set memory limits, set it. * Otherwise, exit 2, signalling to the driver that the test should be * skipped. We do this here rather than in the driver due to some * pathological problems with Linux (setting ulimit in the shell caused * the shell to die). */ if (limit > 0) { #if HAVE_SETRLIMIT && defined(RLIMIT_AS) struct rlimit rl; void *tmp; rl.rlim_cur = limit; rl.rlim_max = limit; if (setrlimit(RLIMIT_AS, &rl) < 0) { syswarn("Can't set data limit to %lu", (unsigned long) limit); exit(2); } if (size < limit || code == 'r') { tmp = malloc(code == 'r' ? 10 : size); if (tmp == NULL) { syswarn("Can't allocate initial memory of %lu", (unsigned long) size); exit(2); } free(tmp); } #else warn("Data limits aren't supported."); exit(2); #endif } switch (code) { case 'c': exit(test_calloc(size) ? willfail : 1); case 'm': exit(test_malloc(size) ? willfail : 1); case 'r': exit(test_realloc(size) ? willfail : 1); case 's': exit(test_strdup(size) ? willfail : 1); case 'n': exit(test_strndup(size) ? willfail : 1); case 'a': exit(test_asprintf(size) ? willfail : 1); case 'v': exit(test_vasprintf(size) ? willfail : 1); default: die("Unknown mode %c", argv[1][0]); break; } exit(1); } kstart-4.1/tests/util/concat-t.c0000644000175000000000000000357611702213030013565 00000000000000/* * concat test suite. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * * The authors hereby relinquish any claim to any copyright that they may have * in this work, whether granted under contract or by operation of law or * international treaty, and hereby commit to the public, at large, that they * shall not, at any time in the future, seek to enforce any copyright in this * work against any person or entity, or prevent any person or entity from * copying, publishing, distributing or creating derivative works of this * work. */ #include #include #include #include #define END (char *) 0 /* * Memory leaks everywhere! Whoo-hoo! */ int main(void) { plan(13); is_string("a", concat("a", END), "concat 1"); is_string("ab", concat("a", "b", END), "concat 2"); is_string("ab", concat("ab", "", END), "concat 3"); is_string("ab", concat("", "ab", END), "concat 4"); is_string("", concat("", END), "concat 5"); is_string("abcde", concat("ab", "c", "", "de", END), "concat 6"); is_string("abcde", concat("abc", "de", END, "f", END), "concat 7"); is_string("/foo", concatpath("/bar", "/foo"), "path 1"); is_string("/foo/bar", concatpath("/foo", "bar"), "path 2"); is_string("./bar", concatpath("/foo", "./bar"), "path 3"); is_string("/bar/baz/foo/bar", concatpath("/bar/baz", "foo/bar"), "path 4"); is_string("./foo", concatpath(NULL, "foo"), "path 5"); is_string("/foo/bar", concatpath(NULL, "/foo/bar"), "path 6"); return 0; } kstart-4.1/tests/util/messages-t.c0000644000175000000000000001615511702213030014122 00000000000000/* * Test suite for error handling routines. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2002, 2004, 2005 Russ Allbery * Copyright 2009, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include /* * Test functions. */ static void test1(void *data UNUSED) { warn("warning"); } static void test2(void *data UNUSED) { die("fatal"); } static void test3(void *data UNUSED) { errno = EPERM; syswarn("permissions"); } static void test4(void *data UNUSED) { errno = EACCES; sysdie("fatal access"); } static void test5(void *data UNUSED) { message_program_name = "test5"; warn("warning"); } static void test6(void *data UNUSED) { message_program_name = "test6"; die("fatal"); } static void test7(void *data UNUSED) { message_program_name = "test7"; errno = EPERM; syswarn("perms %d", 7); } static void test8(void *data UNUSED) { message_program_name = "test8"; errno = EACCES; sysdie("%st%s", "fa", "al"); } static int return10(void) { return 10; } static void test9(void *data UNUSED) { message_fatal_cleanup = return10; die("fatal"); } static void test10(void *data UNUSED) { message_program_name = 0; message_fatal_cleanup = return10; errno = EPERM; sysdie("fatal perm"); } static void test11(void *data UNUSED) { message_program_name = "test11"; message_fatal_cleanup = return10; errno = EPERM; fputs("1st ", stdout); sysdie("fatal"); } static void log_msg(size_t len, const char *format, va_list args, int error) { fprintf(stderr, "%lu %d ", (unsigned long) len, error); vfprintf(stderr, format, args); fprintf(stderr, "\n"); } static void test12(void *data UNUSED) { message_handlers_warn(1, log_msg); warn("warning"); } static void test13(void *data UNUSED) { message_handlers_die(1, log_msg); die("fatal"); } static void test14(void *data UNUSED) { message_handlers_warn(2, log_msg, log_msg); errno = EPERM; syswarn("warning"); } static void test15(void *data UNUSED) { message_handlers_die(2, log_msg, log_msg); message_fatal_cleanup = return10; errno = EPERM; sysdie("fatal"); } static void test16(void *data UNUSED) { message_handlers_warn(2, message_log_stderr, log_msg); message_program_name = "test16"; errno = EPERM; syswarn("warning"); } static void test17(void *data UNUSED) { notice("notice"); } static void test18(void *data UNUSED) { message_program_name = "test18"; notice("notice"); } static void test19(void *data UNUSED) { debug("debug"); } static void test20(void *data UNUSED) { message_handlers_notice(1, log_msg); notice("foo"); } static void test21(void *data UNUSED) { message_handlers_debug(1, message_log_stdout); message_program_name = "test23"; debug("baz"); } static void test22(void *data UNUSED) { message_handlers_die(0); die("hi mom!"); } static void test23(void *data UNUSED) { message_handlers_warn(0); warn("this is a test"); } static void test24(void *data UNUSED) { notice("first"); message_handlers_notice(0); notice("second"); message_handlers_notice(1, message_log_stdout); notice("third"); } /* * Given the intended status, intended message sans the appended strerror * output, errno, and the function to run, check the output. */ static void test_strerror(int status, const char *output, int error, test_function_type function) { char *full_output, *name; full_output = concat(output, ": ", strerror(error), "\n", (char *) NULL); xasprintf(&name, "strerror %lu", testnum / 3 + 1); is_function_output(function, NULL, status, full_output, "%s", name); free(full_output); free(name); } /* * Run the tests. */ int main(void) { char buff[32]; char *output; plan(24 * 3); is_function_output(test1, NULL, 0, "warning\n", "test1"); is_function_output(test2, NULL, 1, "fatal\n", "test2"); test_strerror(0, "permissions", EPERM, test3); test_strerror(1, "fatal access", EACCES, test4); is_function_output(test5, NULL, 0, "test5: warning\n", "test5"); is_function_output(test6, NULL, 1, "test6: fatal\n", "test6"); test_strerror(0, "test7: perms 7", EPERM, test7); test_strerror(1, "test8: fatal", EACCES, test8); is_function_output(test9, NULL, 10, "fatal\n", "test9"); test_strerror(10, "fatal perm", EPERM, test10); test_strerror(10, "1st test11: fatal", EPERM, test11); is_function_output(test12, NULL, 0, "7 0 warning\n", "test12"); is_function_output(test13, NULL, 1, "5 0 fatal\n", "test13"); sprintf(buff, "%d", EPERM); xasprintf(&output, "7 %d warning\n7 %d warning\n", EPERM, EPERM); is_function_output(test14, NULL, 0, output, "test14"); free(output); xasprintf(&output, "5 %d fatal\n5 %d fatal\n", EPERM, EPERM); is_function_output(test15, NULL, 10, output, "test15"); free(output); xasprintf(&output, "test16: warning: %s\n7 %d warning\n", strerror(EPERM), EPERM); is_function_output(test16, NULL, 0, output, "test16"); free(output); is_function_output(test17, NULL, 0, "notice\n", "test17"); is_function_output(test18, NULL, 0, "test18: notice\n", "test18"); is_function_output(test19, NULL, 0, "", "test19"); is_function_output(test20, NULL, 0, "3 0 foo\n", "test20"); is_function_output(test21, NULL, 0, "test23: baz\n", "test21"); /* Make sure that it's possible to turn off a message type entirely. */ is_function_output(test22, NULL, 1, "", "test22"); is_function_output(test23, NULL, 0, "", "test23"); is_function_output(test24, NULL, 0, "first\nthird\n", "test24"); return 0; } kstart-4.1/tests/util/messages-krb5-t.c0000644000175000000000000000727411702213030014765 00000000000000/* * Test suite for Kerberos error handling routines. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include /* * Test functions. */ static void test_warn(void *data UNUSED) { krb5_context ctx; krb5_error_code code; krb5_principal princ; code = krb5_init_context(&ctx); if (code < 0) die_krb5(ctx, code, "cannot create context"); code = krb5_parse_name(ctx, "foo@bar@EXAMPLE.COM", &princ); if (code < 0) warn_krb5(ctx, code, "principal parse failed"); else die("unexpected success parsing principal"); exit(0); } static void test_die(void *data UNUSED) { krb5_context ctx; krb5_error_code code; krb5_principal princ; code = krb5_init_context(&ctx); if (code < 0) die_krb5(ctx, code, "cannot create context"); code = krb5_parse_name(ctx, "foo@bar@EXAMPLE.COM", &princ); if (code < 0) die_krb5(ctx, code, "principal parse failed"); else die("unexpected success parsing principal"); exit(0); } /* * Run the tests. */ int main(void) { krb5_context ctx; krb5_error_code code; krb5_principal princ; const char *message; char *wanted; plan(6 * 3); /* First, we have to get what the correct error message is. */ code = krb5_init_context(&ctx); if (code < 0) bail("cannot create context"); code = krb5_parse_name(ctx, "foo@bar@EXAMPLE.COM", &princ); message = krb5_get_error_message(ctx, code); xasprintf(&wanted, "principal parse failed: %s\n", message); is_function_output(test_warn, NULL, 0, wanted, "warn_krb5"); is_function_output(test_die, NULL, 1, wanted, "die_krb5"); free(wanted); message_program_name = "msg-test"; xasprintf(&wanted, "msg-test: principal parse failed: %s\n", message); is_function_output(test_warn, NULL, 0, wanted, "warn_krb5 with name"); is_function_output(test_die, NULL, 1, wanted, "die_krb5 with name"); free(wanted); message_handlers_warn(0); is_function_output(test_warn, NULL, 0, "", "warn_krb5 with no handlers"); message_handlers_die(0); is_function_output(test_die, NULL, 1, "", "warn_krb5 with no handlers"); return 0; } kstart-4.1/tests/util/xmalloc-t0000755000175000000000000001340111702213030013523 00000000000000#! /bin/sh # # Test suite for xmalloc and friends. # # The canonical version of this file is maintained in the rra-c-util package, # which can be found at . # # Written by Russ Allbery # Copyright 2000, 2001, 2006 Russ Allbery # Copyright 2008, 2009, 2010 # The Board of Trustees of the Leland Stanford Junior University # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. . "$SOURCE/tap/libtap.sh" cd "$BUILD/util" # Run an xmalloc test. Takes the description, the expectd exit status, the # output, and the arguments. ok_xmalloc () { local desc w_status w_output output status desc="$1" shift w_status="$1" shift w_output="$1" shift output=`./xmalloc "$@" 2>&1` status=$? if [ "$w_status" -ne 0 ] ; then output=`echo "$output" | sed 's/:.*//'` fi if [ $status = $w_status ] && [ x"$output" = x"$w_output" ] ; then ok "$desc" true elif [ $status = 2 ] ; then skip "no data limit support" else echo "# saw: ($status) $output" echo "# not: ($w_status) $w_output" ok "$desc" false fi } # Skip this test suite unless maintainer-mode tests are enabled. All of the # failures in automated testing have been problems with the assumptions around # memory allocation or problems with the test suite, not problems with the # underlying xmalloc code. if [ -z "$RRA_MAINTAINER_TESTS" ] ; then skip_all 'xmalloc tests only run for maintainer' fi # Total tests. plan 36 # First run the tests expected to succeed. ok_xmalloc "malloc small" 0 "" "m" "21" "0" ok_xmalloc "malloc large" 0 "" "m" "3500000" "0" ok_xmalloc "malloc zero" 0 "" "m" "0" "0" ok_xmalloc "realloc small" 0 "" "r" "21" "0" ok_xmalloc "realloc large" 0 "" "r" "3500000" "0" ok_xmalloc "strdup small" 0 "" "s" "21" "0" ok_xmalloc "strdup large" 0 "" "s" "3500000" "0" ok_xmalloc "strndup small" 0 "" "n" "21" "0" ok_xmalloc "strndup large" 0 "" "n" "3500000" "0" ok_xmalloc "calloc small" 0 "" "c" "24" "0" ok_xmalloc "calloc large" 0 "" "c" "3500000" "0" ok_xmalloc "asprintf small" 0 "" "a" "24" "0" ok_xmalloc "asprintf large" 0 "" "a" "3500000" "0" ok_xmalloc "vasprintf small" 0 "" "v" "24" "0" ok_xmalloc "vasprintf large" 0 "" "v" "3500000" "0" # Now limit our memory to 3.5MB and then try the large ones again, all of # which should fail. # # The exact memory limits used here are essentially black magic. They need to # be large enough to allow the program to be loaded and do small allocations, # but not so large that we can't reasonably expect to allocate that much # memory normally. 3.5MB seems to work reasonably well on both Solaris and # Linux. # # We assume that there are enough miscellaneous allocations that an allocation # exactly as large as the limit will always fail. ok_xmalloc "malloc fail" 1 \ "failed to malloc 3500000 bytes at xmalloc.c line 38" \ "m" "3500000" "3500000" ok_xmalloc "realloc fail" 1 \ "failed to realloc 3500000 bytes at xmalloc.c line 66" \ "r" "3500000" "3500000" ok_xmalloc "strdup fail" 1 \ "failed to strdup 3500000 bytes at xmalloc.c line 97" \ "s" "3500000" "3500000" ok_xmalloc "strndup fail" 1 \ "failed to strndup 3500000 bytes at xmalloc.c line 124" \ "n" "3500000" "3500000" ok_xmalloc "calloc fail" 1 \ "failed to calloc 3500000 bytes at xmalloc.c line 148" \ "c" "3500000" "3500000" ok_xmalloc "asprintf fail" 1 \ "failed to asprintf 3500000 bytes at xmalloc.c line 173" \ "a" "3500000" "3500000" ok_xmalloc "vasprintf fail" 1 \ "failed to vasprintf 3500000 bytes at xmalloc.c line 195" \ "v" "3500000" "3500000" # Check our custom error handler. ok_xmalloc "malloc custom" 1 "malloc 3500000 xmalloc.c 38" \ "M" "3500000" "3500000" ok_xmalloc "realloc custom" 1 "realloc 3500000 xmalloc.c 66" \ "R" "3500000" "3500000" ok_xmalloc "strdup custom" 1 "strdup 3500000 xmalloc.c 97" \ "S" "3500000" "3500000" ok_xmalloc "strndup custom" 1 "strndup 3500000 xmalloc.c 124" \ "N" "3500000" "3500000" ok_xmalloc "calloc custom" 1 "calloc 3500000 xmalloc.c 148" \ "C" "3500000" "3500000" ok_xmalloc "asprintf custom" 1 "asprintf 3500000 xmalloc.c 173" \ "A" "3500000" "3500000" ok_xmalloc "vasprintf custom" 1 "vasprintf 3500000 xmalloc.c 195" \ "V" "3500000" "3500000" # Check the smaller ones again just for grins. ok_xmalloc "malloc retry" 0 "" "m" "21" "3500000" ok_xmalloc "realloc retry" 0 "" "r" "32" "3500000" ok_xmalloc "strdup retry" 0 "" "s" "64" "3500000" ok_xmalloc "strndup retry" 0 "" "n" "20" "3500000" ok_xmalloc "calloc retry" 0 "" "c" "24" "3500000" ok_xmalloc "asprintf retry" 0 "" "a" "30" "3500000" ok_xmalloc "vasprintf retry" 0 "" "v" "35" "3500000" kstart-4.1/tests/data/0000755000175000000000000000000011702213052011716 500000000000000kstart-4.1/tests/data/fake-aklog0000755000175000000000000000004411702213030013557 00000000000000#!/bin/sh echo 'Running fake aklog' kstart-4.1/tests/data/command0000755000175000000000000000144011702213030013175 00000000000000#!/usr/bin/perl # # An interesting command to run under k5start or krenew to perform various # tests. It takes on the command-line a file into which to write, and into # that file, it puts its PID, its current working directory, and its ticket # cache. When it gets a HUP or INT signal, it writes into that file. When it # gets a TERM signal, it writes into that file and exits. use Cwd; $| = 1; $SIG{HUP} = sub { print OUT "got SIGHUP\n" }; $SIG{INT} = sub { print OUT "got SIGINT\n" }; $SIG{QUIT} = sub { print OUT "got SIGQUIT\n"; exit 0 }; $SIG{TERM} = sub { print OUT "got SIGTERM\n"; exit 0 }; print "Starting\n"; my $file = shift; open (OUT, '>', $file) or die "Cannot write to $file: $!\n"; OUT->autoflush (1); print OUT "$$\n", getcwd, "\n", $ENV{KRB5CCNAME}, "\n"; sleep 1000 while 1; kstart-4.1/tests/data/README0000644000175000000000000000175211702213030012517 00000000000000This directory contains data used by kstart's test suite. To enable tests that require Kerberos authentication and a working end-to-end Kerberos environment, create a Kerberos keytab in the local realm and put it in this directory as test.keytab. Then, create a file named test.principal and in it put the principal name corresponding to the key in the keytab on a single line ending with a newline. The presence of these two files will enable the tests that actually do Kerberos authentication. In order to test AFS PAG and token handling (only applicable if built with --enable-setpag), be sure that you have an AFS token before you run the test suite. (It doesn't matter which user you have an AFS token for.) If you are building in a different directory tree than the source tree, don't put the files in this directory. Instead, after running configure, you will have an empty tests/data directory in your build tree. Put the test.keytab and test.principal files in that directory instead. kstart-4.1/tests/README0000644000175000000000000002573611702213030011616 00000000000000 Writing TAP Tests Introduction This is a guide for users of the C TAP Harness package or similar TAP-based test harnesses explaining how to write tests. If your package uses C TAP Harness as the test suite driver, you may want to copy this document to an appropriate file name in your test suite as documentation for contributors. About TAP TAP is the Test Anything Protocol, a protocol for communication between test cases and a test harness. This is the protocol used by Perl for its internal test suite and for nearly all Perl modules, since it's the format used by the build tools for Perl modules to run tests and report their results. A TAP-based test suite works with a somewhat different set of assumptions than an xUnit test suite. In TAP, each test case is a separate program. That program, when run, must produce output in the following format: 1..4 ok 1 - the first test ok 2 # a diagnostic, ignored by the harness not ok 3 - a failing test ok 4 # skip a skipped test The output should all go to standard output. The first line specifies the number of tests to be run, and then each test produces output that looks like either "ok " or "not ok " depending on whether the test succeeded or failed. Additional information about the test can be provided after the "ok " or "not ok ", but is optional. Additional diagnostics and information can be provided in lines beginning with a "#". Processing directives are supported after the "ok " or "not ok " and start with a "#". The main one of interest is "# skip" which says that the test was skipped rather than successful and optionally gives the reason. Also supported is "# todo", which normally annotates a failing test and indicates that test is expected to fail, optionally providing a reason for why. There are three more special cases. First, the initial line stating the number of tests to run, called the plan, may appear at the end of the output instead of the beginning. This can be useful if the number of tests to run is not known in advance. Second, a plan in the form: 1..0 # skip entire test case skipped can be given instead, which indicates that this entire test case has been skipped (generally because it depends on facilities or optional configuration which is not present). Finally, if the test case encounters a fatal error, it should print the text: Bail out! on standard output, optionally followed by an error message, and then exit. This tells the harness that the test aborted unexpectedly. The exit status of a successful test case should always be 0. The harness will report the test as "dubious" if all the tests appeared to succeed but it exited with a non-zero status. Writing TAP Tests Environment One of the special features of C TAP Harness is the environment that it sets up for your test cases. If your test program is called under the runtests driver, the environment variables SOURCE and BUILD will be set to the top of the test directory in the source tree and the top of the build tree, respectively. You can use those environment variables to locate additional test data, programs and libraries built as part of your software build, and other supporting information needed by tests. The C and shell TAP libraries support a test_file_path() function, which looks for a file under the build tree and then under the source tree, using the BUILD and SOURCE environment variables, and return the full path to the file. This can be used to locate supporting data files. Perl Since TAP is the native test framework for Perl, writing TAP tests in Perl is very easy and extremely well-supported. If you've never written tests in Perl before, start by reading the documentation for Test::Tutorial and Test::Simple, which walks you through the basics, including the TAP output syntax. Then, the best Perl module to use for serious testing is Test::More, which provides a lot of additional functions over Test::Simple including support for skipping tests, bailing out, and not planning tests in advance. See the documentation of Test::More for all the details and lots of examples. C TAP Harness can run Perl test scripts directly and interpret the results correctly, and similarly the Perl Test::Harness module and prove command can run TAP tests written in other languages using, for example, the TAP library that comes with C TAP Harness. You can, if you wish, use the library that comes with C TAP Harness but use prove instead of runtests for running the test suite. C C TAP Harness provides a basic TAP library that takes away most of the pain of writing TAP test cases in C. A C test case should start with a call to plan(), passing in the number of tests to run. Then, each test should use is_int(), is_string(), is_double(), or is_hex() as appropriate to compare expected and seen values, or ok() to do a simpler boolean test. The is_*() functions take expected and seen values and then a printf-style format string explaining the test (which may be NULL). ok() takes a boolean and then the printf-style string. Here's a complete example test program that uses the C TAP library: #include #include int main(void) { plan(4); ok(1, "the first test"); is_int(42, 42, NULL); diag("a diagnostic, ignored by the harness"); ok(0, "a failing test"); skip("a skipped test"); return 0; } This test program produces the output shown above in the section on TAP and demonstrates most of the functions. The other functions of interest are sysdiag() (like diag() but adds strerror() results), bail() and sysbail() for fatal errors, skip_block() to skip a whole block of tests, and skip_all() which is called instead of plan() to skip an entire test case. The C TAP library also provides plan_lazy(), which can be called instead of plan(). If plan_lazy() is called, the library will keep track of how many test results are reported and will print out the plan at the end of execution of the program. This should normally be avoided since the test may appear to be successful even if it exits prematurely, but it can make writing tests easier in some circumstances. Complete API documentation for the basic C TAP library that comes with C TAP Harness is available at: It's common to need additional test functions and utility functions for your C tests, particularly if you have to set up and tear down a test environment for your test programs, and it's useful to have them all in the libtap library so that you only have to link your test programs with one library. Rather than editing tap/basic.c and tap/basic.h to add those additional functions, add additional *.c and *.h files into the tap directory with the function implementations and prototypes, and then add those additional objects to the library. That way, you can update tap/basic.c and tap/basic.h from subsequent releases of C TAP Harness without having to merge changes with your own code. Libraries of additional useful TAP test functions are available in rra-c-util at: Some of the code there is particularly useful when testing programs that require Kerberos keys. If you implement new test functions that compare an expected and seen value, it's best to name them is_ and take the expected value, the seen value, and then a printf-style format string and possible arguments to match the calling convention of the functions provided by C TAP Harness. Shell C TAP Harness provides a library of shell functions to make it easier to write TAP tests in shell. That library includes much of the same functionality as the C TAP library, but takes its parameters in a somewhat different order to make better use of shell features. The libtap.sh file should be installed in a directory named tap in your test suite area. It can then be loaded by tests written in shell using the environment set up by runtests with: . "$SOURCE"/tap/libtap.sh Here is a complete test case written in shell which produces the same output as the TAP sample above: #!/bin/sh . "$SOURCE"/tap/libtap.sh cd "$BUILD" plan 4 ok 'the first test' true ok '' [ 42 -eq 42 ] diag a diagnostic, ignored by the harness ok '' false skip 'a skipped test' The shell framework doesn't provide the is_* functions, so you'll use the ok function more. It takes a string describing the text and then treats all of its remaining arguments as a condition, evaluated the same way as the arguments to the "if" statement. If that condition evaluates to true, the test passes; otherwise, the test fails. The plan, plan_lazy, diag, and bail functions work the same as with the C library. skip takes a string and skips the next test with that explanation. skip_block takes a count and a string and skips that many tests with that explanation. skip_all takes an optional reason and skips the entire test case. Since it's common for shell programs to want to test the output of commands, there's an additional function ok_program provided by the shell test library. It takes the test description string, the expected exit status, the expected program output, and then treats the rest of its arguments as the program to run. That program is run with standard error and standard output combined, and then its exit status and output are tested against the provided values. A utility function, strip_colon_error, is provided that runs the command given as its arguments and strips text following a colon and a space from the output (unless there is no whitespace on the line before the colon and the space, normally indicating a prefix of the program name). This function can be used to wrap commands that are expected to fail with output that has a system- or locale-specific error message appended, such as the output of strerror(). License This file is part of the documentation of C TAP Harness, which can be found at . Copyright 2010 Russ Allbery Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. kstart-4.1/tests/krenew/0000755000175000000000000000000011702213052012300 500000000000000kstart-4.1/tests/krenew/keyring-t0000755000175000000000000000303311702213030014052 00000000000000#!/usr/bin/perl -w # # Tests for krenew support of keyrings. # # Written by Russ Allbery # Copyright 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $KRENEW = "$ENV{BUILD}/../krenew"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. my $principal; if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'KEYRING:test'; unless (kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '10m')) { plan skip_all => 'cannot get renewable tickets in keyring'; exit 0; } unless (!-f 'KEYRING:test') { plan skip_all => 'cannot use keyring caches'; exit 0; } plan tests => 5; } # Basic renewal test. my ($out, $err, $status) = command ($KRENEW, '-v'); is ($status, 0, 'Basic krenew command succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^krenew: renewing credentials for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); my ($default, $service) = klist (); like ($default, qr/^\Q$principal\E(\@\S+)?\z/, ' for the right principal'); like ($service, qr%^krbtgt/%, ' and the right service'); kstart-4.1/tests/krenew/afs-t0000755000175000000000000000633211702213030013160 00000000000000#!/usr/bin/perl -w # # Tests for krenew with AFS. # # Written by Russ Allbery # Copyright 2008, 2009 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built krenew client. our $KRENEW = "$ENV{BUILD}/../krenew"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # The path to a shell script that just prints something out. our $FAKE_AKLOG = "$ENV{SOURCE}/data/fake-aklog"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. my ($principal, $out, $err, $status); if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } elsif (not tokens ()) { plan skip_all => 'no current AFS tokens'; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'krb5cc_test'; unlink 'krb5cc_test'; unless (kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '1h')) { plan skip_all => 'cannot get renewable tickets'; exit 0; } ($out, $err, $status) = command ($KRENEW, '-t', '--', 'tokens'); if ($err eq "krenew: cannot create PAG: AFS support is not available\n") { plan skip_all => 'not built with AFS support'; exit 0; } else { plan tests => 15; } } # Now, see if we can renew tickets and get a token. is ($status, 0, 'krenew -t succeeds'); is ($err, '', ' with no errors'); like ($out, qr/^(User\'s \([^\)]+\) )?[Tt]okens for /m, ' and the right output'); # Set the token program to something that doesn't obtain tokens. Everything # should still work, but we should have no tokens. $ENV{AKLOG} = '/bin/true'; ($out, $err, $status) = command ($KRENEW, '-t', '--', 'tokens'); is ($status, 0, 'krenew -t succeeds with no aklog'); is ($err, '', ' with no errors'); unlike ($out, qr/^(User\'s \([^\)]+\) )?[Tt]okens for /m, ' and we have no tokens'); delete $ENV{AKLOG}; # Make sure that we run the right aklog program. We need to pass -K to reduce # the wakeup period or krenew will want tickets that last longer than an hour # (the default -K interval when running a command). $ENV{AKLOG} = $FAKE_AKLOG; ($out, $err, $status) = command ($KRENEW, '-K', 10, '-t', '--', 'true'); is ($status, 0, 'krenew -t succeeds with fake aklog'); is ($err, '', ' with no errors'); is ($out, "Running fake aklog\n", ' and we ran the fake aklog'); delete $ENV{AKLOG}; # AKLOG should override KINIT_PROG. $ENV{KINIT_PROG} = $FAKE_AKLOG; $ENV{AKLOG} = '/bin/true'; ($out, $err, $status) = command ($KRENEW, '-t', '--', 'true'); is ($status, 0, 'krenew -t succeeds with /bin/true aklog'); is ($err, '', ' with no errors'); is ($out, '', ' and we did not run KINIT_PROG'); delete $ENV{AKLOG}; delete $ENV{KINIT_PROG}; # KINIT_PROG should still work. $ENV{KINIT_PROG} = $FAKE_AKLOG; ($out, $err, $status) = command ($KRENEW, '-K', 10, '-t', '--', 'true'); is ($status, 0, 'krenew -t succeeds with KINIT_PROG'); is ($err, '', ' with no errors'); is ($out, "Running fake aklog\n", ' and we ran the fake aklog'); delete $ENV{KINIT_PROG}; unlink 'krb5cc_test'; kstart-4.1/tests/krenew/errors-t0000755000175000000000000000234111702213030013717 00000000000000#!/usr/bin/perl -w # # Tests for error handling in krenew. # # Written by Russ Allbery # Copyright 2011, 2012 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built k5start client. our $KRENEW = "$ENV{BUILD}/../krenew"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Don't overwrite the user's ticket cache. $ENV{KRB5CCNAME} = 'krb5cc_test'; # Test invalid options. our @OPTIONS = ( [ [ qw/-H 0/ ], '-H limit argument 0 invalid' ], [ [ qw/-H -1/ ], '-H limit argument -1 invalid' ], [ [ qw/-H 4foo/ ], '-H limit argument 4foo invalid' ], [ [ qw/-K 4foo/ ], '-K interval argument 4foo invalid' ], [ [ qw/-H4 a/ ], '-H option cannot be used with a command' ], [ [ qw/-s/ ], '-s option only makes sense with a command to run' ] ); # Test plan. plan tests => scalar (@OPTIONS) * 3; # Run the invalid option tests. for my $opt (@OPTIONS) { my ($out, $err, $status) = command ($KRENEW, @{ $opt->[0] }); is ($status, 1, "krenew @{ $opt->[0] } fails"); is ($out, '', ' with no output'); is ($err, 'krenew: ' . $opt->[1] . "\n", ' and correct error'); } kstart-4.1/tests/krenew/non-renewable-t0000755000175000000000000000461111702213030015141 00000000000000#!/usr/bin/perl -w # # Ensure krenew -H works with non-renewable tickets. # # krenew normally requires tickets be renewable, but krenew -H should be happy # with a non-renewable ticket that nonetheless has sufficient renaming # lifespan. # # Written by Russ Allbery # Copyright 2012 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built krenew client. our $KRENEW = "$ENV{BUILD}/../krenew"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # We have to generate a local krb5.conf that disables any attempt to get # renewable tickets. Try to locate the local krb5.conf that we're supposed to # use and skip if we can't find one. my $krb5conf = $ENV{KRB5_CONFIG}; unless ($krb5conf) { for my $path ('/etc', '/usr/local/etc', "$ENV{BUILD}/data") { if (-r "$path/krb5.conf") { $krb5conf = "$path/krb5.conf"; last; } } } if ($krb5conf) { open (CONF, '<', $krb5conf) or BAIL_OUT ("cannot open $krb5conf: $!"); open (NEWCONF, '>', './krb5.conf') or BAIL_OUT ("cannot create krb5.conf: $!"); while () { next if /^\s*renew_lifetime\b/; print NEWCONF $_; } close CONF; close NEWCONF; $ENV{KRB5_CONFIG} = './krb5.conf'; } else { plan skip_all => "no krb5.conf found, set KRB5_CONFIG"; exit 0; } # Decide whether we have the configuration to run the tests. my $principal; if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { unlink 'krb5.conf'; plan skip_all => "no keytab configuration"; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'krb5cc_test'; unlink 'krb5cc_test'; unless (kinit ("$DATA/test.keytab", $principal, '-l', '1h')) { unlink 'krb5.conf'; plan skip_all => 'cannot get non-renewable tickets'; exit 0; } plan tests => 3; } # Now, krenew should run without reauthenticating even though the ticket isn't # renewable. my ($out, $err, $status) = command ($KRENEW, '-H', '20'); is ($status, 0, 'krenew -H 20 succeeds without reauthenticating'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); # Clean up. unlink 'krb5cc_test', 'krb5.conf'; kstart-4.1/tests/krenew/basic-t0000755000175000000000000001150011702213030013461 00000000000000#!/usr/bin/perl -w # # Tests for basic krenew functionality. # # Written by Russ Allbery # Copyright 2008, 2009, 2011 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Test::More; # The full path to the newly-built krenew client. our $KRENEW = "$ENV{BUILD}/../krenew"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. my $principal; if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = 'krb5cc_test'; unlink 'krb5cc_test'; unless (kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '10m')) { plan skip_all => 'cannot get renewable tickets'; exit 0; } plan tests => 36; } # We should be okay for five minute tickets without doing anything. ($out, $err, $status) = command ($KRENEW, '-vH', '5'); is ($status, 0, 'krenew -H 5 succeeds without reauthenticating'); is ($err, '', ' with no errors'); is ($out, '', ' and no output'); # We should be able to renew to get 30 minute tickets. ($out, $err, $status) = command ($KRENEW, '-vH', '30'); is ($status, 0, 'krenew -H 30 succeeds with authentication'); is ($err, '', ' with no errors'); like ($out, qr/^krenew: renewing credentials for \Q$principal\E(\@\S+)?\n\z/, ' and the right output'); # But we fail if we try to get 3 hour tickets, since we can't renew for # that long. ($out, $err, $status) = command ($KRENEW, '-vH', '180'); is ($status, 1, 'krenew -H 180 fails'); is ($err, "krenew: ticket cannot be renewed for long enough\n", ' with the right error'); is ($out, '', ' and no output'); # Test running a command. klist may fail if we have no K4 tickets since # we're not giving the -5 option; allow for that (we'll catch real # failures in the regex match on the output). ($out, $err, $status) = command ($KRENEW, 'klist'); ok ($status == 0 || $status == 1, 'krenew with command succeeds'); ok ($err eq '' || $err eq "klist: You have no tickets cached\n", ' with no or expected errors'); like ($out, qr,^\s*(Ticket|Credentials)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); ok (-f 'krb5cc_test', ' but the default one was unaffected'); # Test running a command with --. ($out, $err, $status) = command ($KRENEW, '--', 'klist', '-5'); is ($status, 0, 'krenew with command and -- succeeds'); is ($err, '', ' with no errors'); like ($out, qr,^\s*(Ticket|Credentials)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); ok (-f 'krb5cc_test', ' but the default one was unaffected'); # Test propagation of exit status from a command. ($out, $err, $status) = command ($KRENEW, '--', 'sh', '-c', 'klist -5; exit 3'); is ($status, 3, 'krenew of exit 3 returns correct exit status'); is ($err, '', ' with no errors'); like ($out, qr,^\s*(Ticket|Credentials)\ cache: \ (FILE:)?/tmp/krb5cc_\d+_\S{6}\n \s*(Default\ )?[Pp]rincipal:\ \Q$principal\E(\@\S+)?\n,xm, ' and the right output'); ($cache) = ($out =~ /cache: (?:FILE:)?(\S+)/); ok (!$cache || !-f $cache, ' and the new cache file was deleted'); ok (-f 'krb5cc_test', ' and the default cache file was unaffected'); # Check exit status if the ticket cache doesn't exist. unlink 'krb5cc_test'; ($out, $err, $status) = command ($KRENEW); is ($status, 1, 'krenew fails with no ticket cache'); is ($out, '', ' with no output'); like ($err, qr/^krenew: error reading ticket cache: /, ' and the right error'); ($out, $err, $status) = command ($KRENEW, '-vH', 5); is ($status, 1, 'krenew -H fails with no ticket cache'); is ($out, '', ' with no output'); like ($err, qr/^krenew: error reading ticket cache: /, ' and the right error'); # We should still exit with the same error if -i was given. ($out, $err, $status) = command ($KRENEW, '-vi'); is ($status, 1, 'krenew -i fails with no ticket cache'); is ($out, '', ' with no output'); like ($err, qr/^krenew: error reading ticket cache: /, ' and the right error'); ($out, $err, $status) = command ($KRENEW, '-viH', 5); is ($status, 1, 'krenew -iH fails with no ticket cache'); is ($out, '', ' with no output'); like ($err, qr/^krenew: error reading ticket cache: /, ' and the right error'); kstart-4.1/tests/krenew/daemon-t0000755000175000000000000003261111702213030013651 00000000000000#!/usr/bin/perl -w # # Tests for krenew daemon functionality. # # Written by Russ Allbery # Copyright 2008, 2009, 2011, 2012 # The Board of Trustees of the Leland Stanford Junior University # # See LICENSE for licensing terms. use Cwd; use Test::More; # The full path to the newly-built krenew client. our $KRENEW = "$ENV{BUILD}/../krenew"; # The path to our data directory, which contains the keytab to use to test. our $DATA = "$ENV{BUILD}/data"; # The path to our temporary directory used for test ticket caches and the # like. our $TMP = "$ENV{BUILD}/tmp"; unless (-d $TMP) { mkdir $TMP or BAIL_OUT ("cannot create $TMP: $!"); } # Load our test utility programs. require "$ENV{SOURCE}/libtest.pl"; # Decide whether we have the configuration to run the tests. my ($cwd, $principal); if (not -f "$DATA/test.keytab" or not -f "$DATA/test.principal") { plan skip_all => 'no keytab configuration'; exit 0; } else { $principal = contents ("$DATA/test.principal"); $ENV{KRB5CCNAME} = "$TMP/krb5cc_test"; unlink "$TMP/krb5cc_test"; unless (kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '10m')) { plan skip_all => 'cannot get renewable tickets'; exit 0; } plan tests => 94; } # Start a krenew daemon and be sure it gets tickets and stays running. my $pid = fork; if (!defined $pid) { BAIL_OUT ("can't fork: $!"); } elsif ($pid == 0) { open (STDERR, '>', "$TMP/krenew-errors") or BAIL_OUT ("can't create $TMP/krenew-errors: $!"); exec ($KRENEW, '-K', 30, '-p', "$TMP/pid") or BAIL_OUT ("can't run $KRENEW: $!"); } my $tries = 0; while (not -f "$TMP/pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } if (-f "$TMP/pid") { my $daemon = contents ("$TMP/pid"); is ($pid, $daemon, 'The right PID is written'); } else { ok (0, 'The right PID is written'); } ok (kill (0, $pid), ' and krenew is still running'); unlink "$TMP/krb5cc_test"; kill (14, $pid) or warn "Can't kill $pid: $!\n"; is (waitpid ($pid, 0), $pid, ' and it dies after failure to renew'); is (($? >> 8), 1, ' with non-zero exit status'); if (open (ERRORS, '<', "$TMP/krenew-errors")) { like (scalar (), qr/^krenew: error reading ticket cache: /, ' and the correct error message'); } else { ok (0, ' and the correct error message'); } unlink "$TMP/krenew-errors"; ok (!-f "$TMP/pid", ' and the PID file was removed'); kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '10m'); # Try again with the -b flag. my ($out, $err, $status) = command ($KRENEW, '-bK', 30, '-p', "$TMP/pid"); is ($status, 0, 'Backgrounding krenew works'); is ($err, '', ' with no error output'); is ($out, '', ' and -q was added implicitly'); $tries = 0; while (not -f "$TMP/pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), ' and the PID file is correct'); kill (15, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (!kill (0, $pid), ' and it dies after SIGTERM'); ok (!-f "$TMP/pid", ' and the PID file was removed'); # Now try with -i. In this case, krenew should keep running even if the # ticket cache disappears and be able to start refreshing it again when it # reappears. ($out, $err, $status) = command ($KRENEW, '-biK', 30, '-p', "$TMP/pid"); is ($status, 0, 'Backgrounding krenew works'); is ($err, '', ' with no error output'); is ($out, '', ' and -q was added implicitly'); $tries = 0; while (not -f "$TMP/pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), ' and the PID file is correct'); unlink "$TMP/krb5cc_test"; kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (kill (0, $pid), ' and it keeps running after failure to renew'); kinit ("$DATA/test.keytab", $principal, '-r', '2h', '-l', '10m'); my $time = (stat "$TMP/krb5cc_test")[9]; while (time == $time) { select (undef, undef, undef, 0.1); } is ($time, (stat "$TMP/krb5cc_test")[9], 'Cache has not been touched'); kill (14, $pid) or warn "Can't kill $pid: $!\n"; $tries = 0; while ($time >= (stat "$TMP/krb5cc_test")[9] && $tries < 10) { select (undef, undef, undef, 0.5); $tries++; } ok ($time < (stat "$TMP/krb5cc_test")[9], ' and is updated after SIGALRM'); kill (15, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (!kill (0, $pid), ' and it dies after SIGTERM'); ok (!-f "$TMP/pid", ' and the PID file was removed'); # Check that krenew keeps running if the ticket cache directory is not # writeable. $pid = fork; if (!defined $pid) { BAIL_OUT ("can't fork: $!"); } elsif ($pid == 0) { open (STDERR, '>', "$TMP/krenew-errors") or BAIL_OUT ("can't create $TMP/krenew-errors: $!"); exec ($KRENEW, '-K', 30, '-p', "$TMP/pid") or BAIL_OUT ("can't run $KRENEW: $!"); } $tries = 0; while (not -f "$TMP/pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew -K 30 started'); chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (kill (0, $pid), ' and it keeps running on a non-writeable cache'); chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); if (open (ERRORS, '<', "$TMP/krenew-errors")) { like (scalar (), qr/^krenew: error reinitializing cache: /, ' and the correct error message'); } else { ok (0, ' and the correct error message'); } unlink "$TMP/krenew-errors"; kill (15, $pid) or warn "Can't kill $pid: $!\n"; is (waitpid ($pid, 0), $pid, ' and it dies on SIGTERM'); ok (!-f "$TMP/pid", ' and the PID file was removed'); # If we do that again with -x, krenew should exit. ($out, $err, $status) = command ($KRENEW, '-xbK', 30, '-p', "$TMP/pid"); is ($status, 0, 'krenew -xb works'); is ($err, '', ' with no error output'); is ($out, '', ' and no regular output'); $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew -xb started'); chmod 0555, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.5); ok (!kill (0, $pid), ' and it exits on a non-writeable cache'); chmod 0755, $TMP or BAIL_OUT ("cannot chmod $TMP: $!"); unlink "$TMP/pid"; # Now, run a command in the background. unlink 'child-out'; ($out, $err, $status) = command ($KRENEW, '-bK', 30, '-p', "$TMP/pid", '-c', "$TMP/child-pid", '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding krenew works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } kill (1, $pid) or warn "Cannot send HUP to parent $pid: $!\n"; select (undef, undef, undef, 0.1); kill (2, $pid) or warn "Cannot send INT to parent $pid: $!\n"; select (undef, undef, undef, 0.1); kill (15, $pid) or warn "Cannot send TERM to parent $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'krenew is no longer running'); ok (!kill (0, $child), 'The child process is no longer running'); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open $TMP/child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); my $cache = scalar ; like ($cache, qr%^/tmp/krb5cc_%, 'Child cache is correct'); is (scalar (), "got SIGHUP\n", 'SIGHUP was recorded'); is (scalar (), "got SIGINT\n", 'SIGINT was recorded'); is (scalar (), "got SIGTERM\n", 'SIGTERM was recorded'); ok (eof OUT, 'No more child output written'); chomp $cache; ok (! -f $cache, 'New child cache removed'); ok (!-f "$TMP/pid", ' and the PID file was removed'); ok (!-f "$TMP/child-pid", ' and the child PID file was removed'); unlink "$TMP/child-out"; # One more time to test propagation of QUIT signals. ($out, $err, $status) = command ($KRENEW, '-bK', 30, '-p', "$TMP/pid", '-c', "$TMP/child-pid", '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding krenew works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } kill (3, $pid) or warn "Cannot send QUIT to parent $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'krenew is no longer running'); ok (!kill (0, $child), 'The child process is no longer running'); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open $TMP/child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); $cache = scalar ; like ($cache, qr%^/tmp/krb5cc_%, 'Child cache is correct'); is (scalar (), "got SIGQUIT\n", 'SIGQUIT was recorded'); ok (eof OUT, 'No more child output written'); close OUT; chomp $cache; ok (! -f $cache, 'New child cache removed'); ok (!-f "$TMP/pid", ' and the PID file was removed'); ok (!-f "$TMP/child-pid", ' and the child PID file was removed'); unlink "$TMP/child-out"; # Normally, if we are running a command and krenew has to exit because it # can't renew the ticket cache any more, it should exit and leave the command # running. ($out, $err, $status) = command ($KRENEW, '-bK', 30, '-p', "$TMP/pid", '-c', "$TMP/child-pid", '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding krenew works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } select (undef, undef, undef, 0.2); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open $TMP/child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); $cache = scalar ; chomp $cache; like ($cache, qr%^/tmp/krb5cc_%, 'Child cache is correct'); unlink $cache; kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'krenew dies after failure to renew'); ok (kill (0, $child), ' and the child process is still running'); kill (15, $child) or warn "Can't kill child $child: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $child), 'The child process is no longer running'); is (scalar (), "got SIGTERM\n", 'SIGTERM was recorded'); ok (eof OUT, 'No more child output written'); close OUT; ok (!-f "$TMP/pid", ' and the PID file was removed'); ok (!-f "$TMP/child-pid", ' and the child PID file was removed'); unlink "$TMP/child-out"; # If run with -s, krenew should instead kill the child process with HUP on # failure to renew the ticket. ($out, $err, $status) = command ($KRENEW, '-bsK', 30, '-p', "$TMP/pid", '-c', "$TMP/child-pid", '--', "$ENV{SOURCE}/data/command", "$TMP/child-out"); is ($status, 0, 'Backgrounding krenew -s works'); is ($err, '', ' with no error output'); is ($out, '', ' and output was redirected properly'); $tries = 0; while (not -f "$TMP/child-pid" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } $pid = contents ("$TMP/pid"); ok (kill (0, $pid), 'krenew is running'); $child = contents ("$TMP/child-pid"); ok (kill (0, $child), 'The child process is running'); $tries = 0; while (not -S "$TMP/child-out" and $tries < 10) { select (undef, undef, undef, 0.1); $tries++; } select (undef, undef, undef, 0.2); open (OUT, '<', "$TMP/child-out") or BAIL_OUT ("cannot open $TMP/child-out: $!"); is (scalar (), "$child\n", 'Child PID is correct'); is (scalar (), "/\n", 'Child working directory is /'); $cache = scalar ; chomp $cache; like ($cache, qr%^/tmp/krb5cc_%, 'Child cache is correct'); unlink $cache; kill (14, $pid) or warn "Can't kill $pid: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $pid), 'krenew dies after failure to renew'); ok (kill (0, $child), ' and the child process is still running'); kill (15, $child) or warn "Can't kill child $child: $!\n"; select (undef, undef, undef, 0.2); ok (!kill (0, $child), 'The child process is no longer running'); is (scalar (), "got SIGHUP\n", 'SIGHUP was recorded'); is (scalar (), "got SIGTERM\n", 'SIGTERM was recorded'); ok (eof OUT, 'No more child output written'); close OUT; ok (!-f "$TMP/pid", ' and the PID file was removed'); ok (!-f "$TMP/child-pid", ' and the child PID file was removed'); unlink "$TMP/child-out"; # Clean up. unlink "$TMP/krb5cc_test", "$TMP/child-out"; rmdir $TMP; kstart-4.1/tests/kafs/0000755000175000000000000000000011702213052011731 500000000000000kstart-4.1/tests/kafs/basic.c0000644000175000000000000000572111702213030013077 00000000000000/* * Test suite for kafs library. * * This is the backend program run by the kafs-t driver script. It first * checks whether k_hasafs returns true. If it doesn't, it exits with status * 2, indicating that all tests should be skipped. Otherwise, it runs * k_setpag, then tokens, then aklog, then tokens, and then k_unlog, sending * the output to standard output and errors to standard error. If either * k_setpag or k_unlog return failure, it reports an error to standard error * and exits with status 1. If aklog fails, it exits with status 3. If the * commands all finish, it exits 0. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2009, 2010 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include /* * If the program that includes this test case uses aklog for other purposes, * it may have detected a path to aklog during the build and set it as * PATH_AKLOG. Use that if it's available, falling back on searching the * user's path. */ #ifndef PATH_AKLOG # define PATH_AKLOG "aklog" #endif int main(void) { if (!k_hasafs()) exit(2); #ifdef NO_PAG_SUPPORT exit(2); #endif if (k_setpag() != 0) { fprintf(stderr, "k_setpag failed: %s\n", strerror(errno)); exit(1); } printf("=== tokens (setpag) ===\n"); fflush(stdout); system("tokens"); if (system(PATH_AKLOG) != 0) exit(3); printf("=== tokens (aklog) ===\n"); fflush(stdout); system("tokens"); if (k_unlog() != 0) { fprintf(stderr, "k_unlog failed: %s", strerror(errno)); exit(1); } printf("=== tokens (unlog) ===\n"); fflush(stdout); system("tokens"); return 0; } kstart-4.1/tests/kafs/haspag-t.c0000644000175000000000000000377511702213030013531 00000000000000/* * Test suite for k_haspag. * * Currently, we can't do a lot to test this, since there's no way to drop a * PAG once one is in one. The average user will be running this in a PAG, so * k_haspag will always return true. But we can at least confirm that. * * The canonical version of this file is maintained in the rra-c-util package, * which can be found at . * * Written by Russ Allbery * Copyright 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include int main(void) { if (!k_hasafs()) skip_all("AFS not available"); plan(2); #ifdef NO_PAG_SUPPORT skip_block(2, "OS has no PAG support"); #else is_int(0, k_setpag(), "k_setpag succeeds"); is_int(1, k_haspag(), "k_haspag now returns true"); #endif return 0; } kstart-4.1/tests/kafs/basic-t0000755000175000000000000000665711702213030013133 00000000000000#!/bin/sh # # Test suite for the kafs library. # # The canonical version of this file is maintained in the rra-c-util package, # which can be found at . # # Written by Russ Allbery # Copyright 2009 # The Board of Trustees of the Leland Stanford Junior University # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. . "$SOURCE/tap/libtap.sh" cd "$BUILD/kafs" # Check whether we already have a token. if tokens | grep -i 'tokens for ' >/dev/null ; then tokens=true else tokens=false fi # Run the helper program and save its output and error. ./basic > basic-output 2> basic-errors status=$? # If it exited with status 2, AFS is apparently not running and we should skip # all of the tests. if [ "$status" -eq 2 ] ; then rm -f basic-output basic-errors skip_all 'AFS not available' fi plan 5 # If we don't currently have a token, we can't check that it disappears after # k_setpag. Otherwise, check the first tokens output and be sure that no # tokens are seen. if sed -n '/^=== tokens .setpag./,/^===/p' basic-output \ | grep -i 'tokens for ' > /dev/null ; then ok 'k_setpag hides existing tokens' false else if [ "$tokens" = true ] ; then ok 'k_setpag hides existing tokens' true else skip 'no existing tokens' fi fi # If aklog failed, we can't run the rest of the tests. if [ "$status" -eq 3 ] ; then skip_block 3 'aklog failed' else if sed -n '/^=== tokens .aklog./,/^===/p' basic-output \ | grep -i 'tokens for ' > /dev/null ; then ok 'token present after aklog' true else ok 'token present after aklog' false fi # Check for no token after k_unlog. if sed -n '/^=== tokens .unlog./,/^===/p' basic-output \ | grep -i 'tokens for ' > /dev/null ; then ok 'token absent after unlog' false else ok 'token absent after unlog' true fi # Be sure that everything succeeded; otherwise print out the errors file. if [ "$status" -ne 0 ] ; then sed 's/^/# /' basic-errors fi ok 'all kafs calls succeeded' [ "$status" -eq 0 ] fi # Ensure that none of this affected our starting token. if [ "$tokens" = true ] ; then if tokens | grep -i 'tokens for ' >/dev/null ; then ok 'still have initial token' true else ok 'still have initial token' false fi else skip 'no existing tokens' fi # Clean up. rm -f basic-output basic-errors kstart-4.1/k5start.pod0000644000175000000000000004151311702213030011664 00000000000000=for stopwords -bFhLnPqstvx keytab username kinit LDAP aklog HUP ALRM KRB5CCNAME AFS PAG init AKLOG kstart krenew afslog Bense Allbery Navid Golpayegani forwardable proxiable designator Ctrl-C =head1 NAME k5start - Obtain and optionally keep active a Kerberos ticket =head1 SYNOPSIS B [B<-bFhLnPqstvx>] [B<-c> I] [B<-f> I] [B<-g> I] [B<-H> I] [B<-I> I] [B<-i> I] [B<-K> I] [B<-k> I] [B<-l> I