xref: /freebsd/contrib/openbsm/bin/auditdistd/auditdistd.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
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 ask 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 }
799