Download raw body.
split daemon(3) functionality for better debugability
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 <martijn@openbsd.org>
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <martijn@openbsd.org>
+ *
+ * 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 <radius.h>
+#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 <grp.h>
#include <imsg.h>
#include <login_cap.h>
+#include <paths.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
@@ -37,6 +38,7 @@
#include <syslog.h>
#include <unistd.h>
+#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 <assert.h>
#include <err.h>
#include <event.h>
+#include <fcntl.h>
+#include <paths.h>
#include <radius.h>
#include <stdbool.h>
#include <stddef.h>
@@ -36,6 +38,7 @@
#include <time.h>
#include <unistd.h>
+#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 <imsg.h>
#include <limits.h>
#include <md5.h>
+#include <paths.h>
#include <radius.h>
#include <stddef.h>
#include <stdint.h>
@@ -37,6 +38,7 @@
#include <unistd.h>
#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 <errno.h>
#include <event.h>
#include <fcntl.h>
+#include <paths.h>
#include <pwd.h>
#include <radius.h>
#include <stdbool.h>
@@ -42,6 +43,7 @@
#include <unistd.h>
#include <imsg.h>
+#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 <errno.h>
#include <event.h>
#include <fcntl.h>
+#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +35,7 @@
#include <radius.h>
+#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 <err.h>
#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
#include <radius.h>
#include <stdbool.h>
#include <stdint.h>
@@ -31,6 +33,7 @@
#include <syslog.h>
#include <unistd.h>
+#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,
split daemon(3) functionality for better debugability