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