]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/openbsm/bin/auditdistd/auditdistd.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / openbsm / bin / auditdistd / auditdistd.c
1 /*-
2  * Copyright (c) 2012 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <config/config.h>
31
32 #include <sys/param.h>
33 #if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
34 #include <sys/endian.h>
35 #else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
36 #ifdef HAVE_MACHINE_ENDIAN_H
37 #include <machine/endian.h>
38 #else /* !HAVE_MACHINE_ENDIAN_H */
39 #ifdef HAVE_ENDIAN_H
40 #include <endian.h>
41 #else /* !HAVE_ENDIAN_H */
42 #error "No supported endian.h"
43 #endif /* !HAVE_ENDIAN_H */
44 #endif /* !HAVE_MACHINE_ENDIAN_H */
45 #include <compat/endian.h>
46 #endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
47 #include <sys/queue.h>
48 #include <sys/wait.h>
49
50 #include <ctype.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #ifdef HAVE_LIBUTIL_H
55 #include <libutil.h>
56 #endif
57 #include <signal.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <strings.h>
62 #include <unistd.h>
63
64 #include <openssl/hmac.h>
65
66 #ifndef HAVE_PIDFILE_OPEN
67 #include <compat/pidfile.h>
68 #endif
69 #ifndef HAVE_STRLCPY
70 #include <compat/strlcpy.h>
71 #endif
72 #ifndef HAVE_SIGTIMEDWAIT
73 #include "sigtimedwait.h"
74 #endif
75
76 #include "auditdistd.h"
77 #include "pjdlog.h"
78 #include "proto.h"
79 #include "subr.h"
80 #include "synch.h"
81
82 /* Path to configuration file. */
83 const char *cfgpath = ADIST_CONFIG;
84 /* Auditdistd configuration. */
85 static struct adist_config *adcfg;
86 /* Was SIGINT or SIGTERM signal received? */
87 bool sigexit_received = false;
88 /* PID file handle. */
89 struct pidfh *pfh;
90
91 /* How often check for hooks running for too long. */
92 #define SIGNALS_CHECK_INTERVAL  5
93
94 static void
95 usage(void)
96 {
97
98         errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]");
99 }
100
101 void
102 descriptors_cleanup(struct adist_host *adhost)
103 {
104         struct adist_host *adh;
105         struct adist_listen *lst;
106
107         TAILQ_FOREACH(adh, &adcfg->adc_hosts, adh_next) {
108                 if (adh == adhost)
109                         continue;
110                 if (adh->adh_remote != NULL) {
111                         proto_close(adh->adh_remote);
112                         adh->adh_remote = NULL;
113                 }
114         }
115         TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
116                 if (lst->adl_conn != NULL)
117                         proto_close(lst->adl_conn);
118         }
119         (void)pidfile_close(pfh);
120         pjdlog_fini();
121 }
122
123 static void
124 child_cleanup(struct adist_host *adhost)
125 {
126
127         if (adhost->adh_conn != NULL) {
128                 PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
129                 proto_close(adhost->adh_conn);
130                 adhost->adh_conn = NULL;
131         }
132         adhost->adh_worker_pid = 0;
133 }
134
135 static void
136 child_exit_log(const char *type, unsigned int pid, int status)
137 {
138
139         if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
140                 pjdlog_debug(1, "%s process exited gracefully (pid=%u).",
141                     type, pid);
142         } else if (WIFSIGNALED(status)) {
143                 pjdlog_error("%s process killed (pid=%u, signal=%d).",
144                     type, pid, WTERMSIG(status));
145         } else {
146                 pjdlog_error("%s process exited ungracefully (pid=%u, exitcode=%d).",
147                     type, pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1);
148         }
149 }
150
151 static void
152 child_exit(void)
153 {
154         struct adist_host *adhost;
155         bool restart;
156         int status;
157         pid_t pid;
158
159         restart = false;
160         while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
161                 /* Find host related to the process that just exited. */
162                 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
163                         if (pid == adhost->adh_worker_pid)
164                                 break;
165                 }
166                 if (adhost == NULL) {
167                         child_exit_log("Sandbox", pid, status);
168                 } else {
169                         if (adhost->adh_role == ADIST_ROLE_SENDER)
170                                 restart = true;
171                         pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
172                             role2str(adhost->adh_role));
173                         child_exit_log("Worker", pid, status);
174                         child_cleanup(adhost);
175                         pjdlog_prefix_set("%s", "");
176                 }
177         }
178         if (!restart)
179                 return;
180         /* We have some sender processes to restart. */
181         sleep(1);
182         TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
183                 if (adhost->adh_role != ADIST_ROLE_SENDER)
184                         continue;
185                 if (adhost->adh_worker_pid != 0)
186                         continue;
187                 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
188                     role2str(adhost->adh_role));
189                 pjdlog_info("Restarting sender process.");
190                 adist_sender(adcfg, adhost);
191                 pjdlog_prefix_set("%s", "");
192         }
193 }
194
195 /* TODO */
196 static void
197 adist_reload(void)
198 {
199
200         pjdlog_info("Reloading configuration is not yet implemented.");
201 }
202
203 static void
204 terminate_workers(void)
205 {
206         struct adist_host *adhost;
207
208         pjdlog_info("Termination signal received, exiting.");
209         TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
210                 if (adhost->adh_worker_pid == 0)
211                         continue;
212                 pjdlog_info("Terminating worker process (adhost=%s, role=%s, pid=%u).",
213                     adhost->adh_name, role2str(adhost->adh_role),
214                     adhost->adh_worker_pid);
215                 if (kill(adhost->adh_worker_pid, SIGTERM) == 0)
216                         continue;
217                 pjdlog_errno(LOG_WARNING,
218                     "Unable to send signal to worker process (adhost=%s, role=%s, pid=%u).",
219                     adhost->adh_name, role2str(adhost->adh_role),
220                     adhost->adh_worker_pid);
221         }
222 }
223
224 static void
225 listen_accept(struct adist_listen *lst)
226 {
227         unsigned char rnd[32], hash[32], resp[32];
228         struct adist_host *adhost;
229         struct proto_conn *conn;
230         char adname[ADIST_HOSTSIZE];
231         char laddr[256], raddr[256];
232         char welcome[8];
233         int status, version;
234         pid_t pid;
235
236         proto_local_address(lst->adl_conn, laddr, sizeof(laddr));
237         pjdlog_debug(1, "Accepting connection to %s.", laddr);
238
239         if (proto_accept(lst->adl_conn, &conn) == -1) {
240                 pjdlog_errno(LOG_ERR, "Unable to accept connection to %s",
241                     laddr);
242                 return;
243         }
244
245         proto_local_address(conn, laddr, sizeof(laddr));
246         proto_remote_address(conn, raddr, sizeof(raddr));
247         pjdlog_info("Connection from %s to %s.", raddr, laddr);
248
249         /* Error in setting timeout is not critical, but why should it fail? */
250         if (proto_timeout(conn, ADIST_TIMEOUT) < 0)
251                 pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
252
253         /*
254          * Before receiving any data see if remote host is known.
255          */
256         TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
257                 if (adhost->adh_role != ADIST_ROLE_RECEIVER)
258                         continue;
259                 if (!proto_address_match(conn, adhost->adh_remoteaddr))
260                         continue;
261                 break;
262         }
263         if (adhost == NULL) {
264                 pjdlog_error("Client %s is not known.", raddr);
265                 goto close;
266         }
267         /* Ok, remote host is known. */
268
269         /* Exchange welcome message, which include version number. */
270         bzero(welcome, sizeof(welcome));
271         if (proto_recv(conn, welcome, sizeof(welcome)) == -1) {
272                 pjdlog_errno(LOG_WARNING,
273                     "Unable to receive welcome message from %s",
274                     adhost->adh_remoteaddr);
275                 goto close;
276         }
277         if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) ||
278             !isdigit(welcome[6]) || welcome[7] != '\0') {
279                 pjdlog_warning("Invalid welcome message from %s.",
280                     adhost->adh_remoteaddr);
281                 goto close;
282         }
283
284         version = MIN(ADIST_VERSION, atoi(welcome + 5));
285
286         (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", version);
287         if (proto_send(conn, welcome, sizeof(welcome)) == -1) {
288                 pjdlog_errno(LOG_WARNING,
289                     "Unable to send welcome message to %s",
290                     adhost->adh_remoteaddr);
291                 goto close;
292         }
293
294         if (proto_recv(conn, adname, sizeof(adhost->adh_name)) < 0) {
295                 pjdlog_errno(LOG_ERR, "Unable to receive hostname from %s",
296                     raddr);
297                 goto close;
298         }
299
300         /* Find host now that we have hostname. */
301         TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
302                 if (adhost->adh_role != ADIST_ROLE_RECEIVER)
303                         continue;
304                 if (!proto_address_match(conn, adhost->adh_remoteaddr))
305                         continue;
306                 if (strcmp(adhost->adh_name, adname) != 0)
307                         continue;
308                 break;
309         }
310         if (adhost == NULL) {
311                 pjdlog_error("No configuration for host %s from address %s.",
312                     adname, raddr);
313                 goto close;
314         }
315
316         adhost->adh_version = version;
317         pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version,
318             adhost->adh_remoteaddr);
319
320         /* Now that we know host name setup log prefix. */
321         pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
322             role2str(adhost->adh_role));
323
324         if (adist_random(rnd, sizeof(rnd)) == -1) {
325                 pjdlog_error("Unable to generate challenge.");
326                 goto close;
327         }
328         pjdlog_debug(1, "Challenge generated.");
329
330         if (proto_send(conn, rnd, sizeof(rnd)) == -1) {
331                 pjdlog_errno(LOG_ERR, "Unable to send challenge to %s",
332                     adhost->adh_remoteaddr);
333                 goto close;
334         }
335         pjdlog_debug(1, "Challenge sent.");
336
337         if (proto_recv(conn, resp, sizeof(resp)) == -1) {
338                 pjdlog_errno(LOG_ERR, "Unable to receive response from %s",
339                     adhost->adh_remoteaddr);
340                 goto close;
341         }
342         pjdlog_debug(1, "Response received.");
343
344         if (HMAC(EVP_sha256(), adhost->adh_password,
345             (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
346             NULL) == NULL) {
347                 pjdlog_error("Unable to generate hash.");
348                 goto close;
349         }
350         pjdlog_debug(1, "Hash generated.");
351
352         if (memcmp(resp, hash, sizeof(hash)) != 0) {
353                 pjdlog_error("Invalid response from %s (wrong password?).",
354                     adhost->adh_remoteaddr);
355                 goto close;
356         }
357         pjdlog_info("Sender authenticated.");
358
359         if (proto_recv(conn, rnd, sizeof(rnd)) == -1) {
360                 pjdlog_errno(LOG_ERR, "Unable to receive challenge from %s",
361                     adhost->adh_remoteaddr);
362                 goto close;
363         }
364         pjdlog_debug(1, "Challenge received.");
365
366         if (HMAC(EVP_sha256(), adhost->adh_password,
367             (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
368             NULL) == NULL) {
369                 pjdlog_error("Unable to generate response.");
370                 goto close;
371         }
372         pjdlog_debug(1, "Response generated.");
373
374         if (proto_send(conn, hash, sizeof(hash)) == -1) {
375                 pjdlog_errno(LOG_ERR, "Unable to send response to %s",
376                     adhost->adh_remoteaddr);
377                 goto close;
378         }
379         pjdlog_debug(1, "Response sent.");
380
381         if (adhost->adh_worker_pid != 0) {
382                 pjdlog_debug(1,
383                     "Receiver process exists (pid=%u), stopping it.",
384                     (unsigned int)adhost->adh_worker_pid);
385                 /* Stop child process. */
386                 if (kill(adhost->adh_worker_pid, SIGINT) == -1) {
387                         pjdlog_errno(LOG_ERR,
388                             "Unable to stop worker process (pid=%u)",
389                             (unsigned int)adhost->adh_worker_pid);
390                         /*
391                          * Other than logging the problem we
392                          * ignore it - nothing smart to do.
393                          */
394                 }
395                 /* Wait for it to exit. */
396                 else if ((pid = waitpid(adhost->adh_worker_pid,
397                     &status, 0)) != adhost->adh_worker_pid) {
398                         /* We can only log the problem. */
399                         pjdlog_errno(LOG_ERR,
400                             "Waiting for worker process (pid=%u) failed",
401                             (unsigned int)adhost->adh_worker_pid);
402                 } else {
403                         child_exit_log("Worker", adhost->adh_worker_pid,
404                             status);
405                 }
406                 child_cleanup(adhost);
407         }
408
409         adhost->adh_remote = conn;
410         adist_receiver(adcfg, adhost);
411
412         pjdlog_prefix_set("%s", "");
413         return;
414 close:
415         proto_close(conn);
416         pjdlog_prefix_set("%s", "");
417 }
418
419 static void
420 connection_migrate(struct adist_host *adhost)
421 {
422         struct proto_conn *conn;
423         int16_t val = 0;
424
425         pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
426             role2str(adhost->adh_role));
427
428         PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
429
430         if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) {
431                 pjdlog_errno(LOG_WARNING,
432                     "Unable to receive connection command");
433                 return;
434         }
435         if (proto_set("tls:fingerprint", adhost->adh_fingerprint) == -1) {
436                 val = errno;
437                 pjdlog_errno(LOG_WARNING, "Unable to set fingerprint");
438                 goto out;
439         }
440         if (proto_connect(adhost->adh_localaddr[0] != '\0' ?
441             adhost->adh_localaddr : NULL,
442             adhost->adh_remoteaddr, -1, &conn) < 0) {
443                 val = errno;
444                 pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
445                     adhost->adh_remoteaddr);
446                 goto out;
447         }
448         val = 0;
449 out:
450         if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) {
451                 pjdlog_errno(LOG_WARNING,
452                     "Unable to send reply to connection request");
453         }
454         if (val == 0 && proto_connection_send(adhost->adh_conn, conn) < 0)
455                 pjdlog_errno(LOG_WARNING, "Unable to send connection");
456
457         pjdlog_prefix_set("%s", "");
458 }
459
460 static void
461 check_signals(void)
462 {
463         struct timespec sigtimeout;
464         sigset_t mask;
465         int signo;
466
467         sigtimeout.tv_sec = 0;
468         sigtimeout.tv_nsec = 0;
469
470         PJDLOG_VERIFY(sigemptyset(&mask) == 0);
471         PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
472         PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
473         PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
474         PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
475
476         while ((signo = sigtimedwait(&mask, NULL, &sigtimeout)) != -1) {
477                 switch (signo) {
478                 case SIGINT:
479                 case SIGTERM:
480                         sigexit_received = true;
481                         terminate_workers();
482                         exit(EX_OK);
483                         break;
484                 case SIGCHLD:
485                         child_exit();
486                         break;
487                 case SIGHUP:
488                         adist_reload();
489                         break;
490                 default:
491                         PJDLOG_ABORT("Unexpected signal (%d).", signo);
492                 }
493         }
494 }
495
496 static void
497 main_loop(void)
498 {
499         struct adist_host *adhost;
500         struct adist_listen *lst;
501         struct timeval seltimeout;
502         int fd, maxfd, ret;
503         fd_set rfds;
504
505         seltimeout.tv_sec = SIGNALS_CHECK_INTERVAL;
506         seltimeout.tv_usec = 0;
507
508         pjdlog_info("Started successfully.");
509
510         for (;;) {
511                 check_signals();
512
513                 /* Setup descriptors for select(2). */
514                 FD_ZERO(&rfds);
515                 maxfd = -1;
516                 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
517                         if (lst->adl_conn == NULL)
518                                 continue;
519                         fd = proto_descriptor(lst->adl_conn);
520                         PJDLOG_ASSERT(fd >= 0);
521                         FD_SET(fd, &rfds);
522                         maxfd = fd > maxfd ? fd : maxfd;
523                 }
524                 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
525                         if (adhost->adh_role == ADIST_ROLE_SENDER) {
526                                 /* Only sender workers asks for connections. */
527                                 PJDLOG_ASSERT(adhost->adh_conn != NULL);
528                                 fd = proto_descriptor(adhost->adh_conn);
529                                 PJDLOG_ASSERT(fd >= 0);
530                                 FD_SET(fd, &rfds);
531                                 maxfd = fd > maxfd ? fd : maxfd;
532                         } else {
533                                 PJDLOG_ASSERT(adhost->adh_conn == NULL);
534                         }
535                 }
536
537                 PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
538                 ret = select(maxfd + 1, &rfds, NULL, NULL, &seltimeout);
539                 if (ret == 0) {
540                         /*
541                          * select(2) timed out, so there should be no
542                          * descriptors to check.
543                          */
544                         continue;
545                 } else if (ret == -1) {
546                         if (errno == EINTR)
547                                 continue;
548                         KEEP_ERRNO((void)pidfile_remove(pfh));
549                         pjdlog_exit(EX_OSERR, "select() failed");
550                 }
551                 PJDLOG_ASSERT(ret > 0);
552
553                 /*
554                  * Check for signals before we do anything to update our
555                  * info about terminated workers in the meantime.
556                  */
557                 check_signals();
558
559                 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
560                         if (lst->adl_conn == NULL)
561                                 continue;
562                         if (FD_ISSET(proto_descriptor(lst->adl_conn), &rfds))
563                                 listen_accept(lst);
564                 }
565                 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
566                         if (adhost->adh_role == ADIST_ROLE_SENDER) {
567                                 PJDLOG_ASSERT(adhost->adh_conn != NULL);
568                                 if (FD_ISSET(proto_descriptor(adhost->adh_conn),
569                                     &rfds)) {
570                                         connection_migrate(adhost);
571                                 }
572                         } else {
573                                 PJDLOG_ASSERT(adhost->adh_conn == NULL);
574                         }
575                 }
576         }
577 }
578
579 static void
580 adist_config_dump(struct adist_config *cfg)
581 {
582         struct adist_host *adhost;
583         struct adist_listen *lst;
584
585         pjdlog_debug(2, "Configuration:");
586         pjdlog_debug(2, "  Global:");
587         pjdlog_debug(2, "    pidfile: %s", cfg->adc_pidfile);
588         pjdlog_debug(2, "    timeout: %d", cfg->adc_timeout);
589         if (TAILQ_EMPTY(&cfg->adc_listen)) {
590                 pjdlog_debug(2, "  Sender only, not listening.");
591         } else {
592                 pjdlog_debug(2, "  Listening on:");
593                 TAILQ_FOREACH(lst, &cfg->adc_listen, adl_next) {
594                         pjdlog_debug(2, "    listen: %s", lst->adl_addr);
595                         pjdlog_debug(2, "    conn: %p", lst->adl_conn);
596                 }
597         }
598         pjdlog_debug(2, "  Hosts:");
599         TAILQ_FOREACH(adhost, &cfg->adc_hosts, adh_next) {
600                 pjdlog_debug(2, "    name: %s", adhost->adh_name);
601                 pjdlog_debug(2, "      role: %s", role2str(adhost->adh_role));
602                 pjdlog_debug(2, "      version: %d", adhost->adh_version);
603                 pjdlog_debug(2, "      localaddr: %s", adhost->adh_localaddr);
604                 pjdlog_debug(2, "      remoteaddr: %s", adhost->adh_remoteaddr);
605                 pjdlog_debug(2, "      remote: %p", adhost->adh_remote);
606                 pjdlog_debug(2, "      directory: %s", adhost->adh_directory);
607                 pjdlog_debug(2, "      compression: %d", adhost->adh_compression);
608                 pjdlog_debug(2, "      checksum: %d", adhost->adh_checksum);
609                 pjdlog_debug(2, "      pid: %ld", (long)adhost->adh_worker_pid);
610                 pjdlog_debug(2, "      conn: %p", adhost->adh_conn);
611         }
612 }
613
614 static void
615 dummy_sighandler(int sig __unused)
616 {
617         /* Nothing to do. */
618 }
619
620 int
621 main(int argc, char *argv[])
622 {
623         struct adist_host *adhost;
624         struct adist_listen *lst;
625         const char *execpath, *pidfile;
626         bool foreground, launchd;
627         pid_t otherpid;
628         int debuglevel;
629         sigset_t mask;
630
631         execpath = argv[0];
632         if (execpath[0] != '/') {
633                 errx(EX_USAGE,
634                     "auditdistd requires execution with an absolute path.");
635         }
636
637         /*
638          * We are executed from proto to create sandbox.
639          */
640         if (argc > 1 && strcmp(argv[1], "proto") == 0) {
641                 argc -= 2;
642                 argv += 2;
643                 if (proto_exec(argc, argv) == -1)
644                         err(EX_USAGE, "Unable to execute proto");
645         }
646
647         foreground = false;
648         debuglevel = 0;
649         launchd = false;
650         pidfile = NULL;
651
652         for (;;) {
653                 int ch;
654
655                 ch = getopt(argc, argv, "c:dFhlP:");
656                 if (ch == -1)
657                         break;
658                 switch (ch) {
659                 case 'c':
660                         cfgpath = optarg;
661                         break;
662                 case 'd':
663                         debuglevel++;
664                         break;
665                 case 'F':
666                         foreground = true;
667                         break;
668                 case 'l':
669                         launchd = true;
670                         break;
671                 case 'P':
672                         pidfile = optarg;
673                         break;
674                 case 'h':
675                 default:
676                         usage();
677                 }
678         }
679         argc -= optind;
680         argv += optind;
681
682         pjdlog_init(PJDLOG_MODE_STD);
683         pjdlog_debug_set(debuglevel);
684
685         if (proto_set("execpath", execpath) == -1)
686                 pjdlog_exit(EX_TEMPFAIL, "Unable to set executable name");
687         if (proto_set("user", ADIST_USER) == -1)
688                 pjdlog_exit(EX_TEMPFAIL, "Unable to set proto user");
689         if (proto_set("tcp:port", ADIST_TCP_PORT) == -1)
690                 pjdlog_exit(EX_TEMPFAIL, "Unable to set default TCP port");
691
692         /*
693          * When path to the configuration file is relative, obtain full path,
694          * so we can always find the file, even after daemonizing and changing
695          * working directory to /.
696          */
697         if (cfgpath[0] != '/') {
698                 const char *newcfgpath;
699
700                 newcfgpath = realpath(cfgpath, NULL);
701                 if (newcfgpath == NULL) {
702                         pjdlog_exit(EX_CONFIG,
703                             "Unable to obtain full path of %s", cfgpath);
704                 }
705                 cfgpath = newcfgpath;
706         }
707
708         adcfg = yy_config_parse(cfgpath, true);
709         PJDLOG_ASSERT(adcfg != NULL);
710         adist_config_dump(adcfg);
711
712         if (proto_set("tls:certfile", adcfg->adc_certfile) == -1)
713                 pjdlog_exit(EX_TEMPFAIL, "Unable to set certfile path");
714         if (proto_set("tls:keyfile", adcfg->adc_keyfile) == -1)
715                 pjdlog_exit(EX_TEMPFAIL, "Unable to set keyfile path");
716
717         if (pidfile != NULL) {
718                 if (strlcpy(adcfg->adc_pidfile, pidfile,
719                     sizeof(adcfg->adc_pidfile)) >=
720                     sizeof(adcfg->adc_pidfile)) {
721                         pjdlog_exitx(EX_CONFIG, "Pidfile path is too long.");
722                 }
723         }
724         if (foreground && pidfile == NULL) {
725                 pfh = NULL;
726         } else {
727                 pfh = pidfile_open(adcfg->adc_pidfile, 0600, &otherpid);
728                 if (pfh == NULL) {
729                         if (errno == EEXIST) {
730                                 pjdlog_exitx(EX_TEMPFAIL,
731                                     "Another auditdistd is already running, pid: %jd.",
732                                     (intmax_t)otherpid);
733                         }
734                         /*
735                          * If we cannot create pidfile from other reasons,
736                          * only warn.
737                          */
738                         pjdlog_errno(LOG_WARNING,
739                             "Unable to open or create pidfile %s",
740                             adcfg->adc_pidfile);
741                 }
742         }
743
744         /*
745          * Restore default actions for interesting signals in case parent
746          * process (like init(8)) decided to ignore some of them (like SIGHUP).
747          */
748         PJDLOG_VERIFY(signal(SIGHUP, SIG_DFL) != SIG_ERR);
749         PJDLOG_VERIFY(signal(SIGINT, SIG_DFL) != SIG_ERR);
750         PJDLOG_VERIFY(signal(SIGTERM, SIG_DFL) != SIG_ERR);
751         /*
752          * Because SIGCHLD is ignored by default, setup dummy handler for it,
753          * so we can mask it.
754          */
755         PJDLOG_VERIFY(signal(SIGCHLD, dummy_sighandler) != SIG_ERR);
756
757         PJDLOG_VERIFY(sigemptyset(&mask) == 0);
758         PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
759         PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
760         PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
761         PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
762         PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
763
764         /* Listen for remote connections. */
765         TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
766                 if (proto_server(lst->adl_addr, &lst->adl_conn) == -1) {
767                         KEEP_ERRNO((void)pidfile_remove(pfh));
768                         pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
769                             lst->adl_addr);
770                 }
771         }
772
773         if (!foreground) {
774                 if (!launchd && daemon(0, 0) == -1) {
775                         KEEP_ERRNO((void)pidfile_remove(pfh));
776                         pjdlog_exit(EX_OSERR, "Unable to daemonize");
777                 }
778
779                 /* Start logging to syslog. */
780                 pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
781         }
782         if (pfh != NULL) {
783                 /* Write PID to a file. */
784                 if (pidfile_write(pfh) < 0) {
785                         pjdlog_errno(LOG_WARNING,
786                             "Unable to write PID to a file");
787                 }
788         }
789
790         TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
791                 if (adhost->adh_role == ADIST_ROLE_SENDER)
792                         adist_sender(adcfg, adhost);
793         }
794
795         main_loop();
796
797         exit(0);
798 }