diff --git a/cf/roken-frag.m4 b/cf/roken-frag.m4 index e4db259ce..faf8daf68 100644 --- a/cf/roken-frag.m4 +++ b/cf/roken-frag.m4 @@ -307,14 +307,10 @@ AC_FIND_IF_NOT_BROKEN(gai_strerror,, #include #endif],[0]) -dnl Darwin is weird, and in some senses not unix, launchd doesn't want -dnl servers to use daemon(), so its deprecated. case "$host_os" in darwin*) ;; *) - AC_DEFINE([SUPPORT_DETACH], 1, - [Define if os support want to detach is daemonens.]) AC_BROKEN([daemon]) ;; esac diff --git a/kadmin/kadm_conn.c b/kadmin/kadm_conn.c index 58aceb8e1..0baf165af 100644 --- a/kadmin/kadm_conn.c +++ b/kadmin/kadm_conn.c @@ -36,6 +36,8 @@ #include #endif +extern int daemon_child; + struct kadm_port { char *port; unsigned short def_port; @@ -292,5 +294,7 @@ start_server(krb5_context contextp, const char *port_str) if(num_socks == 0) krb5_errx(contextp, 1, "no sockets to listen to - exiting"); + roken_detach_finish(NULL, daemon_child); + wait_for_connection(contextp, socks, num_socks); } diff --git a/kadmin/kadmind.c b/kadmin/kadmind.c index 916374a0b..12abaa598 100644 --- a/kadmin/kadmind.c +++ b/kadmin/kadmind.c @@ -45,6 +45,9 @@ static int debug_flag; static char *port_str; char *realm; +static int detach_from_console = -1; +int daemon_child = -1; + static struct getargs args[] = { { "config-file", 'c', arg_string, &config_file, @@ -68,6 +71,14 @@ static struct getargs args[] = { { "debug", 'd', arg_flag, &debug_flag, "enable debugging", NULL }, + { + "detach", 0 , arg_flag, &detach_from_console, + "detach from console", NULL + }, + { + "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL + }, { "ports", 'p', arg_string, &port_str, "ports to listen to", "port" }, { "help", 'h', arg_flag, &help_flag, NULL, NULL }, @@ -98,10 +109,6 @@ main(int argc, char **argv) setprogname(argv[0]); - ret = krb5_init_context(&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - if (getarg(args, num_args, argc, argv, &optidx)) { warnx("error at argument `%s'", argv[optidx]); usage(1); @@ -115,6 +122,13 @@ main(int argc, char **argv) exit(0); } + if (detach_from_console > 0 && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); + + ret = krb5_init_context(&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + argc -= optidx; argv += optidx; diff --git a/kcm/config.c b/kcm/config.c index bb4530a21..a3a7d3465 100644 --- a/kcm/config.c +++ b/kcm/config.c @@ -44,10 +44,8 @@ char *door_path = NULL; static char *max_request_str; /* `max_request' as a string */ -#ifdef SUPPORT_DETACH int detach_from_console = -1; -#define DETACH_IS_DEFAULT FALSE -#endif +int daemon_child = -1; static const char *system_cache_name = NULL; static const char *system_keytab = NULL; @@ -88,19 +86,14 @@ static struct getargs args[] = { "launchd", 0, arg_flag, &launchd_flag, "when in use by launchd", NULL }, -#ifdef SUPPORT_DETACH -#if DETACH_IS_DEFAULT - { - "detach", 'D', arg_negative_flag, &detach_from_console, - "don't detach from console", NULL - }, -#else { "detach", 0 , arg_flag, &detach_from_console, "detach from console", NULL }, -#endif -#endif + { + "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL + }, { "help", 'h', arg_flag, &help_flag, NULL, NULL }, { "system-principal", 'k', arg_string, &system_principal, @@ -331,10 +324,10 @@ kcm_configure(int argc, char **argv) int optidx = 0; const char *p; - while(getarg(args, num_args, argc, argv, &optidx)) + while (getarg(args, num_args, argc, argv, &optidx)) warnx("error at argument `%s'", argv[optidx]); - if(help_flag) + if (help_flag) usage (0); if (version_flag) { @@ -387,13 +380,11 @@ kcm_configure(int argc, char **argv) krb5_err(kcm_context, 1, ret, "initializing system ccache"); } -#ifdef SUPPORT_DETACH if(detach_from_console == -1) detach_from_console = krb5_config_get_bool_default(kcm_context, NULL, - DETACH_IS_DEFAULT, + FALSE, "kcm", "detach", NULL); -#endif kcm_openlog(); if(max_request == 0) max_request = 64 * 1024; diff --git a/kcm/kcm_locl.h b/kcm/kcm_locl.h index 56bb7045b..a70e8b839 100644 --- a/kcm/kcm_locl.h +++ b/kcm/kcm_locl.h @@ -169,9 +169,8 @@ extern char *door_path; extern size_t max_request; extern sig_atomic_t exit_flag; extern int name_constraints; -#ifdef SUPPORT_DETACH extern int detach_from_console; -#endif +extern int daemon_child; extern int launchd_flag; extern int disallow_getting_krbtgt; diff --git a/kcm/main.c b/kcm/main.c index eb836ed28..38c577fb8 100644 --- a/kcm/main.c +++ b/kcm/main.c @@ -86,11 +86,8 @@ main(int argc, char **argv) signal(SIGUSR2, sigusr2); signal(SIGPIPE, SIG_IGN); #endif -#ifdef SUPPORT_DETACH - if (detach_from_console) - if (daemon(0, 0) == -1) - err(1, "daemon"); -#endif + if (detach_from_console && !launchd_flag && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); pidfile(NULL); if (launchd_flag) { @@ -101,6 +98,8 @@ main(int argc, char **argv) heim_sipc_service_unix(service_name, kcm_service, NULL, &un); } + roken_detach_finish(NULL, daemon_child); + heim_ipc_main(); krb5_free_context(kcm_context); diff --git a/kdc/config.c b/kdc/config.c index bc5820c75..16a72c59b 100644 --- a/kdc/config.c +++ b/kdc/config.c @@ -94,19 +94,14 @@ static struct getargs args[] = { { "ports", 'P', arg_string, rk_UNCONST(&port_str), "ports to listen to", "portspec" }, -#ifdef SUPPORT_DETACH -#if DETACH_IS_DEFAULT - { - "detach", 'D', arg_negative_flag, &detach_from_console, - "don't detach from console", NULL - }, -#else { "detach", 0 , arg_flag, &detach_from_console, "detach from console", NULL }, -#endif -#endif + { + "daemon-child", 0 , arg_flag, &daemon_child, + "private argument, do not use", NULL + }, { "addresses", 0, arg_strings, &addresses_str, "addresses to listen on", "list of addresses" }, { "disable-des", 0, arg_flag, &disable_des, @@ -158,10 +153,10 @@ configure(krb5_context context, int argc, char **argv, int *optidx) *optidx = 0; - while(getarg(args, num_args, argc, argv, optidx)) + while (getarg(args, num_args, argc, argv, optidx)) warnx("error at argument `%s'", argv[*optidx]); - if(help_flag) + if (help_flag) usage (0); if (version_flag) { @@ -179,6 +174,15 @@ configure(krb5_context context, int argc, char **argv, int *optidx) exit(0); } + if(detach_from_console == -1) + detach_from_console = krb5_config_get_bool_default(context, NULL, + FALSE, + "kdc", + "detach", NULL); + + if (detach_from_console && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); + { char **files; int aret; @@ -265,14 +269,6 @@ configure(krb5_context context, int argc, char **argv, int *optidx) krb5_errx(context, 1, "enforce-transited-policy deprecated, " "use [kdc]transited-policy instead"); -#ifdef SUPPORT_DETACH - if(detach_from_console == -1) - detach_from_console = krb5_config_get_bool_default(context, NULL, - DETACH_IS_DEFAULT, - "kdc", - "detach", NULL); -#endif /* SUPPORT_DETACH */ - if(max_request_tcp == 0) max_request_tcp = 64 * 1024; if(max_request_udp == 0) diff --git a/kdc/connect.c b/kdc/connect.c index 52c8f5ee0..81ef8cba0 100644 --- a/kdc/connect.c +++ b/kdc/connect.c @@ -867,16 +867,17 @@ next_min_free(krb5_context context, struct descr **d, unsigned int *ndescr) } void -loop(krb5_context context, - krb5_kdc_configuration *config) +loop(krb5_context context, krb5_kdc_configuration *config) { struct descr *d; unsigned int ndescr; + int ret; ndescr = init_sockets(context, config, &d); if(ndescr <= 0) krb5_errx(context, 1, "No sockets!"); kdc_log(context, config, 0, "KDC started"); + roken_detach_finish(NULL, daemon_child); while(exit_flag == 0){ struct timeval tmout; fd_set fds; diff --git a/kdc/kdc-tester.c b/kdc/kdc-tester.c index 4f2597102..bb4d1ea3e 100644 --- a/kdc/kdc-tester.c +++ b/kdc/kdc-tester.c @@ -44,10 +44,8 @@ struct perf { struct perf *next; } *ptop; -#ifdef SUPPORT_DETACH int detach_from_console = -1; -#define DETACH_IS_DEFAULT FALSE -#endif +int daemon_child = -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 804eebeaf..1a30cca28 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -99,12 +99,8 @@ extern krb5_addresses explicit_addresses; extern int enable_http; -#ifdef SUPPORT_DETACH - -#define DETACH_IS_DEFAULT FALSE - extern int detach_from_console; -#endif +extern int daemon_child; extern const struct units _kdc_digestunits[]; diff --git a/kdc/main.c b/kdc/main.c index 258b31b2c..50ac8e41d 100644 --- a/kdc/main.c +++ b/kdc/main.c @@ -44,9 +44,8 @@ sig_atomic_t exit_flag = 0; -#ifdef SUPPORT_DETACH int detach_from_console = -1; -#endif +int daemon_child = -1; static RETSIGTYPE sigterm(int sig) @@ -105,7 +104,6 @@ switch_environment(void) #endif } - int main(int argc, char **argv) { @@ -157,10 +155,6 @@ main(int argc, char **argv) signal(SIGPIPE, SIG_IGN); #endif #endif -#ifdef SUPPORT_DETACH - if (detach_from_console) - daemon(0, 0); -#endif #ifdef __APPLE__ bonjour_announce(context, config); #endif diff --git a/kpasswd/kpasswdd.c b/kpasswd/kpasswdd.c index a7533109a..6459f5e44 100644 --- a/kpasswd/kpasswdd.c +++ b/kpasswd/kpasswdd.c @@ -644,8 +644,46 @@ out: krb5_auth_con_free(context, auth_context); } +static const char *check_library = NULL; +static const char *check_function = NULL; +static getarg_strings policy_libraries = { 0, NULL }; +static char sHDB[] = "HDBGET:"; +static char *keytab_str = sHDB; +static char *realm_str; +static int version_flag; +static int help_flag; +static int detach_from_console; +static int daemon_child = -1; +static char *port_str; +static char *config_file; + +struct getargs args[] = { +#ifdef HAVE_DLOPEN + { "check-library", 0, arg_string, &check_library, + "library to load password check function from", "library" }, + { "check-function", 0, arg_string, &check_function, + "password check function to load", "function" }, + { "policy-libraries", 0, arg_strings, &policy_libraries, + "password check function to load", "function" }, +#endif + { "addresses", 0, arg_strings, &addresses_str, + "addresses to listen on", "list of addresses" }, + { "detach", 0, arg_flag, &detach_from_console, + "detach from console", NULL }, + { "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL }, + { "keytab", 'k', arg_string, &keytab_str, + "keytab to get authentication key from", "kspec" }, + { "config-file", 'c', arg_string, &config_file, NULL, NULL }, + { "realm", 'r', arg_string, &realm_str, "default realm", "realm" }, + { "port", 'p', arg_string, &port_str, "port", NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + static int -doit (krb5_keytab keytab, int port) +doit(krb5_keytab keytab, int port) { krb5_error_code ret; int *sockets; @@ -659,54 +697,56 @@ doit (krb5_keytab keytab, int port) if (explicit_addresses.len) { addrs = explicit_addresses; } else { - ret = krb5_get_all_server_addrs (context, &addrs); + ret = krb5_get_all_server_addrs(context, &addrs); if (ret) - krb5_err (context, 1, ret, "krb5_get_all_server_addrs"); + krb5_err(context, 1, ret, "krb5_get_all_server_addrs"); } n = addrs.len; - sockets = malloc (n * sizeof(*sockets)); + sockets = malloc(n * sizeof(*sockets)); if (sockets == NULL) - krb5_errx (context, 1, "out of memory"); + krb5_errx(context, 1, "out of memory"); maxfd = -1; FD_ZERO(&real_fdset); for (i = 0; i < n; ++i) { krb5_socklen_t sa_size = sizeof(__ss); - krb5_addr2sockaddr (context, &addrs.val[i], sa, &sa_size, port); + krb5_addr2sockaddr(context, &addrs.val[i], sa, &sa_size, port); - sockets[i] = socket (__ss.ss_family, SOCK_DGRAM, 0); + sockets[i] = socket(__ss.ss_family, SOCK_DGRAM, 0); if (sockets[i] < 0) - krb5_err (context, 1, errno, "socket"); - if (bind (sockets[i], sa, sa_size) < 0) { + krb5_err(context, 1, errno, "socket"); + if (bind(sockets[i], sa, sa_size) < 0) { char str[128]; size_t len; int save_errno = errno; - ret = krb5_print_address (&addrs.val[i], str, sizeof(str), &len); + ret = krb5_print_address(&addrs.val[i], str, sizeof(str), &len); if (ret) strlcpy(str, "unknown address", sizeof(str)); - krb5_warn (context, save_errno, "bind(%s)", str); + krb5_warn(context, save_errno, "bind(%s)", str); continue; } - maxfd = max (maxfd, sockets[i]); + maxfd = max(maxfd, sockets[i]); if (maxfd >= FD_SETSIZE) - krb5_errx (context, 1, "fd too large"); + krb5_errx(context, 1, "fd too large"); FD_SET(sockets[i], &real_fdset); } if (maxfd == -1) - krb5_errx (context, 1, "No sockets!"); + krb5_errx(context, 1, "No sockets!"); - while(exit_flag == 0) { + roken_detach_finish(NULL, daemon_child); + + while (exit_flag == 0) { krb5_ssize_t retx; fd_set fdset = real_fdset; - retx = select (maxfd + 1, &fdset, NULL, NULL, NULL); + retx = select(maxfd + 1, &fdset, NULL, NULL, NULL); if (retx < 0) { if (errno == EINTR) continue; else - krb5_err (context, 1, errno, "select"); + krb5_err(context, 1, errno, "select"); } for (i = 0; i < n; ++i) if (FD_ISSET(sockets[i], &fdset)) { @@ -716,13 +756,13 @@ doit (krb5_keytab keytab, int port) retx = recvfrom(sockets[i], buf, sizeof(buf), 0, sa, &addrlen); if (retx < 0) { - if(errno == EINTR) + if (errno == EINTR) break; else - krb5_err (context, 1, errno, "recvfrom"); + krb5_err(context, 1, errno, "recvfrom"); } - process (keytab, sockets[i], + process(keytab, sockets[i], &addrs.val[i], sa, addrlen, buf, retx); @@ -733,8 +773,8 @@ doit (krb5_keytab keytab, int port) close(sockets[i]); free(sockets); - krb5_free_addresses (context, &addrs); - krb5_free_context (context); + krb5_free_addresses(context, &addrs); + krb5_free_context(context); return 0; } @@ -744,40 +784,8 @@ sigterm(int sig) exit_flag = 1; } -static const char *check_library = NULL; -static const char *check_function = NULL; -static getarg_strings policy_libraries = { 0, NULL }; -static char sHDB[] = "HDBGET:"; -static char *keytab_str = sHDB; -static char *realm_str; -static int version_flag; -static int help_flag; -static char *port_str; -static char *config_file; - -struct getargs args[] = { -#ifdef HAVE_DLOPEN - { "check-library", 0, arg_string, &check_library, - "library to load password check function from", "library" }, - { "check-function", 0, arg_string, &check_function, - "password check function to load", "function" }, - { "policy-libraries", 0, arg_strings, &policy_libraries, - "password check function to load", "function" }, -#endif - { "addresses", 0, arg_strings, &addresses_str, - "addresses to listen on", "list of addresses" }, - { "keytab", 'k', arg_string, &keytab_str, - "keytab to get authentication key from", "kspec" }, - { "config-file", 'c', arg_string, &config_file, NULL, NULL }, - { "realm", 'r', arg_string, &realm_str, "default realm", "realm" }, - { "port", 'p', arg_string, &port_str, "port", NULL }, - { "version", 0, arg_flag, &version_flag, NULL, NULL }, - { "help", 0, arg_flag, &help_flag, NULL, NULL } -}; -int num_args = sizeof(args) / sizeof(args[0]); - int -main (int argc, char **argv) +main(int argc, char **argv) { krb5_keytab keytab; krb5_error_code ret; @@ -787,13 +795,17 @@ main (int argc, char **argv) krb5_program_setup(&context, argc, argv, args, num_args, NULL); - if(help_flag) + if (help_flag) krb5_std_usage(0, args, num_args); - if(version_flag) { + + if (version_flag) { print_version(NULL); exit(0); } + if (detach_from_console > 0 && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); + if (config_file == NULL) { aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); if (aret == -1) @@ -809,37 +821,37 @@ main (int argc, char **argv) if (ret) krb5_err(context, 1, ret, "reading configuration files"); - if(realm_str) + if (realm_str) krb5_set_default_realm(context, realm_str); - krb5_openlog (context, "kpasswdd", &log_facility); + krb5_openlog(context, "kpasswdd", &log_facility); krb5_set_warn_dest(context, log_facility); if (port_str != NULL) { - struct servent *s = roken_getservbyname (port_str, "udp"); + struct servent *s = roken_getservbyname(port_str, "udp"); if (s != NULL) port = s->s_port; else { char *ptr; - port = strtol (port_str, &ptr, 10); + port = strtol(port_str, &ptr, 10); if (port == 0 && ptr == port_str) - krb5_errx (context, 1, "bad port `%s'", port_str); + krb5_errx(context, 1, "bad port `%s'", port_str); port = htons(port); } } else - port = krb5_getportbyname (context, "kpasswd", "udp", KPASSWD_PORT); + port = krb5_getportbyname(context, "kpasswd", "udp", KPASSWD_PORT); ret = krb5_kt_register(context, &hdb_get_kt_ops); - if(ret) + if (ret) krb5_err(context, 1, ret, "krb5_kt_register"); ret = krb5_kt_resolve(context, keytab_str, &keytab); - if(ret) + if (ret) krb5_err(context, 1, ret, "%s", keytab_str); - kadm5_setup_passwd_quality_check (context, check_library, check_function); + kadm5_setup_passwd_quality_check(context, check_library, check_function); for (i = 0; i < policy_libraries.num_strings; i++) { ret = kadm5_add_passwd_quality_verifier(context, @@ -858,16 +870,16 @@ main (int argc, char **argv) int j; for (j = 0; j < addresses_str.num_strings; ++j) - add_one_address (addresses_str.strings[j], j == 0); - free_getarg_strings (&addresses_str); + add_one_address(addresses_str.strings[j], j == 0); + free_getarg_strings(&addresses_str); } else { - char **foo = krb5_config_get_strings (context, NULL, + char **foo = krb5_config_get_strings(context, NULL, "kdc", "addresses", NULL); if (foo != NULL) { - add_one_address (*foo++, TRUE); + add_one_address(*foo++, TRUE); while (*foo) - add_one_address (*foo++, FALSE); + add_one_address(*foo++, FALSE); } } @@ -889,5 +901,5 @@ main (int argc, char **argv) pidfile(NULL); - return doit (keytab, port); + return doit(keytab, port); } diff --git a/lib/kadm5/ipropd_master.c b/lib/kadm5/ipropd_master.c index 6f27ca552..3f9635c79 100644 --- a/lib/kadm5/ipropd_master.c +++ b/lib/kadm5/ipropd_master.c @@ -929,9 +929,8 @@ static char *keytab_str = sHDB; static char *database; static char *config_file; static char *port_str; -#ifdef SUPPORT_DETACH -static int detach_from_console = 0; -#endif +static int detach_from_console; +static int daemon_child = -1; static struct getargs args[] = { { "config-file", 'c', arg_string, &config_file, NULL, NULL }, @@ -947,10 +946,10 @@ static struct getargs args[] = { "time of inactivity after which a slave is considered gone", "time"}, { "port", 0, arg_string, &port_str, "port ipropd will listen to", "port"}, -#ifdef SUPPORT_DETACH { "detach", 0, arg_flag, &detach_from_console, "detach from console", NULL }, -#endif + { "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL }, { "hostname", 0, arg_string, rk_UNCONST(&master_hostname), "hostname of master (if not same as hostname)", "hostname" }, { "version", 0, arg_flag, &version_flag, NULL, NULL }, @@ -973,16 +972,29 @@ main(int argc, char **argv) krb5_keytab keytab; char **files; int aret; + int optidx = 0; - (void) krb5_program_setup(&context, argc, argv, args, num_args, NULL); + setprogname(argv[0]); - if(help_flag) + if (getarg(args, num_args, argc, argv, &optidx)) + krb5_std_usage(1, args, num_args); + + if (help_flag) krb5_std_usage(0, args, num_args); - if(version_flag) { + + if (version_flag) { print_version(NULL); exit(0); } + if (detach_from_console && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); + pidfile(NULL); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context failed: %d", ret); + setup_signal(); if (config_file == NULL) { @@ -1007,17 +1019,7 @@ main(int argc, char **argv) if (time_before_missing < 0) krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing); -#ifdef SUPPORT_DETACH - if (detach_from_console) { - aret = daemon(0, 0); - if (aret == -1) { - /* not much to do if detaching fails... */ - krb5_err(context, 1, aret, "failed to daemon(3)ise"); - } - } -#endif - pidfile (NULL); - krb5_openlog (context, "ipropd-master", &log_facility); + krb5_openlog(context, "ipropd-master", &log_facility); krb5_set_warn_dest(context, log_facility); ret = krb5_kt_register(context, &hdb_get_kt_ops); @@ -1059,7 +1061,9 @@ main(int argc, char **argv) krb5_warnx(context, "ipropd-master started at version: %lu", (unsigned long)current_version); - while(exit_flag == 0){ + roken_detach_finish(NULL, daemon_child); + + while (exit_flag == 0){ slave *p; fd_set readset; int max_fd = 0; diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c index 5caab9bcd..0e87a381e 100644 --- a/lib/kadm5/ipropd_slave.c +++ b/lib/kadm5/ipropd_slave.c @@ -514,9 +514,8 @@ static int version_flag; static int help_flag; static char *keytab_str; static char *port_str; -#ifdef SUPPORT_DETACH -static int detach_from_console = 0; -#endif +static int detach_from_console; +static int daemon_child = -1; static struct getargs args[] = { { "config-file", 'c', arg_string, &config_file, NULL, NULL }, @@ -529,10 +528,10 @@ static struct getargs args[] = { "file to write out status into", "file" }, { "port", 0, arg_string, &port_str, "port ipropd-slave will connect to", "port"}, -#ifdef SUPPORT_DETACH { "detach", 0, arg_flag, &detach_from_console, "detach from console", NULL }, -#endif + { "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL }, { "hostname", 0, arg_string, rk_UNCONST(&slave_str), "hostname of slave (if not same as hostname)", "hostname" }, { "version", 0, arg_flag, &version_flag, NULL, NULL }, @@ -572,16 +571,21 @@ main(int argc, char **argv) setprogname(argv[0]); - if(getarg(args, num_args, argc, argv, &optidx)) + if (getarg(args, num_args, argc, argv, &optidx)) usage(1); - if(help_flag) + if (help_flag) usage(0); - if(version_flag) { + + if (version_flag) { print_version(NULL); exit(0); } + if (detach_from_console && daemon_child == -1) + roken_detach_prep(argc, argv, "--daemon-child"); + pidfile(NULL); + ret = krb5_init_context(&context); if (ret) errx (1, "krb5_init_context failed: %d", ret); @@ -616,17 +620,7 @@ main(int argc, char **argv) krb5_errx(context, 1, "can't allocate status file buffer"); } -#ifdef SUPPORT_DETACH - if (detach_from_console){ - int aret = daemon(0, 0); - if (aret == -1) { - /* not much to do if detaching fails... */ - krb5_err(context, 1, aret, "failed to daemon(3)ise"); - } - } -#endif - pidfile (NULL); - krb5_openlog (context, "ipropd-slave", &log_facility); + krb5_openlog(context, "ipropd-slave", &log_facility); krb5_set_warn_dest(context, log_facility); slave_status(context, status_file, "bootstrapping"); @@ -683,6 +677,8 @@ main(int argc, char **argv) slave_status(context, status_file, "ipropd-slave started"); + roken_detach_finish(NULL, daemon_child); + while (!exit_flag) { time_t now, elapsed; int connected = FALSE; diff --git a/lib/krb5/principal.c b/lib/krb5/principal.c index 5496dd2cf..69fa73219 100644 --- a/lib/krb5/principal.c +++ b/lib/krb5/principal.c @@ -1609,7 +1609,7 @@ make_rules_safe(krb5_context context, krb5_name_canon_rule rules) * conversion. Better let the user get failures and make them think about * their naming rules. */ - if (rules != NULL) + if (rules == NULL) return; for (; rules[0].type != KRB5_NCRT_BOGUS; rules++) { if (rules->type == KRB5_NCRT_NSS) @@ -1843,7 +1843,7 @@ apply_name_canon_rule(krb5_context context, krb5_name_canon_rule rules, } /* If we stripped off a :port, add it back in */ - if (port != NULL) { + if (port != NULL && new_hostname != NULL) { if (asprintf(&hostname_with_port, "%s%s", new_hostname, port) == -1 || hostname_with_port == NULL) { ret = krb5_enomem(context); diff --git a/lib/roken/Makefile.am b/lib/roken/Makefile.am index 72d02d30f..974b82c75 100644 --- a/lib/roken/Makefile.am +++ b/lib/roken/Makefile.am @@ -20,7 +20,9 @@ if HAVE_DBHEADER AM_CPPFLAGS += -I$(DBHEADER) endif -noinst_PROGRAMS = snprintf-test resolve-test rkpty +noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach + +CHECK_LOCAL = snprintf-test resolve-test rkpty make-roken check_PROGRAMS = \ base64-test \ @@ -50,6 +52,8 @@ parse_reply_test_CFLAGS = -DTEST_RESOLVE test_readenv_SOURCES = test-readenv.c test-mem.c +test_detach_SOURCES = test-detach.c + rkpty_LDADD = $(LIB_openpty) $(LDADD) parse_time_test_SOURCES = parse_time-test.c test-mem.c @@ -75,6 +79,7 @@ libroken_la_SOURCES = \ concat.c \ cloexec.c \ ct.c \ + detach.c \ doxygen.c \ dumpdata.c \ environment.c \ diff --git a/lib/roken/NTMakefile b/lib/roken/NTMakefile index 1ae8084ec..57ef7506f 100644 --- a/lib/roken/NTMakefile +++ b/lib/roken/NTMakefile @@ -39,6 +39,7 @@ libroken_la_OBJS = \ $(OBJ)\concat.obj \ $(OBJ)\cloexec.obj \ $(OBJ)\ct.obj \ + $(OBJ)\detach.obj \ $(OBJ)\dirent.obj \ $(OBJ)\dlfcn_w32.obj \ $(OBJ)\dumpdata.obj \ @@ -189,6 +190,7 @@ TEST_PROGS = \ $(OBJ)\getaddrinfo-test.exe \ $(OBJ)\getifaddrs-test.exe \ $(OBJ)\hex-test.exe \ + $(OBJ)\test-detach.exe \ $(OBJ)\test-readenv.exe \ $(OBJ)\parse_bytes-test.exe \ $(OBJ)\parse_reply-test.exe \ @@ -252,6 +254,9 @@ $(OBJ)\hex-test.exe: $(OBJ)\hex-test.obj $(LIBROKEN) $(OBJ)\parse_bytes-test.exe: $(OBJ)\parse_bytes-test.obj $(LIBROKEN) $(EXECONLINK) +$(OBJ)\test-detach.exe: $(OBJ)\test-detach.obj $(OBJ)\detach.obj $(LIBROKEN) + $(EXECONLINK) + $(OBJ)\dirent-test.exe: $(OBJ)\dirent-test.obj $(LIBROKEN) $(EXECONLINK) diff --git a/lib/roken/daemon.c b/lib/roken/daemon.c index 591a9a953..6128bebe3 100644 --- a/lib/roken/daemon.c +++ b/lib/roken/daemon.c @@ -72,7 +72,7 @@ daemon(int nochdir, int noclose) dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) - close (fd); + (void) close(fd); } return (0); } diff --git a/lib/roken/detach.c b/lib/roken/detach.c new file mode 100644 index 000000000..e9fbafc39 --- /dev/null +++ b/lib/roken/detach.c @@ -0,0 +1,211 @@ +/*- + * Copyright (c) 2015 + * Cryptonector LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Cryptonector LLC may not be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#ifdef WIN32 +#include +#include +#else +#include +#endif +#include "roken.h" + +#ifdef WIN32 +#define dup2 _dup2 +#endif + +static int pipefds[2] = {-1, -1}; + +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +roken_detach_prep(int argc, char **argv, char *special_arg) +{ + pid_t child; + char buf[1]; + ssize_t bytes; + int status; + + pipefds[0] = -1; + pipefds[1] = -1; + +#ifdef WIN32 + if (_pipe(pipefds, 4, O_BINARY) == -1) + err(1, "failed to setup to detach daemon (_pipe failed)"); +#else + if (pipe(pipefds) == -1) + err(1, "failed to setup to detach daemon (pipe failed)"); +#endif + +#ifndef WIN32 + fflush(stdout); + child = fork(); +#else + { + intptr_t child_handle; + int write_side; + size_t i; + char *fildes; + char **new_argv; + + new_argv = calloc(argc + 2, sizeof(*new_argv)); + if (new_argv == NULL) + err(1, "Out of memory"); + + write_side = _dup(pipefds[1]); /* The new fd will be inherited */ + if (write_side == -1) + err(1, "Out of memory"); + + if (asprintf(&fildes, "%d", write_side) == -1 || + fildes == NULL) + err(1, "failed to setup to detach daemon (_dup failed)"); + + new_argv[0] = argv[0]; + new_argv[1] = special_arg; + new_argv[2] = fildes; + for (i = 1; argv[i] != NULL; i++) + new_argv[i + 1] = argv[i]; + new_argv[argc + 2] = NULL; + + _flushall(); + child_handle = spawnvp(_P_NOWAIT, argv[0], new_argv); + if (child_handle == -1) + child = (pid_t)-1; + else + child = GetProcessId((HANDLE)child_handle); + } +#endif + if (child == (pid_t)-1) + err(1, "failed to setup to fork daemon (fork failed)"); + +#ifndef WIN32 + if (child == 0) { + int fd; + + (void) close(pipefds[0]); + pipefds[0] = -1; + /* + * Keep stdout/stderr for now so output and errors prior to + * detach_finish() can be seen by the user. + */ + fd = open(_PATH_DEVNULL, O_RDWR, 0); + if (fd == -1) + err(1, "failed to open /dev/null"); + (void) dup2(fd, STDIN_FILENO); + if (fd > STDERR_FILENO) + (void) close(fd); + return; + } +#endif + + (void) close(pipefds[1]); + pipefds[1] = -1; + do { + bytes = read(pipefds[0], buf, sizeof(buf)); + } while (bytes == -1 && errno == EINTR); + if (bytes == -1) { + /* + * No need to wait for the process. We've killed it. If it + * doesn't want to exit, we'd have to wait potentially forever, + * but we want to indicate failure to the user as soon as + * possible. A wait with timeout would end the same way + * (attempting to kill the process). + */ + err(1, "failed to setup daemon child (read from child pipe)"); + } + if (bytes == 0) { + warnx("daemon child preparation failed, waiting for child"); + status = wait_for_process(child); + if (SE_IS_ERROR(status) || SE_PROCSTATUS(status) != 0) + errx(SE_PROCSTATUS(status), + "daemon child preparation failed (child exited)"); + } + _exit(0); +} + +#ifdef WIN32 +#ifdef dup2 +#undef dup2 +#endif +#define dup2 _dup2 +#endif + +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL +roken_detach_finish(const char *dir, int daemon_child_fd) +{ + char buf[1]; + ssize_t bytes; + int fd; + + if (pipefds[1] == -1 && daemon_child_fd != -1) + pipefds[1] = daemon_child_fd; + if (pipefds[0] != -1) + (void) close(pipefds[0]); + if (pipefds[1] == -1) + return; + +#ifdef HAVE_SETSID + if (setsid() == -1) + err(1, "failed to detach from tty"); +#endif + +#ifndef WIN32 + /* + * Hopefully we've written any pidfiles by now, if they had to be in + * the current directory... + * + * The daemons do re-open logs and so on, therefore this chdir() + * call needs to be optional for testing. + */ + if (dir != NULL && chdir(dir) == -1) + err(1, "failed to chdir to /"); +#endif + + buf[1] = 0; + do { + bytes = write(pipefds[1], buf, sizeof(buf)); + } while (bytes == -1 && errno == EINTR); + if (bytes == -1) + err(1, "failed to signal parent while detaching"); + (void) close(pipefds[1]); + if (bytes != sizeof(buf)) + errx(1, "failed to signal parent while detaching"); + + fd = open(_PATH_DEVNULL, O_RDWR, 0); + if (fd == -1) + err(1, "failed to open /dev/null"); + /* + * Maybe we should check that our output got written, if redirected + * to a file. File utils normally do this. + */ + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + if (fd > 2) + (void) close(fd); +} diff --git a/lib/roken/getarg.c b/lib/roken/getarg.c index d6a504868..76f3c808a 100644 --- a/lib/roken/getarg.c +++ b/lib/roken/getarg.c @@ -595,7 +595,7 @@ struct getargs args[] = { int main(int argc, char **argv) { int goptind = 0; - while(getarg(args, 5, argc, argv, &goptind)) + while (getarg(args, 5, argc, argv, &goptind)) printf("Bad arg: %s\n", argv[goptind]); printf("flag1 = %d\n", flag1); printf("flag2 = %d\n", flag2); diff --git a/lib/roken/roken-common.h b/lib/roken/roken-common.h index c6e734c80..8221c2a76 100644 --- a/lib/roken/roken-common.h +++ b/lib/roken/roken-common.h @@ -126,7 +126,11 @@ #define O_NOFOLLOW 0 #endif -#ifndef _WIN32 +#ifdef _WIN32 + +#define _PATH_DEVNULL "\\\\.\\NUL" + +#else #ifndef _PATH_DEV #define _PATH_DEV "/dev/" diff --git a/lib/roken/roken.h.in b/lib/roken/roken.h.in index 46449b248..14034dc12 100644 --- a/lib/roken/roken.h.in +++ b/lib/roken/roken.h.in @@ -810,6 +810,9 @@ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL roken_vconcat (char *, size_t, va_list); ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL roken_vmconcat (char **, size_t, va_list); +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL roken_detach_prep(int, char **, char *); +ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL roken_detach_finish(const char *, int); + ROKEN_LIB_FUNCTION ssize_t ROKEN_LIB_CALL net_write (rk_socket_t, const void *, size_t); diff --git a/lib/roken/test-detach.c b/lib/roken/test-detach.c new file mode 100644 index 000000000..09434d8ab --- /dev/null +++ b/lib/roken/test-detach.c @@ -0,0 +1,82 @@ +/*********************************************************************** + * Copyright (c) 2015, Cryptonector LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#ifdef getpid +#undef getpid +#endif +#define getpid _getpid +#else +#include +#endif +#include "roken.h" + +int main(int argc, char **argv) +{ + char *ends; + long n; + int fd = -1; + + if (argc > 1) { + if (argc != 3) + errx(1, "Usage: test-detach [--daemon-child fd]"); + fprintf(stderr, "Child started (argv[1] = %s, argv[2] = %s)!\n", argv[1], argv[2]); + errno = 0; + n = strtol(argv[2], &ends, 10); + fd = n; + if (errno != 0) + err(1, "Usage: test-detach [--daemon-child fd]"); + if (n < 0 || ends == NULL || *ends != '\0' || n != fd) + errx(1, "Usage: test-detach [--daemon-child fd]"); + } else { + fprintf(stderr, "Parent started as %ld\n", (long)getpid()); + roken_detach_prep(argc, argv, "--daemon-child"); + } + fprintf(stderr, "Now should be the child: %ld\n", (long)getpid()); + roken_detach_finish(NULL, fd); + /* + * These printfs will not appear: stderr will have been replaced + * with /dev/null. + */ + fprintf(stderr, "Now should be the child: %ld, wrote to parent\n", (long)getpid()); + sleep(5); + fprintf(stderr, "Daemon child done\n"); + return 0; +} diff --git a/lib/roken/version-script.map b/lib/roken/version-script.map index d396b3041..31c942cdc 100644 --- a/lib/roken/version-script.map +++ b/lib/roken/version-script.map @@ -162,6 +162,8 @@ HEIMDAL_ROKEN_1.0 { rk_warnerr; rk_xfree; roken_concat; + roken_detach_prep; + roken_detach_finish; roken_getaddrinfo_hostspec2; roken_getaddrinfo_hostspec; roken_gethostby_setup; diff --git a/lib/roken/write_pid.c b/lib/roken/write_pid.c index 6d83d87af..4b549f1b3 100644 --- a/lib/roken/write_pid.c +++ b/lib/roken/write_pid.c @@ -36,29 +36,42 @@ #include "roken.h" ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL -pid_file_write (const char *progname) +pid_file_write(const char *progname) { + const char *pidfile_dir = NULL; char *ret = NULL; FILE *fp; - if (asprintf (&ret, "%s%s.pid", _PATH_VARRUN, progname) < 0 || ret == NULL) + /* + * Maybe we could have a version of this function (and pidfile()) + * where we get a directory from the caller. That would allow us to + * have command-line options for the daemons for this. + * + * For now we use an environment variable. + */ + if (!issuid()) + pidfile_dir = getenv("HEIM_PIDFILE_DIR"); + if (pidfile_dir == NULL) + pidfile_dir = _PATH_VARRUN; + + if (asprintf(&ret, "%s%s.pid", pidfile_dir, progname) < 0 || ret == NULL) return NULL; - fp = fopen (ret, "w"); + fp = fopen(ret, "w"); if (fp == NULL) { - free (ret); + free(ret); return NULL; } - fprintf (fp, "%u", (unsigned)getpid()); - fclose (fp); + fprintf(fp, "%u", (unsigned)getpid()); + fclose(fp); return ret; } ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL -pid_file_delete (char **filename) +pid_file_delete(char **filename) { if (*filename != NULL) { - unlink (*filename); - free (*filename); + unlink(*filename); + free(*filename); *filename = NULL; } } @@ -69,16 +82,16 @@ static char *pidfile_path; static void pidfile_cleanup(void) { - if(pidfile_path != NULL) + if (pidfile_path != NULL) pid_file_delete(&pidfile_path); } ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL pidfile(const char *bname) { - if(pidfile_path != NULL) + if (pidfile_path != NULL) return; - if(bname == NULL) + if (bname == NULL) bname = getprogname(); pidfile_path = pid_file_write(bname); #if defined(HAVE_ATEXIT)