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