From 529a91d69ad9d44bfd1de0813d89e5bdac094f08 Mon Sep 17 00:00:00 2001 From: Viktor Dukhovni Date: Sun, 22 May 2016 16:59:25 -0400 Subject: [PATCH] MacOS/X fixes --- kdc/config.c | 6 +++ kdc/connect.c | 125 +++++++++++++++++++++++++++++++------------ kdc/kdc-tester.c | 1 + kdc/kdc_locl.h | 3 +- kdc/main.c | 3 +- lib/hcrypto/evp-cc.c | 1 + 6 files changed, 102 insertions(+), 37 deletions(-) diff --git a/kdc/config.c b/kdc/config.c index 16a72c59b..f5ce794fb 100644 --- a/kdc/config.c +++ b/kdc/config.c @@ -102,6 +102,12 @@ static struct getargs args[] = { "daemon-child", 0 , arg_flag, &daemon_child, "private argument, do not use", NULL }, +#ifdef __APPLE__ + { + "bonjour", 0 , arg_flag, &do_bonjour, + "private argument, do not use", NULL + }, +#endif { "addresses", 0, arg_strings, &addresses_str, "addresses to listen on", "list of addresses" }, { "disable-des", 0, arg_flag, &disable_des, diff --git a/kdc/connect.c b/kdc/connect.c index 60352a8c7..628f93526 100644 --- a/kdc/connect.c +++ b/kdc/connect.c @@ -47,6 +47,7 @@ struct port_desc{ static struct port_desc *ports; static size_t num_ports; +static pid_t bonjour_pid = -1; /* * add `family, port, protocol' to the list with duplicate suppresion. @@ -258,6 +259,7 @@ init_socket(krb5_context context, d->s = rk_INVALID_SOCKET; return; } + rk_cloexec(d->s); #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) { int one = 1; @@ -833,11 +835,11 @@ handle_tcp(krb5_context context, static void handle_islive(int fd) { - char buf[2]; + char buf; int ret; - ret = read(fd, buf, 2); - if (ret == 0) + ret = read(fd, &buf, 1); + if (ret != 1) exit_flag = -1; } #endif @@ -971,17 +973,28 @@ loop(krb5_context context, krb5_kdc_configuration *config, #ifdef __APPLE__ static void -bonjour_kid(krb5_context context, krb5_kdc_configuration *config, int islive) +bonjour_kid(krb5_context context, krb5_kdc_configuration *config, const char *argv0, int *islive) { - char buf[2]; + char buf; - if (fork()) + if (do_bonjour > 0) { + bonjour_announce(context, config); + + while (read(0, &buf, 1) == 1) + continue; + _exit(0); + } + + if ((bonjour_pid = fork()) != 0) return; - bonjour_announce(context, config); - while (read(islive, buf, 1) != 0) - ; - exit(0); + close(islive[0]); + if (dup2(islive[1], 0) == -1) + err(1, "failed to announce with bonjour (dup)"); + if (islive[1] != 0) + close(islive[1]); + execlp(argv0, "kdc", "--bonjour", NULL); + err(1, "failed to announce with bonjour (exec)"); } #endif @@ -994,6 +1007,8 @@ kill_kids(pid_t *pids, int max_kids, int sig) for (i=0; i < max_kids; i++) if (pids[i] > 0) kill(sig, pids[i]); + if (bonjour_pid > 0) + kill(sig, bonjour_pid); } static int @@ -1001,6 +1016,7 @@ reap_kid(krb5_context context, krb5_kdc_configuration *config, pid_t *pids, int max_kids, int options) { pid_t pid; + char *what; int status; int i; @@ -1008,21 +1024,39 @@ reap_kid(krb5_context context, krb5_kdc_configuration *config, if (pid < 1) return 0; - for (i=0; i < max_kids; i++) { - if (pids[i] == pid) - break; + if (pid != bonjour_pid) { + for (i=0; i < max_kids; i++) { + if (pids[i] == pid) + break; + } + + if (i == max_kids) { + /* XXXrcd: this should not happen, have to do something, though */ + return 0; + } } - if (i == max_kids) { - /* XXXrcd: this should not happen, have to do something, though */ - return 0; + if (pid == bonjour_pid) + what = "bonjour"; + else + what = "worker"; + if (WIFEXITED(status)) + kdc_log(context, config, 0, "KDC reaped %s process: %d, exit status: %d", + what, (int)pid, WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + kdc_log(context, config, 0, "KDC reaped %s process: %d, term signal %d%s", + what, (int)pid, WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); + else + kdc_log(context, config, 0, "KDC reaped %s process: %d", + what, (int)pid); + if (pid == bonjour_pid) { + bonjour_pid = (pid_t)-1; + return 0; + } else { + pids[i] = (pid_t)-1; + return 1; } - - /* XXXrcd: should likely log exit code and the like */ - kdc_log(context, config, 0, "KDC worker process reaped: %d", pid); - pids[i] = (pid_t)-1; - - return 1; } static int @@ -1053,7 +1087,7 @@ select_sleep(int microseconds) void start_kdc(krb5_context context, - krb5_kdc_configuration *config) + krb5_kdc_configuration *config, const char *argv0) { struct timeval tv1; struct timeval tv2; @@ -1068,6 +1102,11 @@ start_kdc(krb5_context context, int islive[2]; #endif +#ifdef __APPLE__ + if (do_bonjour > 0) + bonjour_kid(context, config, argv0, NULL); +#endif + #ifdef HAVE_FORK #ifdef _SC_NPROCESSORS_ONLN if (max_kdcs < 1) @@ -1099,9 +1138,10 @@ start_kdc(krb5_context context, #ifdef HAVE_FORK -#ifdef __APPLE__ - bonjour_kid(context, config, islive[1]); /* fork()s */ -#endif +# ifdef __APPLE__ + if (do_bonjour < 0) + bonjour_kid(context, config, argv0, islive); +# endif kdc_log(context, config, 0, "KDC started master process pid=%d", getpid()); #else @@ -1165,34 +1205,49 @@ start_kdc(krb5_context context, close(islive[0]); close(islive[1]); - gettimeofday(&tv1, NULL); + /* Close our listener sockets before terminating workers */ + for (i = 0; i < ndescr; ++i) + clear_descr(&d[i]); + gettimeofday(&tv1, NULL); + tv2 = tv1; + + /* Reap every 10ms, terminate stragglers once a second, give up after 10 */ for (;;) { + struct timeval tv3; num_kdcs -= reap_kids(context, config, pids, max_kdcs); - if (num_kdcs == 0) - break; + if (num_kdcs == 0 && bonjour_pid <= 0) + goto end; /* * Using select to sleep will fail with EINTR if we receive a * SIGCHLD. This is desirable. */ - select_sleep(200000); - kill_kids(pids, max_kdcs, SIGTERM); - gettimeofday(&tv2, NULL); - if (tv2.tv_sec - tv1.tv_sec > 10) + select_sleep(10000); + gettimeofday(&tv3, NULL); + if (tv3.tv_sec - tv1.tv_sec > 10 || + (tv3.tv_sec - tv1.tv_sec == 10 && tv3.tv_usec >= tv1.tv_usec)) break; + if (tv3.tv_sec - tv2.tv_sec > 1 || + (tv3.tv_sec - tv2.tv_sec == 1 && tv3.tv_usec >= tv2.tv_usec)) { + kill_kids(pids, max_kdcs, SIGTERM); + tv2 = tv3; + } } + /* Kill stragglers and reap every 200ms, give up after 15s */ for (;;) { kill_kids(pids, max_kdcs, SIGKILL); num_kdcs -= reap_kids(context, config, pids, max_kdcs); - if (num_kdcs == 0) + if (num_kdcs == 0 && bonjour_pid <= 0) break; select_sleep(200000); gettimeofday(&tv2, NULL); - if (tv2.tv_sec - tv1.tv_sec > 15) + if (tv2.tv_sec - tv1.tv_sec > 15 || + (tv2.tv_sec - tv1.tv_sec == 15 && tv2.tv_usec >= tv1.tv_usec)) break; } + end: kdc_log(context, config, 0, "KDC master process exiting", pid); free(pids); #else diff --git a/kdc/kdc-tester.c b/kdc/kdc-tester.c index bb4d1ea3e..cbe4b1c00 100644 --- a/kdc/kdc-tester.c +++ b/kdc/kdc-tester.c @@ -46,6 +46,7 @@ struct perf { int detach_from_console = -1; int daemon_child = -1; +int do_bonjour = -1; static krb5_kdc_configuration *kdc_config; static krb5_context kdc_context; diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index f21ff3254..10cbc1d37 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -101,6 +101,7 @@ extern int enable_http; extern int detach_from_console; extern int daemon_child; +extern int do_bonjour; extern const struct units _kdc_digestunits[]; @@ -113,7 +114,7 @@ extern char *runas_string; extern char *chroot_string; void -start_kdc(krb5_context context, krb5_kdc_configuration *config); +start_kdc(krb5_context context, krb5_kdc_configuration *config, const char *argv0); krb5_kdc_configuration * configure(krb5_context context, int argc, char **argv, int *optidx); diff --git a/kdc/main.c b/kdc/main.c index 4367cadbf..a2bd56680 100644 --- a/kdc/main.c +++ b/kdc/main.c @@ -46,6 +46,7 @@ sig_atomic_t exit_flag = 0; int detach_from_console = -1; int daemon_child = -1; +int do_bonjour = -1; static RETSIGTYPE sigchld(int sig) @@ -172,7 +173,7 @@ main(int argc, char **argv) switch_environment(); - start_kdc(context, config); + start_kdc(context, config, argv[0]); krb5_free_context(context); return 0; } diff --git a/lib/hcrypto/evp-cc.c b/lib/hcrypto/evp-cc.c index eb4793b64..4a377f1c3 100644 --- a/lib/hcrypto/evp-cc.c +++ b/lib/hcrypto/evp-cc.c @@ -50,6 +50,7 @@ #endif #include +#include #include /*