commit 95f0bdc0f1a4d74ef7fa12c3dc7e768d7cb3b7d0
parent 1f931b2c026025c601d33e720e5d494e44915960
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sun, 14 Jun 2020 14:37:43 +0200
Add some daemon features for deployment.
Diffstat:
| bmf-milter.c | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ | 
1 file changed, 110 insertions(+), 9 deletions(-)
diff --git a/bmf-milter.c b/bmf-milter.c
@@ -9,6 +9,8 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
@@ -115,7 +117,7 @@ mlfi_helo(SMFICTX *ctx, char *helohost)
 		return SMFIS_CONTINUE;
 	}
 
-	switch((pid = fork())) {
+	switch ((pid = fork())) {
 	case 0:
 		while(dup2(priv->execpipe[0], 0) < 0 && errno == EINTR);
 		close(priv->execpipe[1]);
@@ -330,26 +332,66 @@ struct smfiDesc smfilter =
 };
 
 void
+sighandler(int sig)
+{
+	int i;
+
+	switch (sig) {
+	case SIGCHLD:
+		while (waitpid(-1, NULL, WNOHANG) > 0);
+		break;
+	case SIGINT:
+	case SIGQUIT:
+	case SIGABRT:
+	case SIGTERM:
+	case SIGKILL:
+		smfi_stop();
+		break;
+	default:
+		break;
+	}
+}
+
+void
+initsignals(void)
+{
+	signal(SIGCHLD, sighandler);
+	signal(SIGHUP, sighandler);
+	signal(SIGINT, sighandler);
+	signal(SIGQUIT, sighandler);
+	signal(SIGABRT, sighandler);
+	signal(SIGTERM, sighandler);
+	signal(SIGKILL, sighandler);
+
+	/*
+	 * done by smfi_main():
+	 * signal(SIGPIPE, SIG_IGN);
+	 */
+}
+
+void
 usage(char *argv0)
 {
 	fprintf(stderr,
-		"Usage: %s [-h] [-d dbglvl] [-p listen] [-t timeout]\n",
+		"Usage: %s [-hd] [-v dbglvl] [-p listen] [-t timeout] "
+		"[-u user] [-g group]\n",
 		argv0);
 }
 
 int
 main(int argc, char *argv[])
 {
-	char *argv0, *port;
-	int timeout;
-
-	port = "inet:9957";
-	timeout = -1;
+	char *argv0, *user = NULL, *group = NULL, *port = "inet:9957";
+	int timeout = -1, dofork = 1;
+	struct passwd *us = NULL;
+	struct group *gr = NULL;
 
 	ARGBEGIN(argv0) {
 	case 'd':
-		smfi_setdbg(atoi(EARGF(argv0)));
-		dodebug = 1;
+		dofork = 0;
+		break;
+	case 'g':
+		group = EARGF(usage(argv0));
 		break;
 	case 'p':
 		port = EARGF(usage(argv0));
@@ -357,11 +399,70 @@ main(int argc, char *argv[])
 	case 't':
 		timeout = atoi(EARGF(usage(argv0)));
 		break;
+	case 'u':
+		user = EARGF(usage(argv0));
+		break;
+	case 'v':
+		smfi_setdbg(atoi(EARGF(argv0)));
+		dodebug = 1;
+		break;
 	default:
 		usage(argv0);
 		return 1;
 	} ARGEND;
 
+	if (group != NULL) {
+		errno = 0;
+		if ((gr = getgrnam(group)) == NULL) {
+			if (errno == 0) {
+				fprintf(stderr, "no such group '%s'\n",
+						group);
+			} else {
+				perror("getgrnam");
+			}
+			return 1;
+		}
+	}
+
+	if (user != NULL) {
+		errno = 0;
+		if ((us = getpwnam(user)) == NULL) {
+			if (errno == 0) {
+				fprintf(stderr, "no such user '%s'\n",
+						user);
+			} else {
+				perror("getpwnam");
+			}
+			return 1;
+		}
+	}
+
+	if (dofork) {
+		switch (fork()) {
+		case -1:
+			perror("fork");
+			return 1;
+		case 0:
+			break;
+		default:
+			return 0;
+		}
+	}
+
+	if (gr != NULL) {
+		if (setgroups(1, &gr->gr_gid) != 0 || setgid(gr->gr_gid) != 0)
+			return -1;
+	}
+	if (us != NULL) {
+		if (gr == NULL) {
+			if (setgroups(1, &us->pw_gid) != 0 ||
+			    setgid(us->pw_gid) != 0)
+				return -1;
+		}
+		if (setuid(us->pw_uid) != 0)
+			return -1;
+	}
+
 	if (smfi_setconn(port) == MI_FAILURE) {
 		perror("smfi_setconn");
 		return 1;