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