xref: /freebsd/contrib/openbsm/bin/auditdistd/receiver.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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 
89 static struct adist_config *adcfg;
90 static struct adist_host *adhost;
91 
92 static TAILQ_HEAD(, adreq) adist_free_list;
93 static pthread_mutex_t adist_free_list_lock;
94 static pthread_cond_t adist_free_list_cond;
95 static TAILQ_HEAD(, adreq) adist_disk_list;
96 static pthread_mutex_t adist_disk_list_lock;
97 static pthread_cond_t adist_disk_list_cond;
98 static TAILQ_HEAD(, adreq) adist_send_list;
99 static pthread_mutex_t adist_send_list_lock;
100 static pthread_cond_t adist_send_list_cond;
101 
102 static void
103 adreq_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 
113 static void
114 init_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 
141 static void
142 adreq_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 
183 static void
184 adreq_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  */
209 static void *
210 recv_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  */
277 static int
278 receiver_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  */
363 static int
364 receiver_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 
395 static int
396 receiver_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 
439 static int
440 receiver_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 
458 static void *
459 disk_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  */
502 static void *
503 send_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 
529 static void
530 receiver_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 
564 static void
565 receiver_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 
609 static void
610 receiver_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 
648 void
649 adist_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