From: Martijn van Duren Subject: split daemon(3) functionality for better debugability To: tech@openbsd.org Date: Fri, 20 Feb 2026 18:49:25 +0100 Hello tech@, When it comes to privsep daemons one of the things that always felled a little off to me was the calling of daemon(3) before the setup phase was complete. For most daemons this is not a big problem, but specifically smtpd has bitten me a couple of times when I messed up one of my (custom) filters, resulting in rcttl start smtpd gives me an "(ok)", but right after it crashes. Another daemon which suffers greatly from this is radiusd(8), which calls daemon(3) before parsing the config file. I've been discussing with yasuoka@ for some time now and this is what we came up with. For brevity let's define 4 levels of processes: A) The process spawning the deamon (e.g. shell) B) The original daemon process, with A as its parent C) The detached daemon process, with B as its parent D) Any child as an (in)direct descendant from C forked before daemon_detach() daemon_spawn() is supposed to replace daemon(3) inside B. The biggest difference is that daemon_spawn() doesn't kill itself, but instead creates a socketpair(2), generate a random value, and leave stderr open. In case fork(2) fails daemon_spawn() returns -1 with errno set. Everything after a successful fork(2) can only be returned from C. If a problem occurs inside B the a message is printed to stderr, followed a SIGTERM to C, a waitpid(2), and an _exit(1). If C exits before fully detaching the exit code is picked up and B exits the with the same exit code. If something else than the random value is written back to the socketpair, that implies that the fd is leaked to somewhere it's not supposed to be and C gets a SIGTERM, before B exits with an exit value of 1. After daemon_spawn() has created C initialization can continue as normal, up to the point where normal operation commence. Most often this is right after log_init switches to syslog, or just before event_dispatch(). daemon_detach() inside C writes out the random value to inform B that it can perform its exit(0), followed by doing a dup2(nullfd, STDERR_FILENO) if applicable, to make sure that the tty isn't being kept open. D also needs to call daemon_detach() to make sure STDERR_FILENO is replaced with nullfd, these children don't interact with B, which is guaranteed via FD_CLOEXEC | FD_CLOFORK on the socketpair. This code makes the following assumptions: - STDERR_FILENO is available for debugging. - SIGTERM isn't being masked out by C. - In case C needs to be terminated, D kills themselves by virtue of losing connection with C. AFAIK this holds true for every of our daemons. But this caveat also holds true for every other call to err(3), or fatal(). The diff below contains an implementation for radiusd, as OK by yasuoka@. But since I would like to see this at least in smtpd(8) as well (and probably others), I'm asking for wider opinions about the daemon.c bits. This work is heavily inspired by previous work of kn@ on daemonfd(). Both kn@'s daemonfd(), and daemon(3) should be able to be build upon daemon_{spawn,detach}(). martijn@ diff refs/heads/master refs/heads/radiusd/daemon_spawn commit - 3d36af1f1ebb63f29f1bdcaa411f391f42d04f6c commit + 5057bcc86fe6824094c22470f0902f9742d68ae8 blob - /dev/null blob + 1539df99dfa041be5fd5707bffb4568b5ef7963b (mode 644) --- /dev/null +++ usr.sbin/radiusd/daemon.c @@ -0,0 +1,167 @@ +/* $OpenBSD$ */ +/*- + * + * Copyright (c) 2025 Martijn van Duren + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "daemon.h" + +static int confirm; +static uint32_t magicval; +static pid_t parentpid = 0; + +int +daemon_spawn(int chdirfd, int nullfd) +{ + pid_t pid; + int sp[2]; + int status; + uint32_t val[2]; + ssize_t rret; + int serrno; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == -1) + return -1; + magicval = arc4random(); + + switch (pid = fork()) { + case -1: + serrno = errno; + close(sp[0]); + close(sp[1]); + errno = serrno; + return -1; + case 0: + break; + default: + /* Doesn't return */ + close(sp[0]); + while (1) { + rret = read(sp[1], val, sizeof(val)); + switch (rret) { + case -1: + if (errno == EINTR) + continue; + fprintf(stderr, + "Can't determine daemon process state: " + "%s\n", strerror(errno)); + fflush(stderr); + kill(pid, SIGTERM); + (void)waitpid(pid, &status, 0); + _exit(1); + case 0: + /* Make sure it's really gone */ + kill(pid, SIGTERM); + + if (waitpid(pid, &status, 0) <= 0 || + WEXITSTATUS(status) == 0) + _exit(1); + _exit(WEXITSTATUS(status)); + case 4: + if (val[0] != magicval) { + fprintf(stderr, "Unexpected verify " + "value from daemon process\n"); + fflush(stderr); + kill(pid, SIGTERM); + (void)waitpid(pid, &status, 0); + _exit(1); + } + _exit(0); + default: + fprintf(stderr, "Unexpected verify value " + "length from daemon process\n"); + fflush(stderr); + kill(pid, SIGTERM); + (void)waitpid(pid, &status, 0); + _exit(1); + } + } + } + + parentpid = getpid(); + + close(sp[1]); + confirm = sp[0]; + if (fcntl(confirm, F_SETFD, FD_CLOEXEC | FD_CLOFORK) == -1) { + return -1; + } + + if (setsid() == -1) + return -1; + + if (chdirfd != -1) + (void)fchdir(chdirfd); + + if (nullfd != -1) { + (void)dup2(nullfd, STDIN_FILENO); + (void)dup2(nullfd, STDOUT_FILENO); + } + return 0; +} + +void +daemon_detach(int nullfd) +{ + ssize_t n; + + /* + * It's either the parent pid in case of fork, * or 0 in case of exec. + * Both shouldn't match in helper processes. + */ + if (parentpid == getpid()) { + while ((n = write(confirm, &magicval, sizeof(magicval))) == -1) { + if (errno != EINTR) + break; + } + if (n != sizeof(magicval)) { + fprintf(stderr, + "Failed to write magic value to attached process: %s", + n == -1 ? strerror(errno) : "invalid length written"); + fflush(stderr); + _exit(1); + } + } + + if (nullfd != -1) + (void)dup2(nullfd, STDERR_FILENO); +} blob - /dev/null blob + 1af159c45e6c34af2e5b5c5e57d6d6be3e5e89b2 (mode 644) --- /dev/null +++ usr.sbin/radiusd/daemon.h @@ -0,0 +1,18 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2025 Martijn van Duren + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +int daemon_spawn(int, int); +void daemon_detach(int); blob - d331d85b74421c7e07e461eef4c6456b71660328 blob + fd560c5317fc0fcb3100c8d661538fa37fdffe85 --- usr.sbin/radiusd/radiusd/Makefile +++ usr.sbin/radiusd/radiusd/Makefile @@ -4,7 +4,7 @@ PROG= radiusd BINDIR= /usr/sbin MAN= radiusd.8 radiusd.conf.5 SRCS= radiusd.c radius_subr.c parse.y log.c util.c imsg_subr.c -SRCS+= control.c +SRCS+= control.c daemon.c LDADD+= -lradius -lcrypto -levent -lutil DPADD= ${LIBRADIUS} ${LIBCRYPTO} ${LIBEVENT} ${LIBUTIL} blob - 94a1b260a61e704c10378c452c2fb584bde57deb blob + 496d317fe6458e7dfe7f24460d00d8052e05e699 --- usr.sbin/radiusd/radiusd.c +++ usr.sbin/radiusd/radiusd.c @@ -44,6 +44,7 @@ #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_local.h" #include "radius_subr.h" @@ -100,7 +101,6 @@ static void radiusd_module_account_request(struct ra struct radius_query *); static int imsg_compose_radius_packet(struct imsgbuf *, uint32_t, u_int, RADIUS_PACKET *); -static void close_stdio(void); static u_int radius_query_id_seq = 0; int debug = 0; @@ -121,6 +121,7 @@ main(int argc, char *argv[]) extern char *__progname; const char *conffile = CONFFILE; int ch, error; + int nullfd; struct radiusd *radiusd; bool noaction = false; struct passwd *pw; @@ -156,8 +157,12 @@ main(int argc, char *argv[]) TAILQ_INIT(&radiusd->listen); TAILQ_INIT(&radiusd->query); - if (!noaction && debug == 0) - daemon(0, 1); /* pend closing stdio files */ + if (!noaction && debug == 0) { + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + if (daemon_spawn(-1, nullfd) == -1) + err(1, "daemon_spawn"); + } if (parse_config(conffile, radiusd) != 0) errx(EXIT_FAILURE, "config error"); @@ -167,9 +172,6 @@ main(int argc, char *argv[]) exit(EXIT_SUCCESS); } - if (debug == 0) - close_stdio(); /* close stdio files now */ - if (control_init(RADIUSD_SOCK) == -1) exit(EXIT_FAILURE); @@ -205,6 +207,11 @@ main(int argc, char *argv[]) if (pledge("stdio inet", NULL) == -1) err(EXIT_FAILURE, "pledge"); + if (debug == 0) { + daemon_detach(nullfd); + close(nullfd); + } + event_loop(0); if (radiusd->error != 0) @@ -1905,20 +1912,6 @@ imsg_compose_radius_packet(struct imsgbuf *ibuf, uint3 return (0); } -static void -close_stdio(void) -{ - int fd; - - if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - close(fd); - } -} - /*********************************************************************** * imsg_event ***********************************************************************/ blob - 41a87b38c983f9da14acc153e5c31f058f0455c6 blob + 9a95f5ecd0fd33549bc31f5bc45c7fe21623a9f0 --- usr.sbin/radiusd/radiusd_bsdauth/Makefile +++ usr.sbin/radiusd/radiusd_bsdauth/Makefile @@ -2,7 +2,7 @@ PROG= radiusd_bsdauth BINDIR= /usr/libexec/radiusd -SRCS= radiusd_bsdauth.c radiusd_module.c imsg_subr.c +SRCS= radiusd_bsdauth.c radiusd_module.c imsg_subr.c daemon.c LDADD+= -lradius -lcrypto -lutil DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} MAN= radiusd_bsdauth.8 blob - 68135b9b7a274f778345c3d9f7699061bef927fc blob + 62c29e88c34d495559181f6be7a35aa0c1b53d9b --- usr.sbin/radiusd/radiusd_bsdauth.c +++ usr.sbin/radiusd/radiusd_bsdauth.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_module.h" @@ -50,6 +52,7 @@ struct module_bsdauth { enum { IMSG_BSDAUTH_OK = 1000, IMSG_BSDAUTH_NG, + IMSG_BSDAUTH_DEBUG, IMSG_BSDAUTH_USERCHECK, IMSG_BSDAUTH_GROUPCHECK }; @@ -64,6 +67,7 @@ struct auth_groupcheck_args { __dead static void module_bsdauth_main(void); +static void module_bsdauth_start(void *); static void module_bsdauth_config_set(void *, const char *, int, char * const *); static void module_bsdauth_userpass(void *, u_int, const char *, @@ -73,9 +77,11 @@ __dead static void fatal(const char *); static struct module_handlers module_bsdauth_handlers = { + .start = module_bsdauth_start, .userpass = module_bsdauth_userpass, .config_set = module_bsdauth_config_set }; +static int debug = 0, nullfd = -1; int main(int argc, char *argv[]) @@ -88,6 +94,9 @@ main(int argc, char *argv[]) pid_t pid; char *saved_argv0; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + while ((ch = getopt(argc, argv, "M")) != -1) switch (ch) { case 'M': @@ -129,6 +138,16 @@ main(int argc, char *argv[]) break; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { + case IMSG_BSDAUTH_DEBUG: + { + if (datalen != sizeof(debug)) + err(EXIT_FAILURE, "Invalid message"); + debug = *(int *)imsg.data; + if (!debug) + daemon_detach(nullfd); + close(nullfd); + break; + } case IMSG_BSDAUTH_USERCHECK: { char *user, *pass; @@ -281,6 +300,20 @@ module_bsdauth_main(void) } static void +module_bsdauth_start(void *ctx) +{ + struct module_bsdauth *module = ctx; + + imsg_compose(&module->ibuf, IMSG_BSDAUTH_DEBUG, 0, 0, -1, + &debug, sizeof(debug)); + imsgbuf_flush(&module->ibuf); + module_send_message(module->base, IMSG_OK, NULL); + if (!debug) + daemon_detach(nullfd); + close(nullfd); +} + +static void module_bsdauth_config_set(void *ctx, const char *name, int argc, char * const * argv) { @@ -309,6 +342,9 @@ module_bsdauth_config_set(void *ctx, const char *name, groups[i] = NULL; module->okgroups = groups; module_send_message(module->base, IMSG_OK, NULL); + } else if (strcmp(name, "_debug") == 0) { + debug = 1; + module_send_message(module->base, IMSG_OK, NULL); } else if (strncmp(name, "_", 1) == 0) /* ignore all internal messages */ module_send_message(module->base, IMSG_OK, NULL); blob - 701564f1119155c31d4229352a9ab4ec849b3ff6 blob + 003b2bae66b6449130639e094ecbf5fed93a013c --- usr.sbin/radiusd/radiusd_eap2mschap/Makefile +++ usr.sbin/radiusd/radiusd_eap2mschap/Makefile @@ -3,6 +3,7 @@ PROG= radiusd_eap2mschap BINDIR= /usr/libexec/radiusd SRCS= radiusd_eap2mschap.c radiusd_module.c radius_subr.c log.c +SRCS+= daemon.c CFLAGS+= -DUSE_LIBEVENT LDADD+= -lradius -lutil -lcrypto -levent DPADD+= ${LIBRADIUS} ${LIBUTIL} ${LIBCRYPTO} ${LIBEVENT} blob - 53b6ccf3e6a58fee51a6f80072465ddd2e2d3715 blob + b5941905b5f372cfb7c1b4c3d8aacf61b7554af8 --- usr.sbin/radiusd/radiusd_eap2mschap.c +++ usr.sbin/radiusd/radiusd_eap2mschap.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,6 +38,7 @@ #include #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_module.h" #include "radius_subr.h" @@ -45,6 +48,8 @@ #include "eap2mschap_local.h" +static int debug = 0, nullfd = -1; + int main(int argc, char *argv[]) { @@ -57,6 +62,9 @@ main(int argc, char *argv[]) }; struct eap2mschap eap2mschap; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + eap2mschap_init(&eap2mschap); if ((eap2mschap.base = module_create(STDIN_FILENO, &eap2mschap, &handlers)) == NULL) @@ -73,6 +81,7 @@ main(int argc, char *argv[]) err(1, "pledge"); module_start(eap2mschap.base); + event_loop(0); module_destroy(eap2mschap.base); @@ -102,6 +111,9 @@ eap2mschap_start(void *ctx) module_send_message(self->base, IMSG_OK, NULL); evtimer_set(&self->ev_eapt, eap2mschap_on_eapt, self); + if (!debug) + daemon_detach(nullfd); + close(nullfd); } void @@ -120,9 +132,10 @@ eap2mschap_config_set(void *ctx, const char *name, int "chap-name is too long"); return; } - } else if (strcmp(name, "_debug") == 0) + } else if (strcmp(name, "_debug") == 0) { + debug = 1; log_init(1); - else if (strncmp(name, "_", 1) == 0) + } else if (strncmp(name, "_", 1) == 0) /* ignore all internal messages */; else { module_send_message(self->base, IMSG_NG, blob - 7c15471c29b4ed7e643dab5a13d3f56c10dfe99d blob + 78e94e571085ce948d8373a7b807f099e94080ed --- usr.sbin/radiusd/radiusd_file/Makefile +++ usr.sbin/radiusd/radiusd_file/Makefile @@ -3,6 +3,7 @@ PROG= radiusd_file BINDIR= /usr/libexec/radiusd SRCS= radiusd_file.c radiusd_module.c imsg_subr.c log.c chap_ms.c +SRCS+= daemon.c #SRCS+= radius_subr.c LDADD+= -lradius -lcrypto -lutil DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} blob - c2ec82a6c9b475d2189d03946897bf605c05111a blob + 2b2874e799dfd3b1af03e25fdb2e479a0d4393a4 --- usr.sbin/radiusd/radiusd_file.c +++ usr.sbin/radiusd/radiusd_file.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include "chap_ms.h" +#include "daemon.h" #include "imsg_subr.h" #include "log.h" #include "radiusd.h" @@ -63,6 +65,7 @@ struct module_file_userinfo { enum { IMSG_RADIUSD_FILE_OK = 1000, IMSG_RADIUSD_FILE_NG, + IMSG_RADIUSD_FILE_DEBUG, IMSG_RADIUSD_FILE_PARAMS, IMSG_RADIUSD_FILE_USERINFO }; @@ -90,6 +93,7 @@ static struct module_handlers module_file_handlers = { .config_set = module_file_config_set, .start = module_file_start }; +static int nullfd = -1; int main(int argc, char *argv[]) @@ -104,6 +108,9 @@ main(int argc, char *argv[]) struct module_file_params *paramsp, params; char pathdb[PATH_MAX]; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + while ((ch = getopt(argc, argv, "M")) != -1) switch (ch) { case 'M': @@ -132,9 +139,10 @@ main(int argc, char *argv[]) err(EXIT_FAILURE, "imsgbuf_init"); /* Receive parameters from the main process. */ - if (imsg_sync_read(&ibuf, 2000) <= 0 || - (n = imsg_get(&ibuf, &imsg)) <= 0) - exit(EXIT_FAILURE); + if (imsg_sync_read(&ibuf, 2000) <= 0) + fatal("imsg_sync_read"); + if ((n = imsg_get(&ibuf, &imsg)) <= 0) + fatal("imsg_get"); if (imsg.hdr.type != IMSG_RADIUSD_FILE_PARAMS) err(EXIT_FAILURE, "Receieved unknown message type %d", imsg.hdr.type); @@ -190,9 +198,21 @@ parent_dispatch_main(struct module_file_params *params char *buf, *db[2], *str; int ret; struct module_file_userinfo *ent; + int debug; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; switch (imsg->hdr.type) { + case IMSG_RADIUSD_FILE_DEBUG: + if (datalen != sizeof(debug)) { + log_warn("%s: received " + "IMSG_RADIUSD_FILE_DEBUG is wrong", __func__); + goto on_error; + } + debug = *(int *)imsg->data; + if (!debug) + daemon_detach(nullfd); + close(nullfd); + break; case IMSG_RADIUSD_FILE_USERINFO: if (datalen == 0 || *((char *)imsg->data + datalen - 1) != '\0') { @@ -250,6 +270,7 @@ module_file_main(void) if (pledge("stdio", NULL) == -1) err(EXIT_FAILURE, "pledge"); + while (module_run(module_file.base) == 0) ; @@ -336,6 +357,12 @@ module_file_start(void *ctx) imsgbuf_flush(&module->ibuf); module_send_message(module->base, IMSG_OK, NULL); + imsg_compose(&module->ibuf, IMSG_RADIUSD_FILE_DEBUG, 0, 0, -1, + &module->params.debug, sizeof(module->params.debug)); + imsgbuf_flush(&module->ibuf); + if (!module->params.debug) + daemon_detach(nullfd); + close(nullfd); } void blob - 81d90b91534ddaee2cb9ce3850701be6767aef78 blob + cb35d7e2aa0efc406ddb08a693167b6f9074f606 --- usr.sbin/radiusd/radiusd_ipcp/Makefile +++ usr.sbin/radiusd/radiusd_ipcp/Makefile @@ -2,7 +2,7 @@ PROG= radiusd_ipcp BINDIR= /usr/libexec/radiusd -SRCS= radiusd_ipcp.c radiusd_module.c log.c +SRCS= radiusd_ipcp.c radiusd_module.c log.c daemon.c CFLAGS+= -DUSE_LIBEVENT LDADD+= -lradius -lcrypto -lutil -levent DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} ${LIBEVENT} blob - 3c8715b0f84c8bbbc1406db58e5c78ed701278df blob + db6d8f141d27af435860d01e9d556b8938262f98 --- usr.sbin/radiusd/radiusd_ipcp.c +++ usr.sbin/radiusd/radiusd_ipcp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_module.h" #include "radiusd_ipcp.h" @@ -224,6 +226,8 @@ RB_PROTOTYPE_STATIC(assigned_ipv4_tree, assigned_ipv4, assigned_ipv4_compar); RB_PROTOTYPE_STATIC(user_tree, user, tree, user_compar); +static int debug = 0, nullfd = -1; + int main(int argc, char *argv[]) { @@ -237,6 +241,9 @@ main(int argc, char *argv[]) .dispatch_control = ipcp_dispatch_control }; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + ipcp_init(&module_ipcp); if ((module_ipcp.base = module_create(STDIN_FILENO, &module_ipcp, @@ -258,6 +265,7 @@ main(int argc, char *argv[]) event_init(); module_start(module_ipcp.base); + event_loop(0); ipcp_fini(&module_ipcp); @@ -330,6 +338,10 @@ ipcp_start(void *ctx) } module_send_message(self->base, IMSG_OK, NULL); + + if (!debug) + daemon_detach(nullfd); + close(nullfd); } void @@ -550,8 +562,10 @@ ipcp_config_set(void *ctx, const char *name, int argc, TAILQ_INIT(&dae0->reqs); TAILQ_INSERT_TAIL(&module->daes, dae0, next); dae0->ipcp = module; - } else if (strcmp(name, "_debug") == 0) + } else if (strcmp(name, "_debug") == 0) { log_init(1); + debug = 1; + } else if (strncmp(name, "_", 1) == 0) /* ignore */; else { blob - d77c2c35474ce4c85a750e1f29b049c70fabc974 blob + 296c85c1be044ee4125f532cd48a8454a1b56356 --- usr.sbin/radiusd/radiusd_radius/Makefile +++ usr.sbin/radiusd/radiusd_radius/Makefile @@ -3,6 +3,7 @@ PROG= radiusd_radius BINDIR= /usr/libexec/radiusd SRCS= radiusd_radius.c radiusd_module.c util.c imsg_subr.c log.c +SRCS+= daemon.c CFLAGS+= -DUSE_LIBEVENT LDADD+= -lradius -lcrypto -lutil -levent DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} ${LIBEVENT} blob - 52619c4557788054f808c656b3c654de69fb339e blob + d5c964c9e9ebf43bbe988084c0145db754057e51 --- usr.sbin/radiusd/radiusd_radius.c +++ usr.sbin/radiusd/radiusd_radius.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_module.h" #include "util.h" @@ -110,6 +112,8 @@ static struct module_handlers module_radius_handlers = .access_request = module_radius_access_request }; +static int debug = 0, nullfd = -1; + #ifndef nitems #define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) #endif @@ -119,6 +123,9 @@ main(int argc, char *argv[]) { static struct module_radius module_radius; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + module_radius_init(&module_radius); openlog(NULL, LOG_PID, LOG_DAEMON); @@ -136,6 +143,7 @@ main(int argc, char *argv[]) err(EXIT_FAILURE, "pledge"); module_start(module_radius.base); + event_loop(0); module_destroy(module_radius.base); @@ -220,9 +228,10 @@ module_radius_config_set(void *ctx, const char *paramn (u_long) sizeof(module->secret) - 1); return; } - } else if (strcmp(paramname, "_debug") == 0) + } else if (strcmp(paramname, "_debug") == 0) { + debug = 1; log_init(1); - else if (strncmp(paramname, "_", 1) == 0) + } else if (strncmp(paramname, "_", 1) == 0) /* nothing */; /* ignore all internal messages */ else { module_send_message(module->base, IMSG_NG, @@ -266,6 +275,10 @@ module_radius_start(void *ctx) module_send_message(module->base, IMSG_OK, NULL); module_notify_secret(module->base, module->secret); + + if (!debug) + daemon_detach(nullfd); + close(nullfd); } static void blob - e720296fe406f742ebf7bbb9de9eb0994854e9ec blob + 3d46d6abee24b1f23f4d9fd5918ac73f4af27609 --- usr.sbin/radiusd/radiusd_standard/Makefile +++ usr.sbin/radiusd/radiusd_standard/Makefile @@ -2,7 +2,7 @@ PROG= radiusd_standard BINDIR= /usr/libexec/radiusd -SRCS= radiusd_standard.c radiusd_module.c +SRCS= radiusd_standard.c radiusd_module.c daemon.c LDADD= -lradius -lcrypto -lutil DPADD= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} MAN= radiusd_standard.8 blob - b925ec4c152117b11c9b2a276128068b8164d864 blob + 713f1e3eaf8827298a152f7e08cdfb027e5428f8 --- usr.sbin/radiusd/radiusd_standard.c +++ usr.sbin/radiusd/radiusd_standard.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -31,6 +33,7 @@ #include #include +#include "daemon.h" #include "radiusd.h" #include "radiusd_module.h" @@ -58,6 +61,7 @@ struct radius_const_str { static void radius_const_print(FILE *, RADIUS_PACKET *, uint8_t, const char *, struct radius_const_str *); +static void module_standard_start(void *); static void module_standard_config_set(void *, const char *, int, char * const *); static void module_standard_reqdeco(void *, u_int, const u_char *, size_t); @@ -79,12 +83,14 @@ static struct radius_const_str service_type_consts[], framed_protocol_consts[], acct_status_type_consts[], acct_authentic_consts[], terminate_cause_consts[], tunnel_medium_type_consts[]; +static int debug = 0, nullfd = -1; int main(int argc, char *argv[]) { struct module_standard module_standard; struct module_handlers handlers = { + .start = module_standard_start, .config_set = module_standard_config_set, .request_decoration = module_standard_reqdeco, .response_decoration = module_standard_resdeco, @@ -92,6 +98,9 @@ main(int argc, char *argv[]) }; struct attr *attr; + if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) + err(1, "open(%s)", _PATH_DEVNULL); + memset(&module_standard, 0, sizeof(module_standard)); TAILQ_INIT(&module_standard.remove_reqattrs); TAILQ_INIT(&module_standard.remove_resattrs); @@ -125,6 +134,17 @@ main(int argc, char *argv[]) } static void +module_standard_start(void *ctx) +{ + struct module_standard *module = ctx; + + module_send_message(module->base, IMSG_OK, NULL); + if (!debug) + daemon_detach(nullfd); + close(nullfd); +} + +static void module_standard_config_set(void *ctx, const char *name, int argc, char * const * argv) { @@ -198,7 +218,9 @@ module_standard_config_set(void *ctx, const char *name else SYNTAX_ASSERT(attr == NULL, "wrong number for `remove-response-attribute`"); - } else if (strncmp(name, "_", 1) == 0) + } else if (strcmp(name, "_debug") == 0) + debug = 1; + else if (strncmp(name, "_", 1) == 0) /* nothing */; /* ignore all internal messages */ else { module_send_message(module->base, IMSG_NG,