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/receiver.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/stat.h>
51#include <sys/time.h>
52
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 <pthread.h>
60#include <pwd.h>
61#include <signal.h>
62#include <stdint.h>
63#include <stdio.h>
64#include <string.h>
65#include <sysexits.h>
66#include <unistd.h>
67
68#ifndef HAVE_STRLCPY
69#include <compat/strlcpy.h>
70#endif
71#ifndef HAVE_FSTATAT
72#include "fstatat.h"
73#endif
74#ifndef HAVE_OPENAT
75#include "openat.h"
76#endif
77#ifndef HAVE_RENAMEAT
78#include "renameat.h"
79#endif
80
81#include "auditdistd.h"
82#include "pjdlog.h"
83#include "proto.h"
84#include "sandbox.h"
85#include "subr.h"
86#include "synch.h"
87#include "trail.h"
88
89static struct adist_config *adcfg;
90static struct adist_host *adhost;
91
92static TAILQ_HEAD(, adreq) adist_free_list;
93static pthread_mutex_t adist_free_list_lock;
94static pthread_cond_t adist_free_list_cond;
95static TAILQ_HEAD(, adreq) adist_disk_list;
96static pthread_mutex_t adist_disk_list_lock;
97static pthread_cond_t adist_disk_list_cond;
98static TAILQ_HEAD(, adreq) adist_send_list;
99static pthread_mutex_t adist_send_list_lock;
100static pthread_cond_t adist_send_list_cond;
101
102static void
103adreq_clear(struct adreq *adreq)
104{
105
106	adreq->adr_error = -1;
107	adreq->adr_byteorder = ADIST_BYTEORDER_UNDEFINED;
108	adreq->adr_cmd = ADIST_CMD_UNDEFINED;
109	adreq->adr_seq = 0;
110	adreq->adr_datasize = 0;
111}
112
113static void
114init_environment(void)
115{
116	struct adreq *adreq;
117	unsigned int ii;
118
119	TAILQ_INIT(&adist_free_list);
120	mtx_init(&adist_free_list_lock);
121	cv_init(&adist_free_list_cond);
122	TAILQ_INIT(&adist_disk_list);
123	mtx_init(&adist_disk_list_lock);
124	cv_init(&adist_disk_list_cond);
125	TAILQ_INIT(&adist_send_list);
126	mtx_init(&adist_send_list_lock);
127	cv_init(&adist_send_list_cond);
128
129	for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) {
130		adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE);
131		if (adreq == NULL) {
132			pjdlog_exitx(EX_TEMPFAIL,
133			    "Unable to allocate %zu bytes of memory for adreq object.",
134			    sizeof(*adreq) + ADIST_BUF_SIZE);
135		}
136		adreq_clear(adreq);
137		TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next);
138	}
139}
140
141static void
142adreq_decode_and_validate_header(struct adreq *adreq)
143{
144
145	/* Byte-swap only is the sender is using different byte order. */
146	if (adreq->adr_byteorder != ADIST_BYTEORDER) {
147		adreq->adr_byteorder = ADIST_BYTEORDER;
148		adreq->adr_seq = bswap64(adreq->adr_seq);
149		adreq->adr_datasize = bswap32(adreq->adr_datasize);
150	}
151
152	/* Validate packet header. */
153
154	if (adreq->adr_datasize > ADIST_BUF_SIZE) {
155		pjdlog_exitx(EX_PROTOCOL, "Invalid datasize received (%ju).",
156		    (uintmax_t)adreq->adr_datasize);
157	}
158
159	switch (adreq->adr_cmd) {
160	case ADIST_CMD_OPEN:
161	case ADIST_CMD_APPEND:
162	case ADIST_CMD_CLOSE:
163		if (adreq->adr_datasize == 0) {
164			pjdlog_exitx(EX_PROTOCOL,
165			    "Invalid datasize received (%ju).",
166			    (uintmax_t)adreq->adr_datasize);
167		}
168		break;
169	case ADIST_CMD_KEEPALIVE:
170	case ADIST_CMD_ERROR:
171		if (adreq->adr_datasize > 0) {
172			pjdlog_exitx(EX_PROTOCOL,
173			    "Invalid datasize received (%ju).",
174			    (uintmax_t)adreq->adr_datasize);
175		}
176		break;
177	default:
178		pjdlog_exitx(EX_PROTOCOL, "Invalid command received (%hhu).",
179		    adreq->adr_cmd);
180	}
181}
182
183static void
184adreq_validate_data(const struct adreq *adreq)
185{
186
187	/* Validate packet data. */
188
189	switch (adreq->adr_cmd) {
190	case ADIST_CMD_OPEN:
191	case ADIST_CMD_CLOSE:
192		/*
193		 * File name must end up with '\0' and there must be no '\0'
194		 * in the middle.
195		 */
196		if (adreq->adr_data[adreq->adr_datasize - 1] != '\0' ||
197		    strchr(adreq->adr_data, '\0') !=
198		    (const char *)adreq->adr_data + adreq->adr_datasize - 1) {
199			pjdlog_exitx(EX_PROTOCOL,
200			    "Invalid file name received.");
201		}
202		break;
203	}
204}
205
206/*
207 * Thread receives requests from the sender.
208 */
209static void *
210recv_thread(void *arg __unused)
211{
212	struct adreq *adreq;
213
214	for (;;) {
215		pjdlog_debug(3, "recv: Taking free request.");
216		QUEUE_TAKE(adreq, &adist_free_list, 0);
217		pjdlog_debug(3, "recv: (%p) Got request.", adreq);
218
219		if (proto_recv(adhost->adh_remote, &adreq->adr_packet,
220		    sizeof(adreq->adr_packet)) == -1) {
221			pjdlog_exit(EX_TEMPFAIL,
222			    "Unable to receive request header");
223		}
224		adreq_decode_and_validate_header(adreq);
225
226		switch (adreq->adr_cmd) {
227		case ADIST_CMD_KEEPALIVE:
228			adreq->adr_error = 0;
229			adreq_log(LOG_DEBUG, 2, -1, adreq,
230			    "recv: (%p) Got request header: ", adreq);
231			pjdlog_debug(3,
232			    "recv: (%p) Moving request to the send queue.",
233			    adreq);
234			QUEUE_INSERT(adreq, &adist_send_list);
235			continue;
236		case ADIST_CMD_ERROR:
237			pjdlog_error("An error occured on the sender while reading \"%s/%s\".",
238			    adhost->adh_directory, adhost->adh_trail_name);
239			adreq_log(LOG_DEBUG, 2, ADIST_ERROR_READ, adreq,
240			    "recv: (%p) Got request header: ", adreq);
241			pjdlog_debug(3,
242			    "recv: (%p) Moving request to the send queue.",
243			    adreq);
244			QUEUE_INSERT(adreq, &adist_disk_list);
245			continue;
246		case ADIST_CMD_OPEN:
247		case ADIST_CMD_APPEND:
248		case ADIST_CMD_CLOSE:
249			if (proto_recv(adhost->adh_remote, adreq->adr_data,
250			    adreq->adr_datasize) == -1) {
251				pjdlog_exit(EX_TEMPFAIL,
252				    "Unable to receive request data");
253			}
254			adreq_validate_data(adreq);
255			adreq_log(LOG_DEBUG, 2, -1, adreq,
256			    "recv: (%p) Got request header: ", adreq);
257			pjdlog_debug(3,
258			    "recv: (%p) Moving request to the disk queue.",
259			    adreq);
260			QUEUE_INSERT(adreq, &adist_disk_list);
261			break;
262		default:
263			PJDLOG_ABORT("Invalid condition.");
264		}
265	}
266	/* NOTREACHED */
267	return (NULL);
268}
269
270/*
271 * Function that opens trail file requested by the sender.
272 * If the file already exist, it has to be the most recent file and it can
273 * only be open for append.
274 * If the file doesn't already exist, it has to be "older" than all existing
275 * files.
276 */
277static int
278receiver_open(const char *filename)
279{
280	int fd;
281
282	/*
283	 * Previous file should be closed by now. Sending OPEN request without
284	 * sending CLOSE for the previous file is a sender bug.
285	 */
286	if (adhost->adh_trail_fd != -1) {
287		pjdlog_error("Sender requested opening file \"%s\" without first closing \"%s\".",
288		    filename, adhost->adh_trail_name);
289		return (ADIST_ERROR_WRONG_ORDER);
290	}
291
292	if (!trail_validate_name(filename, NULL)) {
293		pjdlog_error("Sender wants to open file \"%s\", which has invalid name.",
294		    filename);
295		return (ADIST_ERROR_INVALID_NAME);
296	}
297
298	switch (trail_name_compare(filename, adhost->adh_trail_name)) {
299	case TRAIL_RENAMED:
300		if (!trail_is_not_terminated(adhost->adh_trail_name)) {
301			pjdlog_error("Terminated trail \"%s/%s\" was unterminated on the sender as \"%s/%s\"?",
302			    adhost->adh_directory, adhost->adh_trail_name,
303			    adhost->adh_directory, filename);
304			return (ADIST_ERROR_INVALID_NAME);
305		}
306		if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
307		    adhost->adh_trail_dirfd, filename) == -1) {
308			pjdlog_errno(LOG_ERR,
309			    "Unable to rename file \"%s/%s\" to \"%s/%s\"",
310			    adhost->adh_directory, adhost->adh_trail_name,
311			    adhost->adh_directory, filename);
312			PJDLOG_ASSERT(errno > 0);
313			return (ADIST_ERROR_RENAME);
314		}
315		pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
316		    adhost->adh_directory, adhost->adh_trail_name,
317		    adhost->adh_directory, filename);
318		/* FALLTHROUGH */
319	case TRAIL_IDENTICAL:
320		/* Opening existing file. */
321		fd = openat(adhost->adh_trail_dirfd, filename,
322		    O_WRONLY | O_APPEND | O_NOFOLLOW);
323		if (fd == -1) {
324			pjdlog_errno(LOG_ERR,
325			    "Unable to open file \"%s/%s\" for append",
326			    adhost->adh_directory, filename);
327			PJDLOG_ASSERT(errno > 0);
328			return (ADIST_ERROR_OPEN);
329		}
330		pjdlog_debug(1, "Opened file \"%s/%s\".",
331		    adhost->adh_directory, filename);
332		break;
333	case TRAIL_NEWER:
334		/* Opening new file. */
335		fd = openat(adhost->adh_trail_dirfd, filename,
336		    O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
337		if (fd == -1) {
338			pjdlog_errno(LOG_ERR,
339			    "Unable to create file \"%s/%s\"",
340			    adhost->adh_directory, filename);
341			PJDLOG_ASSERT(errno > 0);
342			return (ADIST_ERROR_CREATE);
343		}
344		pjdlog_debug(1, "Created file \"%s/%s\".",
345		    adhost->adh_directory, filename);
346		break;
347	case TRAIL_OLDER:
348		/* Trying to open old file. */
349		pjdlog_error("Sender wants to open an old file \"%s\".", filename);
350		return (ADIST_ERROR_OPEN_OLD);
351	default:
352		PJDLOG_ABORT("Unknown return value from trail_name_compare().");
353	}
354	PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
355	    sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
356	adhost->adh_trail_fd = fd;
357	return (0);
358}
359
360/*
361 * Function appends data to the trail file that is currently open.
362 */
363static int
364receiver_append(const unsigned char *data, size_t size)
365{
366	ssize_t done;
367	size_t osize;
368
369	/* We should have opened trail file. */
370	if (adhost->adh_trail_fd == -1) {
371		pjdlog_error("Sender requested append without first opening file.");
372		return (ADIST_ERROR_WRONG_ORDER);
373	}
374
375	osize = size;
376	while (size > 0) {
377		done = write(adhost->adh_trail_fd, data, size);
378		if (done == -1) {
379			if (errno == EINTR)
380				continue;
381			pjdlog_errno(LOG_ERR, "Write to \"%s/%s\" failed",
382			    adhost->adh_directory, adhost->adh_trail_name);
383			PJDLOG_ASSERT(errno > 0);
384			return (ADIST_ERROR_WRITE);
385		}
386		pjdlog_debug(3, "Wrote %zd bytes into \"%s/%s\".", done,
387		    adhost->adh_directory, adhost->adh_trail_name);
388		size -= done;
389	}
390	pjdlog_debug(2, "Appended %zu bytes to file \"%s/%s\".",
391	    osize, adhost->adh_directory, adhost->adh_trail_name);
392	return (0);
393}
394
395static int
396receiver_close(const char *filename)
397{
398
399	/* We should have opened trail file. */
400	if (adhost->adh_trail_fd == -1) {
401		pjdlog_error("Sender requested closing file without first opening it.");
402		return (ADIST_ERROR_WRONG_ORDER);
403	}
404
405	/* Validate if we can do the rename. */
406	if (!trail_validate_name(adhost->adh_trail_name, filename)) {
407		pjdlog_error("Sender wants to close file \"%s\" using name \"%s\".",
408		    adhost->adh_trail_name, filename);
409		return (ADIST_ERROR_INVALID_NAME);
410	}
411
412	PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
413	adhost->adh_trail_fd = -1;
414
415	pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
416	    adhost->adh_trail_name);
417
418	if (strcmp(adhost->adh_trail_name, filename) == 0) {
419		/* File name didn't change, we are done here. */
420		return (0);
421	}
422
423	if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
424	    adhost->adh_trail_dirfd, filename) == -1) {
425		pjdlog_errno(LOG_ERR, "Unable to rename \"%s\" to \"%s\"",
426		    adhost->adh_trail_name, filename);
427		PJDLOG_ASSERT(errno > 0);
428		return (ADIST_ERROR_RENAME);
429	}
430	pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
431	    adhost->adh_directory, adhost->adh_trail_name,
432	    adhost->adh_directory, filename);
433	PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
434	    sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
435
436	return (0);
437}
438
439static int
440receiver_error(void)
441{
442
443	/* We should have opened trail file. */
444	if (adhost->adh_trail_fd == -1) {
445		pjdlog_error("Sender send read error, but file is not open.");
446		return (ADIST_ERROR_WRONG_ORDER);
447	}
448
449	PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
450	adhost->adh_trail_fd = -1;
451
452	pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
453	    adhost->adh_trail_name);
454
455	return (0);
456}
457
458static void *
459disk_thread(void *arg __unused)
460{
461	struct adreq *adreq;
462
463	for (;;) {
464		pjdlog_debug(3, "disk: Taking request.");
465		QUEUE_TAKE(adreq, &adist_disk_list, 0);
466		adreq_log(LOG_DEBUG, 3, -1, adreq, "disk: (%p) Got request: ",
467		    adreq);
468		/* Handle the actual request. */
469		switch (adreq->adr_cmd) {
470		case ADIST_CMD_OPEN:
471			adreq->adr_error = receiver_open(adreq->adr_data);
472			break;
473		case ADIST_CMD_APPEND:
474			adreq->adr_error = receiver_append(adreq->adr_data,
475			    adreq->adr_datasize);
476			break;
477		case ADIST_CMD_CLOSE:
478			adreq->adr_error = receiver_close(adreq->adr_data);
479			break;
480		case ADIST_CMD_ERROR:
481			adreq->adr_error = receiver_error();
482			break;
483		default:
484			PJDLOG_ABORT("Unexpected command (cmd=%hhu).",
485			    adreq->adr_cmd);
486		}
487		if (adreq->adr_error != 0) {
488			adreq_log(LOG_ERR, 0, adreq->adr_error, adreq,
489			    "Request failed: ");
490		}
491		pjdlog_debug(3, "disk: (%p) Moving request to the send queue.",
492		    adreq);
493		QUEUE_INSERT(adreq, &adist_send_list);
494	}
495	/* NOTREACHED */
496	return (NULL);
497}
498
499/*
500 * Thread sends requests back to primary node.
501 */
502static void *
503send_thread(void *arg __unused)
504{
505	struct adreq *adreq;
506	struct adrep adrep;
507
508	for (;;) {
509		pjdlog_debug(3, "send: Taking request.");
510		QUEUE_TAKE(adreq, &adist_send_list, 0);
511		adreq_log(LOG_DEBUG, 3, -1, adreq, "send: (%p) Got request: ",
512		    adreq);
513		adrep.adrp_byteorder = ADIST_BYTEORDER;
514		adrep.adrp_seq = adreq->adr_seq;
515		adrep.adrp_error = adreq->adr_error;
516		if (proto_send(adhost->adh_remote, &adrep,
517		    sizeof(adrep)) == -1) {
518			pjdlog_exit(EX_TEMPFAIL, "Unable to send reply");
519		}
520		pjdlog_debug(3, "send: (%p) Moving request to the free queue.",
521		    adreq);
522		adreq_clear(adreq);
523		QUEUE_INSERT(adreq, &adist_free_list);
524	}
525	/* NOTREACHED */
526	return (NULL);
527}
528
529static void
530receiver_directory_create(void)
531{
532	struct passwd *pw;
533
534	/*
535	 * According to getpwnam(3) we have to clear errno before calling the
536	 * function to be able to distinguish between an error and missing
537	 * entry (with is not treated as error by getpwnam(3)).
538	 */
539	errno = 0;
540	pw = getpwnam(ADIST_USER);
541	if (pw == NULL) {
542		if (errno != 0) {
543			pjdlog_exit(EX_NOUSER,
544			    "Unable to find info about '%s' user", ADIST_USER);
545		} else {
546			pjdlog_exitx(EX_NOUSER, "User '%s' doesn't exist.",
547			    ADIST_USER);
548		}
549	}
550
551	if (mkdir(adhost->adh_directory, 0700) == -1) {
552		pjdlog_exit(EX_OSFILE, "Unable to create directory \"%s\"",
553		    adhost->adh_directory);
554	}
555	if (chown(adhost->adh_directory, pw->pw_uid, pw->pw_gid) == -1) {
556		pjdlog_errno(LOG_ERR,
557		    "Unable to change owner of the directory \"%s\"",
558		    adhost->adh_directory);
559		(void)rmdir(adhost->adh_directory);
560		exit(EX_OSFILE);
561	}
562}
563
564static void
565receiver_directory_open(void)
566{
567
568#ifdef HAVE_FDOPENDIR
569	adhost->adh_trail_dirfd = open(adhost->adh_directory,
570	    O_RDONLY | O_DIRECTORY);
571	if (adhost->adh_trail_dirfd == -1) {
572		if (errno == ENOENT) {
573			receiver_directory_create();
574			adhost->adh_trail_dirfd = open(adhost->adh_directory,
575			    O_RDONLY | O_DIRECTORY);
576		}
577		if (adhost->adh_trail_dirfd == -1) {
578			pjdlog_exit(EX_CONFIG,
579			    "Unable to open directory \"%s\"",
580			    adhost->adh_directory);
581		}
582	}
583	adhost->adh_trail_dirfp = fdopendir(adhost->adh_trail_dirfd);
584	if (adhost->adh_trail_dirfp == NULL) {
585		pjdlog_exit(EX_CONFIG, "Unable to fdopen directory \"%s\"",
586		    adhost->adh_directory);
587	}
588#else
589	struct stat sb;
590
591	if (stat(adhost->adh_directory, &sb) == -1) {
592		if (errno == ENOENT) {
593			receiver_directory_create();
594		} else {
595			pjdlog_exit(EX_CONFIG,
596			    "Unable to stat directory \"%s\"",
597			    adhost->adh_directory);
598		}
599	}
600	adhost->adh_trail_dirfp = opendir(adhost->adh_directory);
601	if (adhost->adh_trail_dirfp == NULL) {
602		pjdlog_exit(EX_CONFIG, "Unable to open directory \"%s\"",
603		    adhost->adh_directory);
604	}
605	adhost->adh_trail_dirfd = dirfd(adhost->adh_trail_dirfp);
606#endif
607}
608
609static void
610receiver_connect(void)
611{
612	uint64_t trail_size;
613	struct stat sb;
614
615	PJDLOG_ASSERT(adhost->adh_trail_dirfp != NULL);
616
617	trail_last(adhost->adh_trail_dirfp, adhost->adh_trail_name,
618	    sizeof(adhost->adh_trail_name));
619
620	if (adhost->adh_trail_name[0] == '\0') {
621		trail_size = 0;
622	} else {
623		if (fstatat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
624		    &sb, AT_SYMLINK_NOFOLLOW) == -1) {
625			pjdlog_exit(EX_CONFIG, "Unable to stat \"%s/%s\"",
626			    adhost->adh_directory, adhost->adh_trail_name);
627		}
628		if (!S_ISREG(sb.st_mode)) {
629			pjdlog_exitx(EX_CONFIG,
630			    "File \"%s/%s\" is not a regular file.",
631			    adhost->adh_directory, adhost->adh_trail_name);
632		}
633		trail_size = sb.st_size;
634	}
635	trail_size = htole64(trail_size);
636	if (proto_send(adhost->adh_remote, &trail_size,
637	    sizeof(trail_size)) == -1) {
638		pjdlog_exit(EX_TEMPFAIL,
639		    "Unable to send size of the most recent trail file");
640	}
641	if (proto_send(adhost->adh_remote, adhost->adh_trail_name,
642	    sizeof(adhost->adh_trail_name)) == -1) {
643		pjdlog_exit(EX_TEMPFAIL,
644		    "Unable to send name of the most recent trail file");
645	}
646}
647
648void
649adist_receiver(struct adist_config *config, struct adist_host *adh)
650{
651	sigset_t mask;
652	pthread_t td;
653	pid_t pid;
654	int error, mode, debuglevel;
655
656	pid = fork();
657	if (pid == -1) {
658		pjdlog_errno(LOG_ERR, "Unable to fork");
659		proto_close(adh->adh_remote);
660		adh->adh_remote = NULL;
661		return;
662	}
663
664	if (pid > 0) {
665		/* This is parent. */
666		proto_close(adh->adh_remote);
667		adh->adh_remote = NULL;
668		adh->adh_worker_pid = pid;
669		return;
670	}
671
672	adcfg = config;
673	adhost = adh;
674	mode = pjdlog_mode_get();
675	debuglevel = pjdlog_debug_get();
676
677	descriptors_cleanup(adhost);
678
679//	descriptors_assert(adhost, mode);
680
681	pjdlog_init(mode);
682	pjdlog_debug_set(debuglevel);
683	pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
684	    role2str(adhost->adh_role));
685#ifdef HAVE_SETPROCTITLE
686	setproctitle("%s (%s)", adhost->adh_name, role2str(adhost->adh_role));
687#endif
688
689	PJDLOG_VERIFY(sigemptyset(&mask) == 0);
690	PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
691
692	/* Error in setting timeout is not critical, but why should it fail? */
693	if (proto_timeout(adhost->adh_remote, adcfg->adc_timeout) == -1)
694		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
695
696	init_environment();
697
698	adhost->adh_trail_fd = -1;
699	receiver_directory_open();
700
701	if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)",
702	    role2str(adhost->adh_role), adhost->adh_name) != 0) {
703		exit(EX_CONFIG);
704	}
705	pjdlog_info("Privileges successfully dropped.");
706
707	receiver_connect();
708
709	error = pthread_create(&td, NULL, recv_thread, adhost);
710	PJDLOG_ASSERT(error == 0);
711	error = pthread_create(&td, NULL, disk_thread, adhost);
712	PJDLOG_ASSERT(error == 0);
713	(void)send_thread(adhost);
714}
715