receiver.c revision 243734
1243730Srwatson/*-
2243730Srwatson * Copyright (c) 2012 The FreeBSD Foundation
3243730Srwatson * All rights reserved.
4243730Srwatson *
5243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from
6243730Srwatson * the FreeBSD Foundation.
7243730Srwatson *
8243730Srwatson * Redistribution and use in source and binary forms, with or without
9243730Srwatson * modification, are permitted provided that the following conditions
10243730Srwatson * are met:
11243730Srwatson * 1. Redistributions of source code must retain the above copyright
12243730Srwatson *    notice, this list of conditions and the following disclaimer.
13243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright
14243730Srwatson *    notice, this list of conditions and the following disclaimer in the
15243730Srwatson *    documentation and/or other materials provided with the distribution.
16243730Srwatson *
17243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20243730Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27243730Srwatson * SUCH DAMAGE.
28243730Srwatson *
29243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/receiver.c#3 $
30243730Srwatson */
31243730Srwatson
32243734Srwatson#include <config/config.h>
33243730Srwatson
34243730Srwatson#include <sys/param.h>
35243730Srwatson#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
36243730Srwatson#include <sys/endian.h>
37243730Srwatson#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
38243730Srwatson#ifdef HAVE_MACHINE_ENDIAN_H
39243730Srwatson#include <machine/endian.h>
40243730Srwatson#else /* !HAVE_MACHINE_ENDIAN_H */
41243730Srwatson#ifdef HAVE_ENDIAN_H
42243730Srwatson#include <endian.h>
43243730Srwatson#else /* !HAVE_ENDIAN_H */
44243730Srwatson#error "No supported endian.h"
45243730Srwatson#endif /* !HAVE_ENDIAN_H */
46243730Srwatson#endif /* !HAVE_MACHINE_ENDIAN_H */
47243730Srwatson#include <compat/endian.h>
48243730Srwatson#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
49243730Srwatson#include <sys/queue.h>
50243730Srwatson#include <sys/stat.h>
51243730Srwatson#include <sys/time.h>
52243730Srwatson
53243730Srwatson#include <err.h>
54243730Srwatson#include <errno.h>
55243730Srwatson#include <fcntl.h>
56243730Srwatson#ifdef HAVE_LIBUTIL_H
57243730Srwatson#include <libutil.h>
58243730Srwatson#endif
59243730Srwatson#include <pthread.h>
60243730Srwatson#include <pwd.h>
61243730Srwatson#include <signal.h>
62243730Srwatson#include <stdint.h>
63243730Srwatson#include <stdio.h>
64243730Srwatson#include <string.h>
65243730Srwatson#include <sysexits.h>
66243730Srwatson#include <unistd.h>
67243730Srwatson
68243730Srwatson#ifndef HAVE_STRLCPY
69243730Srwatson#include <compat/strlcpy.h>
70243730Srwatson#endif
71243730Srwatson#ifndef HAVE_FSTATAT
72243730Srwatson#include "fstatat.h"
73243730Srwatson#endif
74243730Srwatson#ifndef HAVE_OPENAT
75243730Srwatson#include "openat.h"
76243730Srwatson#endif
77243730Srwatson#ifndef HAVE_RENAMEAT
78243730Srwatson#include "renameat.h"
79243730Srwatson#endif
80243730Srwatson
81243730Srwatson#include "auditdistd.h"
82243734Srwatson#include "pjdlog.h"
83243730Srwatson#include "proto.h"
84243730Srwatson#include "sandbox.h"
85243730Srwatson#include "subr.h"
86243730Srwatson#include "synch.h"
87243730Srwatson#include "trail.h"
88243730Srwatson
89243730Srwatsonstatic struct adist_config *adcfg;
90243730Srwatsonstatic struct adist_host *adhost;
91243730Srwatson
92243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_free_list;
93243730Srwatsonstatic pthread_mutex_t adist_free_list_lock;
94243730Srwatsonstatic pthread_cond_t adist_free_list_cond;
95243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_disk_list;
96243730Srwatsonstatic pthread_mutex_t adist_disk_list_lock;
97243730Srwatsonstatic pthread_cond_t adist_disk_list_cond;
98243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_send_list;
99243730Srwatsonstatic pthread_mutex_t adist_send_list_lock;
100243730Srwatsonstatic pthread_cond_t adist_send_list_cond;
101243730Srwatson
102243730Srwatsonstatic void
103243730Srwatsonadreq_clear(struct adreq *adreq)
104243730Srwatson{
105243730Srwatson
106243730Srwatson	adreq->adr_error = -1;
107243730Srwatson	adreq->adr_byteorder = ADIST_BYTEORDER_UNDEFINED;
108243730Srwatson	adreq->adr_cmd = ADIST_CMD_UNDEFINED;
109243730Srwatson	adreq->adr_seq = 0;
110243730Srwatson	adreq->adr_datasize = 0;
111243730Srwatson}
112243730Srwatson
113243730Srwatsonstatic void
114243730Srwatsoninit_environment(void)
115243730Srwatson{
116243730Srwatson	struct adreq *adreq;
117243730Srwatson	unsigned int ii;
118243730Srwatson
119243730Srwatson	TAILQ_INIT(&adist_free_list);
120243730Srwatson	mtx_init(&adist_free_list_lock);
121243730Srwatson	cv_init(&adist_free_list_cond);
122243730Srwatson	TAILQ_INIT(&adist_disk_list);
123243730Srwatson	mtx_init(&adist_disk_list_lock);
124243730Srwatson	cv_init(&adist_disk_list_cond);
125243730Srwatson	TAILQ_INIT(&adist_send_list);
126243730Srwatson	mtx_init(&adist_send_list_lock);
127243730Srwatson	cv_init(&adist_send_list_cond);
128243730Srwatson
129243730Srwatson	for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) {
130243730Srwatson		adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE);
131243730Srwatson		if (adreq == NULL) {
132243730Srwatson			pjdlog_exitx(EX_TEMPFAIL,
133243730Srwatson			    "Unable to allocate %zu bytes of memory for adreq object.",
134243730Srwatson			    sizeof(*adreq) + ADIST_BUF_SIZE);
135243730Srwatson		}
136243730Srwatson		adreq_clear(adreq);
137243730Srwatson		TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next);
138243730Srwatson	}
139243730Srwatson}
140243730Srwatson
141243730Srwatsonstatic void
142243730Srwatsonadreq_decode_and_validate_header(struct adreq *adreq)
143243730Srwatson{
144243730Srwatson
145243730Srwatson	/* Byte-swap only is the sender is using different byte order. */
146243730Srwatson	if (adreq->adr_byteorder != ADIST_BYTEORDER) {
147243730Srwatson		adreq->adr_byteorder = ADIST_BYTEORDER;
148243730Srwatson		adreq->adr_seq = bswap64(adreq->adr_seq);
149243730Srwatson		adreq->adr_datasize = bswap32(adreq->adr_datasize);
150243730Srwatson	}
151243730Srwatson
152243730Srwatson	/* Validate packet header. */
153243730Srwatson
154243730Srwatson	if (adreq->adr_datasize > ADIST_BUF_SIZE) {
155243730Srwatson		pjdlog_exitx(EX_PROTOCOL, "Invalid datasize received (%ju).",
156243730Srwatson		    (uintmax_t)adreq->adr_datasize);
157243730Srwatson	}
158243730Srwatson
159243730Srwatson	switch (adreq->adr_cmd) {
160243730Srwatson	case ADIST_CMD_OPEN:
161243730Srwatson	case ADIST_CMD_APPEND:
162243730Srwatson	case ADIST_CMD_CLOSE:
163243730Srwatson		if (adreq->adr_datasize == 0) {
164243730Srwatson			pjdlog_exitx(EX_PROTOCOL,
165243730Srwatson			    "Invalid datasize received (%ju).",
166243730Srwatson			    (uintmax_t)adreq->adr_datasize);
167243730Srwatson		}
168243730Srwatson		break;
169243730Srwatson	case ADIST_CMD_KEEPALIVE:
170243730Srwatson	case ADIST_CMD_ERROR:
171243730Srwatson		if (adreq->adr_datasize > 0) {
172243730Srwatson			pjdlog_exitx(EX_PROTOCOL,
173243730Srwatson			    "Invalid datasize received (%ju).",
174243730Srwatson			    (uintmax_t)adreq->adr_datasize);
175243730Srwatson		}
176243730Srwatson		break;
177243730Srwatson	default:
178243730Srwatson		pjdlog_exitx(EX_PROTOCOL, "Invalid command received (%hhu).",
179243730Srwatson		    adreq->adr_cmd);
180243730Srwatson	}
181243730Srwatson}
182243730Srwatson
183243730Srwatsonstatic void
184243730Srwatsonadreq_validate_data(const struct adreq *adreq)
185243730Srwatson{
186243730Srwatson
187243730Srwatson	/* Validate packet data. */
188243730Srwatson
189243730Srwatson	switch (adreq->adr_cmd) {
190243730Srwatson	case ADIST_CMD_OPEN:
191243730Srwatson	case ADIST_CMD_CLOSE:
192243730Srwatson		/*
193243730Srwatson		 * File name must end up with '\0' and there must be no '\0'
194243730Srwatson		 * in the middle.
195243730Srwatson		 */
196243730Srwatson		if (adreq->adr_data[adreq->adr_datasize - 1] != '\0' ||
197243730Srwatson		    strchr(adreq->adr_data, '\0') !=
198243730Srwatson		    (const char *)adreq->adr_data + adreq->adr_datasize - 1) {
199243730Srwatson			pjdlog_exitx(EX_PROTOCOL,
200243730Srwatson			    "Invalid file name received.");
201243730Srwatson		}
202243730Srwatson		break;
203243730Srwatson	}
204243730Srwatson}
205243730Srwatson
206243730Srwatson/*
207243730Srwatson * Thread receives requests from the sender.
208243730Srwatson */
209243730Srwatsonstatic void *
210243730Srwatsonrecv_thread(void *arg __unused)
211243730Srwatson{
212243730Srwatson	struct adreq *adreq;
213243730Srwatson
214243730Srwatson	for (;;) {
215243730Srwatson		pjdlog_debug(3, "recv: Taking free request.");
216243730Srwatson		QUEUE_TAKE(adreq, &adist_free_list, 0);
217243730Srwatson		pjdlog_debug(3, "recv: (%p) Got request.", adreq);
218243730Srwatson
219243730Srwatson		if (proto_recv(adhost->adh_remote, &adreq->adr_packet,
220243730Srwatson		    sizeof(adreq->adr_packet)) == -1) {
221243730Srwatson			pjdlog_exit(EX_TEMPFAIL,
222243730Srwatson			    "Unable to receive request header");
223243730Srwatson		}
224243730Srwatson		adreq_decode_and_validate_header(adreq);
225243730Srwatson
226243730Srwatson		switch (adreq->adr_cmd) {
227243730Srwatson		case ADIST_CMD_KEEPALIVE:
228243730Srwatson			adreq->adr_error = 0;
229243730Srwatson			adreq_log(LOG_DEBUG, 2, -1, adreq,
230243730Srwatson			    "recv: (%p) Got request header: ", adreq);
231243730Srwatson			pjdlog_debug(3,
232243730Srwatson			    "recv: (%p) Moving request to the send queue.",
233243730Srwatson			    adreq);
234243730Srwatson			QUEUE_INSERT(adreq, &adist_send_list);
235243730Srwatson			continue;
236243730Srwatson		case ADIST_CMD_ERROR:
237243730Srwatson			pjdlog_error("An error occured on the sender while reading \"%s/%s\".",
238243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name);
239243730Srwatson			adreq_log(LOG_DEBUG, 2, ADIST_ERROR_READ, adreq,
240243730Srwatson			    "recv: (%p) Got request header: ", adreq);
241243730Srwatson			pjdlog_debug(3,
242243730Srwatson			    "recv: (%p) Moving request to the send queue.",
243243730Srwatson			    adreq);
244243730Srwatson			QUEUE_INSERT(adreq, &adist_disk_list);
245243730Srwatson			continue;
246243730Srwatson		case ADIST_CMD_OPEN:
247243730Srwatson		case ADIST_CMD_APPEND:
248243730Srwatson		case ADIST_CMD_CLOSE:
249243730Srwatson			if (proto_recv(adhost->adh_remote, adreq->adr_data,
250243730Srwatson			    adreq->adr_datasize) == -1) {
251243730Srwatson				pjdlog_exit(EX_TEMPFAIL,
252243730Srwatson				    "Unable to receive request data");
253243730Srwatson			}
254243730Srwatson			adreq_validate_data(adreq);
255243730Srwatson			adreq_log(LOG_DEBUG, 2, -1, adreq,
256243730Srwatson			    "recv: (%p) Got request header: ", adreq);
257243730Srwatson			pjdlog_debug(3,
258243730Srwatson			    "recv: (%p) Moving request to the disk queue.",
259243730Srwatson			    adreq);
260243730Srwatson			QUEUE_INSERT(adreq, &adist_disk_list);
261243730Srwatson			break;
262243730Srwatson		default:
263243730Srwatson			PJDLOG_ABORT("Invalid condition.");
264243730Srwatson		}
265243730Srwatson	}
266243730Srwatson	/* NOTREACHED */
267243730Srwatson	return (NULL);
268243730Srwatson}
269243730Srwatson
270243730Srwatson/*
271243730Srwatson * Function that opens trail file requested by the sender.
272243730Srwatson * If the file already exist, it has to be the most recent file and it can
273243730Srwatson * only be open for append.
274243730Srwatson * If the file doesn't already exist, it has to be "older" than all existing
275243730Srwatson * files.
276243730Srwatson */
277243730Srwatsonstatic int
278243730Srwatsonreceiver_open(const char *filename)
279243730Srwatson{
280243730Srwatson	int fd;
281243730Srwatson
282243730Srwatson	/*
283243730Srwatson	 * Previous file should be closed by now. Sending OPEN request without
284243730Srwatson	 * sending CLOSE for the previous file is a sender bug.
285243730Srwatson	 */
286243730Srwatson	if (adhost->adh_trail_fd != -1) {
287243730Srwatson		pjdlog_error("Sender requested opening file \"%s\" without first closing \"%s\".",
288243730Srwatson		    filename, adhost->adh_trail_name);
289243730Srwatson		return (ADIST_ERROR_WRONG_ORDER);
290243730Srwatson	}
291243730Srwatson
292243730Srwatson	if (!trail_validate_name(filename, NULL)) {
293243730Srwatson		pjdlog_error("Sender wants to open file \"%s\", which has invalid name.",
294243730Srwatson		    filename);
295243730Srwatson		return (ADIST_ERROR_INVALID_NAME);
296243730Srwatson	}
297243730Srwatson
298243730Srwatson	switch (trail_name_compare(filename, adhost->adh_trail_name)) {
299243730Srwatson	case TRAIL_RENAMED:
300243730Srwatson		if (!trail_is_not_terminated(adhost->adh_trail_name)) {
301243730Srwatson			pjdlog_error("Terminated trail \"%s/%s\" was unterminated on the sender as \"%s/%s\"?",
302243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name,
303243730Srwatson			    adhost->adh_directory, filename);
304243730Srwatson			return (ADIST_ERROR_INVALID_NAME);
305243730Srwatson		}
306243730Srwatson		if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
307243730Srwatson		    adhost->adh_trail_dirfd, filename) == -1) {
308243730Srwatson			pjdlog_errno(LOG_ERR,
309243730Srwatson			    "Unable to rename file \"%s/%s\" to \"%s/%s\"",
310243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name,
311243730Srwatson			    adhost->adh_directory, filename);
312243730Srwatson			PJDLOG_ASSERT(errno > 0);
313243730Srwatson			return (ADIST_ERROR_RENAME);
314243730Srwatson		}
315243730Srwatson		pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
316243730Srwatson		    adhost->adh_directory, adhost->adh_trail_name,
317243730Srwatson		    adhost->adh_directory, filename);
318243730Srwatson		/* FALLTHROUGH */
319243730Srwatson	case TRAIL_IDENTICAL:
320243730Srwatson		/* Opening existing file. */
321243730Srwatson		fd = openat(adhost->adh_trail_dirfd, filename,
322243730Srwatson		    O_WRONLY | O_APPEND | O_NOFOLLOW);
323243730Srwatson		if (fd == -1) {
324243730Srwatson			pjdlog_errno(LOG_ERR,
325243730Srwatson			    "Unable to open file \"%s/%s\" for append",
326243730Srwatson			    adhost->adh_directory, filename);
327243730Srwatson			PJDLOG_ASSERT(errno > 0);
328243730Srwatson			return (ADIST_ERROR_OPEN);
329243730Srwatson		}
330243730Srwatson		pjdlog_debug(1, "Opened file \"%s/%s\".",
331243730Srwatson		    adhost->adh_directory, filename);
332243730Srwatson		break;
333243730Srwatson	case TRAIL_NEWER:
334243730Srwatson		/* Opening new file. */
335243730Srwatson		fd = openat(adhost->adh_trail_dirfd, filename,
336243730Srwatson		    O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
337243730Srwatson		if (fd == -1) {
338243730Srwatson			pjdlog_errno(LOG_ERR,
339243730Srwatson			    "Unable to create file \"%s/%s\"",
340243730Srwatson			    adhost->adh_directory, filename);
341243730Srwatson			PJDLOG_ASSERT(errno > 0);
342243730Srwatson			return (ADIST_ERROR_CREATE);
343243730Srwatson		}
344243730Srwatson		pjdlog_debug(1, "Created file \"%s/%s\".",
345243730Srwatson		    adhost->adh_directory, filename);
346243730Srwatson		break;
347243730Srwatson	case TRAIL_OLDER:
348243730Srwatson		/* Trying to open old file. */
349243730Srwatson		pjdlog_error("Sender wants to open an old file \"%s\".", filename);
350243730Srwatson		return (ADIST_ERROR_OPEN_OLD);
351243730Srwatson	default:
352243730Srwatson		PJDLOG_ABORT("Unknown return value from trail_name_compare().");
353243730Srwatson	}
354243730Srwatson	PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
355243730Srwatson	    sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
356243730Srwatson	adhost->adh_trail_fd = fd;
357243730Srwatson	return (0);
358243730Srwatson}
359243730Srwatson
360243730Srwatson/*
361243730Srwatson * Function appends data to the trail file that is currently open.
362243730Srwatson */
363243730Srwatsonstatic int
364243730Srwatsonreceiver_append(const unsigned char *data, size_t size)
365243730Srwatson{
366243730Srwatson	ssize_t done;
367243730Srwatson	size_t osize;
368243730Srwatson
369243730Srwatson	/* We should have opened trail file. */
370243730Srwatson	if (adhost->adh_trail_fd == -1) {
371243730Srwatson		pjdlog_error("Sender requested append without first opening file.");
372243730Srwatson		return (ADIST_ERROR_WRONG_ORDER);
373243730Srwatson	}
374243730Srwatson
375243730Srwatson	osize = size;
376243730Srwatson	while (size > 0) {
377243730Srwatson		done = write(adhost->adh_trail_fd, data, size);
378243730Srwatson		if (done == -1) {
379243730Srwatson			if (errno == EINTR)
380243730Srwatson				continue;
381243730Srwatson			pjdlog_errno(LOG_ERR, "Write to \"%s/%s\" failed",
382243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name);
383243730Srwatson			PJDLOG_ASSERT(errno > 0);
384243730Srwatson			return (ADIST_ERROR_WRITE);
385243730Srwatson		}
386243730Srwatson		pjdlog_debug(3, "Wrote %zd bytes into \"%s/%s\".", done,
387243730Srwatson		    adhost->adh_directory, adhost->adh_trail_name);
388243730Srwatson		size -= done;
389243730Srwatson	}
390243730Srwatson	pjdlog_debug(2, "Appended %zu bytes to file \"%s/%s\".",
391243730Srwatson	    osize, adhost->adh_directory, adhost->adh_trail_name);
392243730Srwatson	return (0);
393243730Srwatson}
394243730Srwatson
395243730Srwatsonstatic int
396243730Srwatsonreceiver_close(const char *filename)
397243730Srwatson{
398243730Srwatson
399243730Srwatson	/* We should have opened trail file. */
400243730Srwatson	if (adhost->adh_trail_fd == -1) {
401243730Srwatson		pjdlog_error("Sender requested closing file without first opening it.");
402243730Srwatson		return (ADIST_ERROR_WRONG_ORDER);
403243730Srwatson	}
404243730Srwatson
405243730Srwatson	/* Validate if we can do the rename. */
406243730Srwatson	if (!trail_validate_name(adhost->adh_trail_name, filename)) {
407243730Srwatson		pjdlog_error("Sender wants to close file \"%s\" using name \"%s\".",
408243730Srwatson		    adhost->adh_trail_name, filename);
409243730Srwatson		return (ADIST_ERROR_INVALID_NAME);
410243730Srwatson	}
411243730Srwatson
412243730Srwatson	PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
413243730Srwatson	adhost->adh_trail_fd = -1;
414243730Srwatson
415243730Srwatson	pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
416243730Srwatson	    adhost->adh_trail_name);
417243730Srwatson
418243730Srwatson	if (strcmp(adhost->adh_trail_name, filename) == 0) {
419243730Srwatson		/* File name didn't change, we are done here. */
420243730Srwatson		return (0);
421243730Srwatson	}
422243730Srwatson
423243730Srwatson	if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
424243730Srwatson	    adhost->adh_trail_dirfd, filename) == -1) {
425243730Srwatson		pjdlog_errno(LOG_ERR, "Unable to rename \"%s\" to \"%s\"",
426243730Srwatson		    adhost->adh_trail_name, filename);
427243730Srwatson		PJDLOG_ASSERT(errno > 0);
428243730Srwatson		return (ADIST_ERROR_RENAME);
429243730Srwatson	}
430243730Srwatson	pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".",
431243730Srwatson	    adhost->adh_directory, adhost->adh_trail_name,
432243730Srwatson	    adhost->adh_directory, filename);
433243730Srwatson	PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename,
434243730Srwatson	    sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name));
435243730Srwatson
436243730Srwatson	return (0);
437243730Srwatson}
438243730Srwatson
439243730Srwatsonstatic int
440243730Srwatsonreceiver_error(void)
441243730Srwatson{
442243730Srwatson
443243730Srwatson	/* We should have opened trail file. */
444243730Srwatson	if (adhost->adh_trail_fd == -1) {
445243730Srwatson		pjdlog_error("Sender send read error, but file is not open.");
446243730Srwatson		return (ADIST_ERROR_WRONG_ORDER);
447243730Srwatson	}
448243730Srwatson
449243730Srwatson	PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0);
450243730Srwatson	adhost->adh_trail_fd = -1;
451243730Srwatson
452243730Srwatson	pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory,
453243730Srwatson	    adhost->adh_trail_name);
454243730Srwatson
455243730Srwatson	return (0);
456243730Srwatson}
457243730Srwatson
458243730Srwatsonstatic void *
459243730Srwatsondisk_thread(void *arg __unused)
460243730Srwatson{
461243730Srwatson	struct adreq *adreq;
462243730Srwatson
463243730Srwatson	for (;;) {
464243730Srwatson		pjdlog_debug(3, "disk: Taking request.");
465243730Srwatson		QUEUE_TAKE(adreq, &adist_disk_list, 0);
466243730Srwatson		adreq_log(LOG_DEBUG, 3, -1, adreq, "disk: (%p) Got request: ",
467243730Srwatson		    adreq);
468243730Srwatson		/* Handle the actual request. */
469243730Srwatson		switch (adreq->adr_cmd) {
470243730Srwatson		case ADIST_CMD_OPEN:
471243730Srwatson			adreq->adr_error = receiver_open(adreq->adr_data);
472243730Srwatson			break;
473243730Srwatson		case ADIST_CMD_APPEND:
474243730Srwatson			adreq->adr_error = receiver_append(adreq->adr_data,
475243730Srwatson			    adreq->adr_datasize);
476243730Srwatson			break;
477243730Srwatson		case ADIST_CMD_CLOSE:
478243730Srwatson			adreq->adr_error = receiver_close(adreq->adr_data);
479243730Srwatson			break;
480243730Srwatson		case ADIST_CMD_ERROR:
481243730Srwatson			adreq->adr_error = receiver_error();
482243730Srwatson			break;
483243730Srwatson		default:
484243730Srwatson			PJDLOG_ABORT("Unexpected command (cmd=%hhu).",
485243730Srwatson			    adreq->adr_cmd);
486243730Srwatson		}
487243730Srwatson		if (adreq->adr_error != 0) {
488243730Srwatson			adreq_log(LOG_ERR, 0, adreq->adr_error, adreq,
489243730Srwatson			    "Request failed: ");
490243730Srwatson		}
491243730Srwatson		pjdlog_debug(3, "disk: (%p) Moving request to the send queue.",
492243730Srwatson		    adreq);
493243730Srwatson		QUEUE_INSERT(adreq, &adist_send_list);
494243730Srwatson	}
495243730Srwatson	/* NOTREACHED */
496243730Srwatson	return (NULL);
497243730Srwatson}
498243730Srwatson
499243730Srwatson/*
500243730Srwatson * Thread sends requests back to primary node.
501243730Srwatson */
502243730Srwatsonstatic void *
503243730Srwatsonsend_thread(void *arg __unused)
504243730Srwatson{
505243730Srwatson	struct adreq *adreq;
506243730Srwatson	struct adrep adrep;
507243730Srwatson
508243730Srwatson	for (;;) {
509243730Srwatson		pjdlog_debug(3, "send: Taking request.");
510243730Srwatson		QUEUE_TAKE(adreq, &adist_send_list, 0);
511243730Srwatson		adreq_log(LOG_DEBUG, 3, -1, adreq, "send: (%p) Got request: ",
512243730Srwatson		    adreq);
513243730Srwatson		adrep.adrp_byteorder = ADIST_BYTEORDER;
514243730Srwatson		adrep.adrp_seq = adreq->adr_seq;
515243730Srwatson		adrep.adrp_error = adreq->adr_error;
516243730Srwatson		if (proto_send(adhost->adh_remote, &adrep,
517243730Srwatson		    sizeof(adrep)) == -1) {
518243730Srwatson			pjdlog_exit(EX_TEMPFAIL, "Unable to send reply");
519243730Srwatson		}
520243730Srwatson		pjdlog_debug(3, "send: (%p) Moving request to the free queue.",
521243730Srwatson		    adreq);
522243730Srwatson		adreq_clear(adreq);
523243730Srwatson		QUEUE_INSERT(adreq, &adist_free_list);
524243730Srwatson	}
525243730Srwatson	/* NOTREACHED */
526243730Srwatson	return (NULL);
527243730Srwatson}
528243730Srwatson
529243730Srwatsonstatic void
530243730Srwatsonreceiver_directory_create(void)
531243730Srwatson{
532243730Srwatson	struct passwd *pw;
533243730Srwatson
534243730Srwatson	/*
535243730Srwatson	 * According to getpwnam(3) we have to clear errno before calling the
536243730Srwatson	 * function to be able to distinguish between an error and missing
537243730Srwatson	 * entry (with is not treated as error by getpwnam(3)).
538243730Srwatson	 */
539243730Srwatson	errno = 0;
540243730Srwatson	pw = getpwnam(ADIST_USER);
541243730Srwatson	if (pw == NULL) {
542243730Srwatson		if (errno != 0) {
543243730Srwatson			pjdlog_exit(EX_NOUSER,
544243730Srwatson			    "Unable to find info about '%s' user", ADIST_USER);
545243730Srwatson		} else {
546243730Srwatson			pjdlog_exitx(EX_NOUSER, "User '%s' doesn't exist.",
547243730Srwatson			    ADIST_USER);
548243730Srwatson		}
549243730Srwatson	}
550243730Srwatson
551243730Srwatson	if (mkdir(adhost->adh_directory, 0700) == -1) {
552243730Srwatson		pjdlog_exit(EX_OSFILE, "Unable to create directory \"%s\"",
553243730Srwatson		    adhost->adh_directory);
554243730Srwatson	}
555243730Srwatson	if (chown(adhost->adh_directory, pw->pw_uid, pw->pw_gid) == -1) {
556243730Srwatson		pjdlog_errno(LOG_ERR,
557243730Srwatson		    "Unable to change owner of the directory \"%s\"",
558243730Srwatson		    adhost->adh_directory);
559243730Srwatson		(void)rmdir(adhost->adh_directory);
560243730Srwatson		exit(EX_OSFILE);
561243730Srwatson	}
562243730Srwatson}
563243730Srwatson
564243730Srwatsonstatic void
565243730Srwatsonreceiver_directory_open(void)
566243730Srwatson{
567243730Srwatson
568243730Srwatson#ifdef HAVE_FDOPENDIR
569243730Srwatson	adhost->adh_trail_dirfd = open(adhost->adh_directory,
570243730Srwatson	    O_RDONLY | O_DIRECTORY);
571243730Srwatson	if (adhost->adh_trail_dirfd == -1) {
572243730Srwatson		if (errno == ENOENT) {
573243730Srwatson			receiver_directory_create();
574243730Srwatson			adhost->adh_trail_dirfd = open(adhost->adh_directory,
575243730Srwatson			    O_RDONLY | O_DIRECTORY);
576243730Srwatson		}
577243730Srwatson		if (adhost->adh_trail_dirfd == -1) {
578243730Srwatson			pjdlog_exit(EX_CONFIG,
579243730Srwatson			    "Unable to open directory \"%s\"",
580243730Srwatson			    adhost->adh_directory);
581243730Srwatson		}
582243730Srwatson	}
583243730Srwatson	adhost->adh_trail_dirfp = fdopendir(adhost->adh_trail_dirfd);
584243730Srwatson	if (adhost->adh_trail_dirfp == NULL) {
585243730Srwatson		pjdlog_exit(EX_CONFIG, "Unable to fdopen directory \"%s\"",
586243730Srwatson		    adhost->adh_directory);
587243730Srwatson	}
588243730Srwatson#else
589243730Srwatson	struct stat sb;
590243730Srwatson
591243730Srwatson	if (stat(adhost->adh_directory, &sb) == -1) {
592243730Srwatson		if (errno == ENOENT) {
593243730Srwatson			receiver_directory_create();
594243730Srwatson		} else {
595243730Srwatson			pjdlog_exit(EX_CONFIG,
596243730Srwatson			    "Unable to stat directory \"%s\"",
597243730Srwatson			    adhost->adh_directory);
598243730Srwatson		}
599243730Srwatson	}
600243730Srwatson	adhost->adh_trail_dirfp = opendir(adhost->adh_directory);
601243730Srwatson	if (adhost->adh_trail_dirfp == NULL) {
602243730Srwatson		pjdlog_exit(EX_CONFIG, "Unable to open directory \"%s\"",
603243730Srwatson		    adhost->adh_directory);
604243730Srwatson	}
605243730Srwatson	adhost->adh_trail_dirfd = dirfd(adhost->adh_trail_dirfp);
606243730Srwatson#endif
607243730Srwatson}
608243730Srwatson
609243730Srwatsonstatic void
610243730Srwatsonreceiver_connect(void)
611243730Srwatson{
612243730Srwatson	uint64_t trail_size;
613243730Srwatson	struct stat sb;
614243730Srwatson
615243730Srwatson	PJDLOG_ASSERT(adhost->adh_trail_dirfp != NULL);
616243730Srwatson
617243730Srwatson	trail_last(adhost->adh_trail_dirfp, adhost->adh_trail_name,
618243730Srwatson	    sizeof(adhost->adh_trail_name));
619243730Srwatson
620243730Srwatson	if (adhost->adh_trail_name[0] == '\0') {
621243730Srwatson		trail_size = 0;
622243730Srwatson	} else {
623243730Srwatson		if (fstatat(adhost->adh_trail_dirfd, adhost->adh_trail_name,
624243730Srwatson		    &sb, AT_SYMLINK_NOFOLLOW) == -1) {
625243730Srwatson			pjdlog_exit(EX_CONFIG, "Unable to stat \"%s/%s\"",
626243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name);
627243730Srwatson		}
628243730Srwatson		if (!S_ISREG(sb.st_mode)) {
629243730Srwatson			pjdlog_exitx(EX_CONFIG,
630243730Srwatson			    "File \"%s/%s\" is not a regular file.",
631243730Srwatson			    adhost->adh_directory, adhost->adh_trail_name);
632243730Srwatson		}
633243730Srwatson		trail_size = sb.st_size;
634243730Srwatson	}
635243730Srwatson	trail_size = htole64(trail_size);
636243730Srwatson	if (proto_send(adhost->adh_remote, &trail_size,
637243730Srwatson	    sizeof(trail_size)) == -1) {
638243730Srwatson		pjdlog_exit(EX_TEMPFAIL,
639243730Srwatson		    "Unable to send size of the most recent trail file");
640243730Srwatson	}
641243730Srwatson	if (proto_send(adhost->adh_remote, adhost->adh_trail_name,
642243730Srwatson	    sizeof(adhost->adh_trail_name)) == -1) {
643243730Srwatson		pjdlog_exit(EX_TEMPFAIL,
644243730Srwatson		    "Unable to send name of the most recent trail file");
645243730Srwatson	}
646243730Srwatson}
647243730Srwatson
648243730Srwatsonvoid
649243730Srwatsonadist_receiver(struct adist_config *config, struct adist_host *adh)
650243730Srwatson{
651243730Srwatson	sigset_t mask;
652243730Srwatson	pthread_t td;
653243730Srwatson	pid_t pid;
654243730Srwatson	int error, mode, debuglevel;
655243730Srwatson
656243730Srwatson	pid = fork();
657243730Srwatson	if (pid == -1) {
658243730Srwatson		pjdlog_errno(LOG_ERR, "Unable to fork");
659243730Srwatson		proto_close(adh->adh_remote);
660243730Srwatson		adh->adh_remote = NULL;
661243730Srwatson		return;
662243730Srwatson	}
663243730Srwatson
664243730Srwatson	if (pid > 0) {
665243730Srwatson		/* This is parent. */
666243730Srwatson		proto_close(adh->adh_remote);
667243730Srwatson		adh->adh_remote = NULL;
668243730Srwatson		adh->adh_worker_pid = pid;
669243730Srwatson		return;
670243730Srwatson	}
671243730Srwatson
672243730Srwatson	adcfg = config;
673243730Srwatson	adhost = adh;
674243730Srwatson	mode = pjdlog_mode_get();
675243730Srwatson	debuglevel = pjdlog_debug_get();
676243730Srwatson
677243730Srwatson	descriptors_cleanup(adhost);
678243730Srwatson
679243730Srwatson//	descriptors_assert(adhost, mode);
680243730Srwatson
681243730Srwatson	pjdlog_init(mode);
682243730Srwatson	pjdlog_debug_set(debuglevel);
683243730Srwatson	pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
684243730Srwatson	    role2str(adhost->adh_role));
685243730Srwatson#ifdef HAVE_SETPROCTITLE
686243730Srwatson	setproctitle("%s (%s)", adhost->adh_name, role2str(adhost->adh_role));
687243730Srwatson#endif
688243730Srwatson
689243730Srwatson	PJDLOG_VERIFY(sigemptyset(&mask) == 0);
690243730Srwatson	PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
691243730Srwatson
692243730Srwatson	/* Error in setting timeout is not critical, but why should it fail? */
693243730Srwatson	if (proto_timeout(adhost->adh_remote, adcfg->adc_timeout) == -1)
694243730Srwatson		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
695243730Srwatson
696243730Srwatson	init_environment();
697243730Srwatson
698243730Srwatson	adhost->adh_trail_fd = -1;
699243730Srwatson	receiver_directory_open();
700243730Srwatson
701243730Srwatson	if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)",
702243730Srwatson	    role2str(adhost->adh_role), adhost->adh_name) != 0) {
703243730Srwatson		exit(EX_CONFIG);
704243730Srwatson	}
705243730Srwatson	pjdlog_info("Privileges successfully dropped.");
706243730Srwatson
707243730Srwatson	receiver_connect();
708243730Srwatson
709243730Srwatson	error = pthread_create(&td, NULL, recv_thread, adhost);
710243730Srwatson	PJDLOG_ASSERT(error == 0);
711243730Srwatson	error = pthread_create(&td, NULL, disk_thread, adhost);
712243730Srwatson	PJDLOG_ASSERT(error == 0);
713243730Srwatson	(void)send_thread(adhost);
714243730Srwatson}
715