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. */
83const char *cfgpath = ADIST_CONFIG;
84/* Auditdistd configuration. */
85static struct adist_config *adcfg;
86/* Was SIGINT or SIGTERM signal received? */
87bool sigexit_received = false;
88/* PID file handle. */
89struct pidfh *pfh;
90
91/* How often check for hooks running for too long. */
92#define	SIGNALS_CHECK_INTERVAL	5
93
94static void
95usage(void)
96{
97
98	errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]");
99}
100
101void
102descriptors_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
123static void
124child_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
135static void
136child_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
151static void
152child_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 */
196static void
197adist_reload(void)
198{
199
200	pjdlog_info("Reloading configuration is not yet implemented.");
201}
202
203static void
204terminate_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
224static void
225listen_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;
414close:
415	proto_close(conn);
416	pjdlog_prefix_set("%s", "");
417}
418
419static void
420connection_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;
449out:
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
460static void
461check_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
496static void
497main_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
579static void
580adist_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
614static void
615dummy_sighandler(int sig __unused)
616{
617	/* Nothing to do. */
618}
619
620int
621main(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