2 50794f47 2023-04-04 op * This file is in the public domain.
5 50794f47 2023-04-04 op #include <sys/socket.h>
6 50794f47 2023-04-04 op #include <sys/stat.h>
7 50794f47 2023-04-04 op #include <sys/tree.h>
8 50794f47 2023-04-04 op #include <sys/types.h>
9 50794f47 2023-04-04 op #include <sys/un.h>
10 50794f47 2023-04-04 op #include <sys/wait.h>
12 50794f47 2023-04-04 op #include <err.h>
13 50794f47 2023-04-04 op #include <errno.h>
14 50794f47 2023-04-04 op #include <event.h>
15 50794f47 2023-04-04 op #include <fcntl.h>
16 50794f47 2023-04-04 op #include <limits.h>
17 50794f47 2023-04-04 op #include <pwd.h>
18 50794f47 2023-04-04 op #include <signal.h>
19 50794f47 2023-04-04 op #include <stdarg.h>
20 50794f47 2023-04-04 op #include <stdio.h>
21 50794f47 2023-04-04 op #include <stdlib.h>
22 50794f47 2023-04-04 op #include <string.h>
23 50794f47 2023-04-04 op #include <syslog.h>
24 50794f47 2023-04-04 op #include <unistd.h>
26 50794f47 2023-04-04 op #include "msearchd.h"
28 50794f47 2023-04-04 op #ifndef MSEARCHD_DB
29 50794f47 2023-04-04 op #define MSEARCHD_DB "/msearchd/mails.sqlite3"
32 50794f47 2023-04-04 op #ifndef MSEARCHD_SOCK
33 50794f47 2023-04-04 op #define MSEARCHD_SOCK "/run/msearchd.sock"
36 50794f47 2023-04-04 op #ifndef MSEARCHD_USER
37 50794f47 2023-04-04 op #define MSEARCHD_USER "www"
40 50794f47 2023-04-04 op #define MAX_CHILDREN 32
44 50794f47 2023-04-04 op int children = 3;
45 50794f47 2023-04-04 op pid_t pids[MAX_CHILDREN];
47 50794f47 2023-04-04 op __dead void srch_syslog_fatal(int, const char *, ...);
48 50794f47 2023-04-04 op __dead void srch_syslog_fatalx(int, const char *, ...);
49 50794f47 2023-04-04 op void srch_syslog_warn(const char *, ...);
50 50794f47 2023-04-04 op void srch_syslog_warnx(const char *, ...);
51 50794f47 2023-04-04 op void srch_syslog_info(const char *, ...);
52 50794f47 2023-04-04 op void srch_syslog_debug(const char *, ...);
54 50794f47 2023-04-04 op const struct logger syslogger = {
55 50794f47 2023-04-04 op .fatal = &srch_syslog_fatal,
56 50794f47 2023-04-04 op .fatalx = &srch_syslog_fatalx,
57 50794f47 2023-04-04 op .warn = &srch_syslog_warn,
58 50794f47 2023-04-04 op .warnx = &srch_syslog_warnx,
59 50794f47 2023-04-04 op .info = &srch_syslog_info,
60 50794f47 2023-04-04 op .debug = &srch_syslog_debug,
63 50794f47 2023-04-04 op const struct logger dbglogger = {
64 50794f47 2023-04-04 op .fatal = &err,
65 50794f47 2023-04-04 op .fatalx = &errx,
66 50794f47 2023-04-04 op .warn = &warn,
67 50794f47 2023-04-04 op .warnx = &warnx,
68 50794f47 2023-04-04 op .info = &warnx,
69 50794f47 2023-04-04 op .debug = &warnx,
72 50794f47 2023-04-04 op const struct logger *logger = &dbglogger;
75 50794f47 2023-04-04 op handle_sigchld(int sig)
77 50794f47 2023-04-04 op static volatile sig_atomic_t got_sigchld;
78 50794f47 2023-04-04 op int i, save_errno;
80 50794f47 2023-04-04 op if (got_sigchld)
82 50794f47 2023-04-04 op got_sigchld = -1;
84 50794f47 2023-04-04 op save_errno = errno;
85 50794f47 2023-04-04 op for (i = 0; i < children; ++i)
86 50794f47 2023-04-04 op (void)kill(pids[i], SIGTERM);
87 50794f47 2023-04-04 op errno = save_errno;
91 50794f47 2023-04-04 op bind_socket(const char *path, struct passwd *pw)
93 50794f47 2023-04-04 op struct sockaddr_un sun;
94 50794f47 2023-04-04 op int fd, old_umask;
96 50794f47 2023-04-04 op if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0)) == -1) {
97 50794f47 2023-04-04 op log_warn("%s: socket", __func__);
101 50794f47 2023-04-04 op memset(&sun, 0, sizeof(sun));
102 50794f47 2023-04-04 op sun.sun_family = AF_UNIX;
104 50794f47 2023-04-04 op if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
105 50794f47 2023-04-04 op sizeof(sun.sun_path)) {
106 50794f47 2023-04-04 op log_warnx("%s: path too long: %s", __func__, path);
111 50794f47 2023-04-04 op if (unlink(path) == -1 && errno != ENOENT) {
112 50794f47 2023-04-04 op log_warn("%s: unlink %s", __func__, path);
117 50794f47 2023-04-04 op old_umask = umask(0117);
118 50794f47 2023-04-04 op if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
119 50794f47 2023-04-04 op log_warn("%s: bind: %s (%d)", __func__, path, geteuid());
121 50794f47 2023-04-04 op umask(old_umask);
124 50794f47 2023-04-04 op umask(old_umask);
126 50794f47 2023-04-04 op if (chmod(path, 0660) == -1) {
127 50794f47 2023-04-04 op log_warn("%s: chmod 0660 %s", __func__, path);
129 50794f47 2023-04-04 op (void)unlink(path);
133 50794f47 2023-04-04 op if (chown(path, pw->pw_uid, pw->pw_gid) == -1) {
134 50794f47 2023-04-04 op log_warn("%s: chown %s %s", __func__, pw->pw_name, path);
136 50794f47 2023-04-04 op (void)unlink(path);
140 50794f47 2023-04-04 op if (listen(fd, 5) == -1) {
141 50794f47 2023-04-04 op log_warn("%s: listen", __func__);
143 50794f47 2023-04-04 op (void)unlink(path);
151 50794f47 2023-04-04 op start_child(const char *argv0, const char *root, const char *user,
152 ffb578a0 2023-04-04 op const char *db, int debug, int verbose, int fd)
154 50794f47 2023-04-04 op const char *argv[11];
155 50794f47 2023-04-04 op int argc = 0;
158 50794f47 2023-04-04 op switch (pid = fork()) {
160 50794f47 2023-04-04 op fatal("cannot fork");
165 50794f47 2023-04-04 op return (pid);
168 50794f47 2023-04-04 op if (fd != 3) {
169 50794f47 2023-04-04 op if (dup2(fd, 3) == -1)
170 50794f47 2023-04-04 op fatal("cannot setup socket fd");
171 50794f47 2023-04-04 op } else if (fcntl(fd, F_SETFD, 0) == -1)
172 50794f47 2023-04-04 op fatal("cannot setup socket fd");
174 50794f47 2023-04-04 op argv[argc++] = argv0;
175 50794f47 2023-04-04 op argv[argc++] = "-S";
176 50794f47 2023-04-04 op argv[argc++] = "-p"; argv[argc++] = root;
177 50794f47 2023-04-04 op argv[argc++] = "-u"; argv[argc++] = user;
179 50794f47 2023-04-04 op argv[argc++] = "-d";
180 50794f47 2023-04-04 op if (verbose--)
181 50794f47 2023-04-04 op argv[argc++] = "-v";
182 50794f47 2023-04-04 op if (verbose--)
183 50794f47 2023-04-04 op argv[argc++] = "-v";
184 50794f47 2023-04-04 op argv[argc++] = db;
185 50794f47 2023-04-04 op argv[argc++] = NULL;
187 50794f47 2023-04-04 op /* obnoxious cast */
188 50794f47 2023-04-04 op execvp(argv0, (char * const *) argv);
189 50794f47 2023-04-04 op fatal("execvp %s", argv0);
192 50794f47 2023-04-04 op static void __dead
195 50794f47 2023-04-04 op fprintf(stderr,
196 50794f47 2023-04-04 op "usage: %s [-dv] [-j n] [-p path] [-s socket] [-u user] [db]\n",
197 50794f47 2023-04-04 op getprogname());
202 50794f47 2023-04-04 op main(int argc, char **argv)
204 50794f47 2023-04-04 op struct stat sb;
205 50794f47 2023-04-04 op struct passwd *pw;
206 50794f47 2023-04-04 op char sockp[PATH_MAX];
207 50794f47 2023-04-04 op const char *sock = MSEARCHD_SOCK;
208 50794f47 2023-04-04 op const char *user = MSEARCHD_USER;
209 50794f47 2023-04-04 op const char *root = NULL;
210 50794f47 2023-04-04 op const char *db = MSEARCHD_DB;
211 50794f47 2023-04-04 op const char *errstr, *cause, *argv0;
213 50794f47 2023-04-04 op int ch, i, fd, ret, status, server = 0;
216 50794f47 2023-04-04 op * Ensure we have fds 0-2 open so that we have no issue with
217 50794f47 2023-04-04 op * calling bind_socket before daemon(3).
219 50794f47 2023-04-04 op for (i = 0; i < 3; ++i) {
220 50794f47 2023-04-04 op if (fstat(i, &sb) == -1) {
221 50794f47 2023-04-04 op if ((fd = open("/dev/null", O_RDWR)) != -1) {
222 50794f47 2023-04-04 op if (dup2(fd, i) == -1)
231 50794f47 2023-04-04 op if ((argv0 = argv[0]) == NULL)
232 50794f47 2023-04-04 op argv0 = "msearchd";
234 50794f47 2023-04-04 op while ((ch = getopt(argc, argv, "dj:p:Ss:u:v")) != -1) {
235 50794f47 2023-04-04 op switch (ch) {
240 50794f47 2023-04-04 op children = strtonum(optarg, 1, MAX_CHILDREN, &errstr);
242 50794f47 2023-04-04 op fatalx("number of children is %s: %s",
243 50794f47 2023-04-04 op errstr, optarg);
246 50794f47 2023-04-04 op root = optarg;
252 50794f47 2023-04-04 op sock = optarg;
255 50794f47 2023-04-04 op user = optarg;
264 50794f47 2023-04-04 op argc -= optind;
265 50794f47 2023-04-04 op argv += optind;
267 50794f47 2023-04-04 op if (argc > 0) {
268 50794f47 2023-04-04 op db = argv[0];
272 50794f47 2023-04-04 op if (argc != 0)
275 50794f47 2023-04-04 op if (geteuid())
276 50794f47 2023-04-04 op fatalx("need root privileges");
278 50794f47 2023-04-04 op pw = getpwnam(user);
279 50794f47 2023-04-04 op if (pw == NULL)
280 50794f47 2023-04-04 op fatalx("user %s not found", user);
281 50794f47 2023-04-04 op if (pw->pw_uid == 0)
282 50794f47 2023-04-04 op fatalx("cannot run as %s: must not be the superuser", user);
284 50794f47 2023-04-04 op if (root == NULL)
285 50794f47 2023-04-04 op root = pw->pw_dir;
287 50794f47 2023-04-04 op if (!server) {
288 50794f47 2023-04-04 op sigset_t set;
290 50794f47 2023-04-04 op sigemptyset(&set);
291 50794f47 2023-04-04 op sigaddset(&set, SIGCHLD);
292 50794f47 2023-04-04 op sigprocmask(SIG_BLOCK, &set, NULL);
294 50794f47 2023-04-04 op ret = snprintf(sockp, sizeof(sockp), "%s/%s", root, sock);
295 50794f47 2023-04-04 op if (ret < 0 || (size_t)ret >= sizeof(sockp))
296 50794f47 2023-04-04 op fatalx("socket path too long");
297 50794f47 2023-04-04 op if ((fd = bind_socket(sockp, pw)) == -1)
298 50794f47 2023-04-04 op fatalx("failed to open socket %s", sock);
299 50794f47 2023-04-04 op for (i = 0; i < children; ++i) {
302 50794f47 2023-04-04 op if ((d = dup(fd)) == -1)
303 50794f47 2023-04-04 op fatalx("dup");
304 50794f47 2023-04-04 op pids[i] = start_child(argv0, root, user, db, debug,
306 50794f47 2023-04-04 op log_debug("forking child %d (pid %lld)", i,
307 50794f47 2023-04-04 op (long long)pids[i]);
310 50794f47 2023-04-04 op signal(SIGCHLD, handle_sigchld);
311 50794f47 2023-04-04 op signal(SIGHUP, SIG_IGN);
313 50794f47 2023-04-04 op sigprocmask(SIG_UNBLOCK, &set, NULL);
316 50794f47 2023-04-04 op if (chroot(root) == -1)
317 50794f47 2023-04-04 op fatal("chroot %s", root);
318 50794f47 2023-04-04 op if (chdir("/") == -1)
319 50794f47 2023-04-04 op fatal("chdir /");
321 50794f47 2023-04-04 op if (setgroups(1, &pw->pw_gid) == -1 ||
322 50794f47 2023-04-04 op setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
323 50794f47 2023-04-04 op setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
324 50794f47 2023-04-04 op fatal("failed to drop privileges");
327 50794f47 2023-04-04 op logger = &syslogger;
330 50794f47 2023-04-04 op return (server_main(db));
332 50794f47 2023-04-04 op if (!debug && daemon(1, 0) == -1)
333 50794f47 2023-04-04 op fatal("daemon");
335 50794f47 2023-04-04 op if (pledge("stdio proc", NULL) == -1)
336 50794f47 2023-04-04 op fatal("pledge");
340 50794f47 2023-04-04 op pid = waitpid(WAIT_ANY, &status, 0);
341 50794f47 2023-04-04 op } while (pid != -1 || errno == EINTR);
343 50794f47 2023-04-04 op if (pid == -1) {
344 50794f47 2023-04-04 op if (errno == ECHILD)
346 50794f47 2023-04-04 op fatal("waitpid");
349 50794f47 2023-04-04 op if (WIFSIGNALED(status))
350 50794f47 2023-04-04 op cause = "was terminated";
351 50794f47 2023-04-04 op else if (WIFEXITED(status)) {
352 50794f47 2023-04-04 op if (WEXITSTATUS(status) != 0)
353 50794f47 2023-04-04 op cause = "exited abnormally";
355 50794f47 2023-04-04 op cause = "exited successfully";
357 50794f47 2023-04-04 op cause = "died";
359 50794f47 2023-04-04 op log_warnx("child process %lld %s", (long long)pid, cause);
366 50794f47 2023-04-04 op srch_syslog_fatal(int eval, const char *fmt, ...)
368 50794f47 2023-04-04 op static char s[BUFSIZ];
370 50794f47 2023-04-04 op int r, save_errno;
372 50794f47 2023-04-04 op save_errno = errno;
374 50794f47 2023-04-04 op va_start(ap, fmt);
375 50794f47 2023-04-04 op r = vsnprintf(s, sizeof(s), fmt, ap);
378 50794f47 2023-04-04 op errno = save_errno;
380 50794f47 2023-04-04 op if (r > 0 && (size_t)r <= sizeof(s))
381 50794f47 2023-04-04 op syslog(LOG_DAEMON|LOG_CRIT, "%s: %s", s, strerror(errno));
387 50794f47 2023-04-04 op srch_syslog_fatalx(int eval, const char *fmt, ...)
391 50794f47 2023-04-04 op va_start(ap, fmt);
392 50794f47 2023-04-04 op vsyslog(LOG_DAEMON|LOG_CRIT, fmt, ap);
399 50794f47 2023-04-04 op srch_syslog_warn(const char *fmt, ...)
401 50794f47 2023-04-04 op static char s[BUFSIZ];
403 50794f47 2023-04-04 op int r, save_errno;
405 50794f47 2023-04-04 op save_errno = errno;
407 50794f47 2023-04-04 op va_start(ap, fmt);
408 50794f47 2023-04-04 op r = vsnprintf(s, sizeof(s), fmt, ap);
411 50794f47 2023-04-04 op errno = save_errno;
413 cae98100 2023-04-04 op if (r > 0 && (size_t)r < sizeof(s))
414 50794f47 2023-04-04 op syslog(LOG_DAEMON|LOG_ERR, "%s: %s", s, strerror(errno));
416 50794f47 2023-04-04 op errno = save_errno;
420 50794f47 2023-04-04 op srch_syslog_warnx(const char *fmt, ...)
423 50794f47 2023-04-04 op int save_errno;
425 50794f47 2023-04-04 op save_errno = errno;
426 50794f47 2023-04-04 op va_start(ap, fmt);
427 50794f47 2023-04-04 op vsyslog(LOG_DAEMON|LOG_ERR, fmt, ap);
429 50794f47 2023-04-04 op errno = save_errno;
433 50794f47 2023-04-04 op srch_syslog_info(const char *fmt, ...)
436 50794f47 2023-04-04 op int save_errno;
438 50794f47 2023-04-04 op if (verbose < 1)
441 50794f47 2023-04-04 op save_errno = errno;
442 50794f47 2023-04-04 op va_start(ap, fmt);
443 50794f47 2023-04-04 op vsyslog(LOG_DAEMON|LOG_INFO, fmt, ap);
445 50794f47 2023-04-04 op errno = save_errno;
449 50794f47 2023-04-04 op srch_syslog_debug(const char *fmt, ...)
452 50794f47 2023-04-04 op int save_errno;
454 50794f47 2023-04-04 op if (verbose < 2)
457 50794f47 2023-04-04 op save_errno = errno;
458 50794f47 2023-04-04 op va_start(ap, fmt);
459 50794f47 2023-04-04 op vsyslog(LOG_DAEMON|LOG_DEBUG, fmt, ap);
461 50794f47 2023-04-04 op errno = save_errno;