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