auditdistd.c revision 243734
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. */
85const char *cfgpath = ADIST_CONFIG;
86/* Auditdistd configuration. */
87static struct adist_config *adcfg;
88/* Was SIGINT or SIGTERM signal received? */
89bool sigexit_received = false;
90/* PID file handle. */
91struct pidfh *pfh;
92
93/* How often check for hooks running for too long. */
94#define	SIGNALS_CHECK_INTERVAL	5
95
96static void
97usage(void)
98{
99
100	errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]");
101}
102
103void
104descriptors_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
125static void
126child_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
137static void
138child_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
153static void
154child_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 */
198static void
199adist_reload(void)
200{
201
202	pjdlog_info("Reloading configuration is not yet implemented.");
203}
204
205static void
206terminate_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
226static void
227listen_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;
416close:
417	proto_close(conn);
418	pjdlog_prefix_set("%s", "");
419}
420
421static void
422connection_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;
451out:
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
462static void
463check_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
498static void
499main_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
581static void
582adist_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
616static void
617dummy_sighandler(int sig __unused)
618{
619	/* Nothing to do. */
620}
621
622int
623main(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