xref: /freebsd/contrib/openbsm/bin/auditdistd/sender.c (revision c6879c6c14eedbd060ba588a3129a6c60ebbe783)
1aa772005SRobert Watson /*-
2aa772005SRobert Watson  * Copyright (c) 2012 The FreeBSD Foundation
3aa772005SRobert Watson  * All rights reserved.
4aa772005SRobert Watson  *
5aa772005SRobert Watson  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6aa772005SRobert Watson  * the FreeBSD Foundation.
7aa772005SRobert Watson  *
8aa772005SRobert Watson  * Redistribution and use in source and binary forms, with or without
9aa772005SRobert Watson  * modification, are permitted provided that the following conditions
10aa772005SRobert Watson  * are met:
11aa772005SRobert Watson  * 1. Redistributions of source code must retain the above copyright
12aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer.
13aa772005SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
14aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
15aa772005SRobert Watson  *    documentation and/or other materials provided with the distribution.
16aa772005SRobert Watson  *
17aa772005SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18aa772005SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19aa772005SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20aa772005SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21aa772005SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22aa772005SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23aa772005SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24aa772005SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25aa772005SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26aa772005SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27aa772005SRobert Watson  * SUCH DAMAGE.
28aa772005SRobert Watson  */
29aa772005SRobert Watson 
30aa772005SRobert Watson #include <config/config.h>
31aa772005SRobert Watson 
32aa772005SRobert Watson #include <sys/param.h>
33aa772005SRobert Watson #if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP)
34aa772005SRobert Watson #include <sys/endian.h>
35aa772005SRobert Watson #else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
36aa772005SRobert Watson #ifdef HAVE_MACHINE_ENDIAN_H
37aa772005SRobert Watson #include <machine/endian.h>
38aa772005SRobert Watson #else /* !HAVE_MACHINE_ENDIAN_H */
39aa772005SRobert Watson #ifdef HAVE_ENDIAN_H
40aa772005SRobert Watson #include <endian.h>
41aa772005SRobert Watson #else /* !HAVE_ENDIAN_H */
42aa772005SRobert Watson #error "No supported endian.h"
43aa772005SRobert Watson #endif /* !HAVE_ENDIAN_H */
44aa772005SRobert Watson #endif /* !HAVE_MACHINE_ENDIAN_H */
45aa772005SRobert Watson #include <compat/endian.h>
46aa772005SRobert Watson #endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */
47aa772005SRobert Watson #include <sys/queue.h>
48aa772005SRobert Watson #include <sys/stat.h>
49aa772005SRobert Watson #include <sys/wait.h>
50aa772005SRobert Watson 
51aa772005SRobert Watson #include <stdio.h>
52aa772005SRobert Watson #include <stdlib.h>
53aa772005SRobert Watson #include <unistd.h>
54aa772005SRobert Watson 
55aa772005SRobert Watson #include <ctype.h>
56aa772005SRobert Watson #include <dirent.h>
57aa772005SRobert Watson #include <err.h>
58aa772005SRobert Watson #include <errno.h>
59aa772005SRobert Watson #include <fcntl.h>
60aa772005SRobert Watson #ifdef HAVE_LIBUTIL_H
61aa772005SRobert Watson #include <libutil.h>
62aa772005SRobert Watson #endif
63aa772005SRobert Watson #include <signal.h>
64aa772005SRobert Watson #include <string.h>
65aa772005SRobert Watson #include <strings.h>
66aa772005SRobert Watson 
67aa772005SRobert Watson #include <openssl/hmac.h>
68aa772005SRobert Watson 
69aa772005SRobert Watson #ifndef HAVE_SIGTIMEDWAIT
70aa772005SRobert Watson #include "sigtimedwait.h"
71aa772005SRobert Watson #endif
72aa772005SRobert Watson 
73aa772005SRobert Watson #include "auditdistd.h"
74aa772005SRobert Watson #include "pjdlog.h"
75aa772005SRobert Watson #include "proto.h"
76aa772005SRobert Watson #include "sandbox.h"
77aa772005SRobert Watson #include "subr.h"
78aa772005SRobert Watson #include "synch.h"
79aa772005SRobert Watson #include "trail.h"
80aa772005SRobert Watson 
81aa772005SRobert Watson static struct adist_config *adcfg;
82aa772005SRobert Watson static struct adist_host *adhost;
83aa772005SRobert Watson 
84aa772005SRobert Watson static pthread_rwlock_t adist_remote_lock;
85aa772005SRobert Watson static pthread_mutex_t adist_remote_mtx;
86aa772005SRobert Watson static pthread_cond_t adist_remote_cond;
87aa772005SRobert Watson static struct trail *adist_trail;
88aa772005SRobert Watson 
89aa772005SRobert Watson static TAILQ_HEAD(, adreq) adist_free_list;
90aa772005SRobert Watson static pthread_mutex_t adist_free_list_lock;
91aa772005SRobert Watson static pthread_cond_t adist_free_list_cond;
92aa772005SRobert Watson static TAILQ_HEAD(, adreq) adist_send_list;
93aa772005SRobert Watson static pthread_mutex_t adist_send_list_lock;
94aa772005SRobert Watson static pthread_cond_t adist_send_list_cond;
95aa772005SRobert Watson static TAILQ_HEAD(, adreq) adist_recv_list;
96aa772005SRobert Watson static pthread_mutex_t adist_recv_list_lock;
97aa772005SRobert Watson static pthread_cond_t adist_recv_list_cond;
98aa772005SRobert Watson 
99aa772005SRobert Watson static void
init_environment(void)100aa772005SRobert Watson init_environment(void)
101aa772005SRobert Watson {
102aa772005SRobert Watson 	struct adreq *adreq;
103aa772005SRobert Watson 	unsigned int ii;
104aa772005SRobert Watson 
105aa772005SRobert Watson 	rw_init(&adist_remote_lock);
106aa772005SRobert Watson 	mtx_init(&adist_remote_mtx);
107aa772005SRobert Watson 	cv_init(&adist_remote_cond);
108aa772005SRobert Watson 	TAILQ_INIT(&adist_free_list);
109aa772005SRobert Watson 	mtx_init(&adist_free_list_lock);
110aa772005SRobert Watson 	cv_init(&adist_free_list_cond);
111aa772005SRobert Watson 	TAILQ_INIT(&adist_send_list);
112aa772005SRobert Watson 	mtx_init(&adist_send_list_lock);
113aa772005SRobert Watson 	cv_init(&adist_send_list_cond);
114aa772005SRobert Watson 	TAILQ_INIT(&adist_recv_list);
115aa772005SRobert Watson 	mtx_init(&adist_recv_list_lock);
116aa772005SRobert Watson 	cv_init(&adist_recv_list_cond);
117aa772005SRobert Watson 
118aa772005SRobert Watson 	for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) {
119aa772005SRobert Watson 		adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE);
120aa772005SRobert Watson 		if (adreq == NULL) {
121aa772005SRobert Watson 			pjdlog_exitx(EX_TEMPFAIL,
122aa772005SRobert Watson 			    "Unable to allocate %zu bytes of memory for adreq object.",
123aa772005SRobert Watson 			    sizeof(*adreq) + ADIST_BUF_SIZE);
124aa772005SRobert Watson 		}
125aa772005SRobert Watson 		adreq->adr_byteorder = ADIST_BYTEORDER;
126aa772005SRobert Watson 		adreq->adr_cmd = ADIST_CMD_UNDEFINED;
127aa772005SRobert Watson 		adreq->adr_seq = 0;
128aa772005SRobert Watson 		adreq->adr_datasize = 0;
129aa772005SRobert Watson 		TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next);
130aa772005SRobert Watson 	}
131aa772005SRobert Watson }
132aa772005SRobert Watson 
133aa772005SRobert Watson static int
sender_connect(void)134aa772005SRobert Watson sender_connect(void)
135aa772005SRobert Watson {
136aa772005SRobert Watson 	unsigned char rnd[32], hash[32], resp[32];
137aa772005SRobert Watson 	struct proto_conn *conn;
138aa772005SRobert Watson 	char welcome[8];
139aa772005SRobert Watson 	int16_t val;
140aa772005SRobert Watson 
141aa772005SRobert Watson 	val = 1;
142aa772005SRobert Watson 	if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) {
143aa772005SRobert Watson 		pjdlog_exit(EX_TEMPFAIL,
144aa772005SRobert Watson 		    "Unable to send connection request to parent");
145aa772005SRobert Watson 	}
146aa772005SRobert Watson 	if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) {
147aa772005SRobert Watson 		pjdlog_exit(EX_TEMPFAIL,
148aa772005SRobert Watson 		    "Unable to receive reply to connection request from parent");
149aa772005SRobert Watson 	}
150aa772005SRobert Watson 	if (val != 0) {
151aa772005SRobert Watson 		errno = val;
152aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
153aa772005SRobert Watson 		    adhost->adh_remoteaddr);
154aa772005SRobert Watson 		return (-1);
155aa772005SRobert Watson 	}
156aa772005SRobert Watson 	if (proto_connection_recv(adhost->adh_conn, true, &conn) < 0) {
157aa772005SRobert Watson 		pjdlog_exit(EX_TEMPFAIL,
158aa772005SRobert Watson 		    "Unable to receive connection from parent");
159aa772005SRobert Watson 	}
160aa772005SRobert Watson 	if (proto_connect_wait(conn, adcfg->adc_timeout) < 0) {
161aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
162aa772005SRobert Watson 		    adhost->adh_remoteaddr);
163aa772005SRobert Watson 		proto_close(conn);
164aa772005SRobert Watson 		return (-1);
165aa772005SRobert Watson 	}
166aa772005SRobert Watson 	pjdlog_debug(1, "Connected to %s.", adhost->adh_remoteaddr);
167aa772005SRobert Watson 	/* Error in setting timeout is not critical, but why should it fail? */
168aa772005SRobert Watson 	if (proto_timeout(conn, adcfg->adc_timeout) < 0)
169aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
170aa772005SRobert Watson 	else
171aa772005SRobert Watson 		pjdlog_debug(1, "Timeout set to %d.", adcfg->adc_timeout);
172aa772005SRobert Watson 
173aa772005SRobert Watson 	/* Exchange welcome message, which includes version number. */
174aa772005SRobert Watson 	(void)snprintf(welcome, sizeof(welcome), "ADIST%02d", ADIST_VERSION);
175aa772005SRobert Watson 	if (proto_send(conn, welcome, sizeof(welcome)) < 0) {
176aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING,
177aa772005SRobert Watson 		    "Unable to send welcome message to %s",
178aa772005SRobert Watson 		    adhost->adh_remoteaddr);
179aa772005SRobert Watson 		proto_close(conn);
180aa772005SRobert Watson 		return (-1);
181aa772005SRobert Watson 	}
182aa772005SRobert Watson 	pjdlog_debug(1, "Welcome message sent (%s).", welcome);
183aa772005SRobert Watson 	bzero(welcome, sizeof(welcome));
184aa772005SRobert Watson 	if (proto_recv(conn, welcome, sizeof(welcome)) < 0) {
185aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING,
186aa772005SRobert Watson 		    "Unable to receive welcome message from %s",
187aa772005SRobert Watson 		    adhost->adh_remoteaddr);
188aa772005SRobert Watson 		proto_close(conn);
189aa772005SRobert Watson 		return (-1);
190aa772005SRobert Watson 	}
191aa772005SRobert Watson 	if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) ||
192aa772005SRobert Watson 	    !isdigit(welcome[6]) || welcome[7] != '\0') {
193aa772005SRobert Watson 		pjdlog_warning("Invalid welcome message from %s.",
194aa772005SRobert Watson 		    adhost->adh_remoteaddr);
195aa772005SRobert Watson 		proto_close(conn);
196aa772005SRobert Watson 		return (-1);
197aa772005SRobert Watson 	}
198aa772005SRobert Watson 	pjdlog_debug(1, "Welcome message received (%s).", welcome);
199aa772005SRobert Watson 	/*
200aa772005SRobert Watson 	 * Receiver can only reply with version number lower or equal to
201aa772005SRobert Watson 	 * the one we sent.
202aa772005SRobert Watson 	 */
203aa772005SRobert Watson 	adhost->adh_version = atoi(welcome + 5);
204aa772005SRobert Watson 	if (adhost->adh_version > ADIST_VERSION) {
205aa772005SRobert Watson 		pjdlog_warning("Invalid version number from %s (%d received, up to %d supported).",
206aa772005SRobert Watson 		    adhost->adh_remoteaddr, adhost->adh_version, ADIST_VERSION);
207aa772005SRobert Watson 		proto_close(conn);
208aa772005SRobert Watson 		return (-1);
209aa772005SRobert Watson 	}
210aa772005SRobert Watson 
211aa772005SRobert Watson 	pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version,
212aa772005SRobert Watson 	    adhost->adh_remoteaddr);
213aa772005SRobert Watson 
214aa772005SRobert Watson 	if (proto_send(conn, adcfg->adc_name, sizeof(adcfg->adc_name)) == -1) {
215aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to send name to %s",
216aa772005SRobert Watson 		    adhost->adh_remoteaddr);
217aa772005SRobert Watson 		proto_close(conn);
218aa772005SRobert Watson 		return (-1);
219aa772005SRobert Watson 	}
220aa772005SRobert Watson 	pjdlog_debug(1, "Name (%s) sent.", adcfg->adc_name);
221aa772005SRobert Watson 
222aa772005SRobert Watson 	if (proto_recv(conn, rnd, sizeof(rnd)) == -1) {
223aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to receive challenge from %s",
224aa772005SRobert Watson 		    adhost->adh_remoteaddr);
225aa772005SRobert Watson 		proto_close(conn);
226aa772005SRobert Watson 		return (-1);
227aa772005SRobert Watson 	}
228aa772005SRobert Watson 	pjdlog_debug(1, "Challenge received.");
229aa772005SRobert Watson 
230aa772005SRobert Watson 	if (HMAC(EVP_sha256(), adhost->adh_password,
231aa772005SRobert Watson 	    (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
232aa772005SRobert Watson 	    NULL) == NULL) {
233aa772005SRobert Watson 		pjdlog_warning("Unable to generate response.");
234aa772005SRobert Watson 		proto_close(conn);
235aa772005SRobert Watson 		return (-1);
236aa772005SRobert Watson 	}
237aa772005SRobert Watson 	pjdlog_debug(1, "Response generated.");
238aa772005SRobert Watson 
239aa772005SRobert Watson 	if (proto_send(conn, hash, sizeof(hash)) == -1) {
240aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to send response to %s",
241aa772005SRobert Watson 		    adhost->adh_remoteaddr);
242aa772005SRobert Watson 		proto_close(conn);
243aa772005SRobert Watson 		return (-1);
244aa772005SRobert Watson 	}
245aa772005SRobert Watson 	pjdlog_debug(1, "Response sent.");
246aa772005SRobert Watson 
247aa772005SRobert Watson 	if (adist_random(rnd, sizeof(rnd)) == -1) {
248aa772005SRobert Watson 		pjdlog_warning("Unable to generate challenge.");
249aa772005SRobert Watson 		proto_close(conn);
250aa772005SRobert Watson 		return (-1);
251aa772005SRobert Watson 	}
252aa772005SRobert Watson 	pjdlog_debug(1, "Challenge generated.");
253aa772005SRobert Watson 
254aa772005SRobert Watson 	if (proto_send(conn, rnd, sizeof(rnd)) == -1) {
255aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to send challenge to %s",
256aa772005SRobert Watson 		    adhost->adh_remoteaddr);
257aa772005SRobert Watson 		proto_close(conn);
258aa772005SRobert Watson 		return (-1);
259aa772005SRobert Watson 	}
260aa772005SRobert Watson 	pjdlog_debug(1, "Challenge sent.");
261aa772005SRobert Watson 
262aa772005SRobert Watson 	if (proto_recv(conn, resp, sizeof(resp)) == -1) {
263aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING, "Unable to receive response from %s",
264aa772005SRobert Watson 		    adhost->adh_remoteaddr);
265aa772005SRobert Watson 		proto_close(conn);
266aa772005SRobert Watson 		return (-1);
267aa772005SRobert Watson 	}
268aa772005SRobert Watson 	pjdlog_debug(1, "Response received.");
269aa772005SRobert Watson 
270aa772005SRobert Watson 	if (HMAC(EVP_sha256(), adhost->adh_password,
271aa772005SRobert Watson 	    (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
272aa772005SRobert Watson 	    NULL) == NULL) {
273aa772005SRobert Watson 		pjdlog_warning("Unable to generate hash.");
274aa772005SRobert Watson 		proto_close(conn);
275aa772005SRobert Watson 		return (-1);
276aa772005SRobert Watson 	}
277aa772005SRobert Watson 	pjdlog_debug(1, "Hash generated.");
278aa772005SRobert Watson 
279aa772005SRobert Watson 	if (memcmp(resp, hash, sizeof(hash)) != 0) {
280aa772005SRobert Watson 		pjdlog_warning("Invalid response from %s (wrong password?).",
281aa772005SRobert Watson 		    adhost->adh_remoteaddr);
282aa772005SRobert Watson 		proto_close(conn);
283aa772005SRobert Watson 		return (-1);
284aa772005SRobert Watson 	}
285aa772005SRobert Watson 	pjdlog_info("Receiver authenticated.");
286aa772005SRobert Watson 
287aa772005SRobert Watson 	if (proto_recv(conn, &adhost->adh_trail_offset,
288aa772005SRobert Watson 	    sizeof(adhost->adh_trail_offset)) == -1) {
289aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING,
290aa772005SRobert Watson 		    "Unable to receive size of the most recent trail file from %s",
291aa772005SRobert Watson 		    adhost->adh_remoteaddr);
292aa772005SRobert Watson 		proto_close(conn);
293aa772005SRobert Watson 		return (-1);
294aa772005SRobert Watson 	}
295aa772005SRobert Watson 	adhost->adh_trail_offset = le64toh(adhost->adh_trail_offset);
296aa772005SRobert Watson 	if (proto_recv(conn, &adhost->adh_trail_name,
297aa772005SRobert Watson 	    sizeof(adhost->adh_trail_name)) == -1) {
298aa772005SRobert Watson 		pjdlog_errno(LOG_WARNING,
299aa772005SRobert Watson 		    "Unable to receive name of the most recent trail file from %s",
300aa772005SRobert Watson 		    adhost->adh_remoteaddr);
301aa772005SRobert Watson 		proto_close(conn);
302aa772005SRobert Watson 		return (-1);
303aa772005SRobert Watson 	}
304aa772005SRobert Watson 	pjdlog_debug(1, "Trail name (%s) and offset (%ju) received.",
305aa772005SRobert Watson 	    adhost->adh_trail_name, (uintmax_t)adhost->adh_trail_offset);
306aa772005SRobert Watson 
307aa772005SRobert Watson 	rw_wlock(&adist_remote_lock);
308aa772005SRobert Watson 	mtx_lock(&adist_remote_mtx);
309aa772005SRobert Watson 	PJDLOG_ASSERT(adhost->adh_remote == NULL);
310aa772005SRobert Watson 	PJDLOG_ASSERT(conn != NULL);
311aa772005SRobert Watson 	adhost->adh_remote = conn;
312aa772005SRobert Watson 	mtx_unlock(&adist_remote_mtx);
313aa772005SRobert Watson 	rw_unlock(&adist_remote_lock);
314aa772005SRobert Watson 	cv_signal(&adist_remote_cond);
315aa772005SRobert Watson 
316aa772005SRobert Watson 	return (0);
317aa772005SRobert Watson }
318aa772005SRobert Watson 
319aa772005SRobert Watson static void
sender_disconnect(void)320aa772005SRobert Watson sender_disconnect(void)
321aa772005SRobert Watson {
322aa772005SRobert Watson 
323aa772005SRobert Watson 	rw_wlock(&adist_remote_lock);
324aa772005SRobert Watson 	/*
325aa772005SRobert Watson 	 * Check for a race between dropping rlock and acquiring wlock -
326aa772005SRobert Watson 	 * another thread can close connection in-between.
327aa772005SRobert Watson 	 */
328aa772005SRobert Watson 	if (adhost->adh_remote == NULL) {
329aa772005SRobert Watson 		rw_unlock(&adist_remote_lock);
330aa772005SRobert Watson 		return;
331aa772005SRobert Watson 	}
332aa772005SRobert Watson 	pjdlog_debug(2, "Closing connection to %s.", adhost->adh_remoteaddr);
333aa772005SRobert Watson 	proto_close(adhost->adh_remote);
334aa772005SRobert Watson 	mtx_lock(&adist_remote_mtx);
335aa772005SRobert Watson 	adhost->adh_remote = NULL;
336aa772005SRobert Watson 	adhost->adh_reset = true;
337aa772005SRobert Watson 	adhost->adh_trail_name[0] = '\0';
338aa772005SRobert Watson 	adhost->adh_trail_offset = 0;
339aa772005SRobert Watson 	mtx_unlock(&adist_remote_mtx);
340aa772005SRobert Watson 	rw_unlock(&adist_remote_lock);
341aa772005SRobert Watson 
342aa772005SRobert Watson 	pjdlog_warning("Disconnected from %s.", adhost->adh_remoteaddr);
343aa772005SRobert Watson 
344aa772005SRobert Watson 	/* Move all in-flight requests back onto free list. */
3450785e8ceSPawel Jakub Dawidek 	QUEUE_CONCAT2(&adist_free_list, &adist_send_list, &adist_recv_list);
346aa772005SRobert Watson }
347aa772005SRobert Watson 
348aa772005SRobert Watson static void
adreq_fill(struct adreq * adreq,uint8_t cmd,const unsigned char * data,size_t size)349aa772005SRobert Watson adreq_fill(struct adreq *adreq, uint8_t cmd, const unsigned char *data,
350aa772005SRobert Watson     size_t size)
351aa772005SRobert Watson {
352aa772005SRobert Watson 	static uint64_t seq = 1;
353aa772005SRobert Watson 
354aa772005SRobert Watson 	PJDLOG_ASSERT(size <= ADIST_BUF_SIZE);
355aa772005SRobert Watson 
356aa772005SRobert Watson 	switch (cmd) {
357aa772005SRobert Watson 	case ADIST_CMD_OPEN:
358aa772005SRobert Watson 	case ADIST_CMD_CLOSE:
359aa772005SRobert Watson 		PJDLOG_ASSERT(data != NULL && size == 0);
360aa772005SRobert Watson 		size = strlen(data) + 1;
361aa772005SRobert Watson 		break;
362aa772005SRobert Watson 	case ADIST_CMD_APPEND:
363aa772005SRobert Watson 		PJDLOG_ASSERT(data != NULL && size > 0);
364aa772005SRobert Watson 		break;
365aa772005SRobert Watson 	case ADIST_CMD_KEEPALIVE:
366aa772005SRobert Watson 	case ADIST_CMD_ERROR:
367aa772005SRobert Watson 		PJDLOG_ASSERT(data == NULL && size == 0);
368aa772005SRobert Watson 		break;
369aa772005SRobert Watson 	default:
370aa772005SRobert Watson 		PJDLOG_ABORT("Invalid command (%hhu).", cmd);
371aa772005SRobert Watson 	}
372aa772005SRobert Watson 
373aa772005SRobert Watson 	adreq->adr_cmd = cmd;
374aa772005SRobert Watson 	adreq->adr_seq = seq++;
375aa772005SRobert Watson 	adreq->adr_datasize = size;
376aa772005SRobert Watson 	/* Don't copy if data is already in out buffer. */
377aa772005SRobert Watson 	if (data != NULL && data != adreq->adr_data)
378aa772005SRobert Watson 		bcopy(data, adreq->adr_data, size);
379aa772005SRobert Watson }
380aa772005SRobert Watson 
381aa772005SRobert Watson static bool
read_thread_wait(void)382aa772005SRobert Watson read_thread_wait(void)
383aa772005SRobert Watson {
384aa772005SRobert Watson 	bool newfile = false;
385aa772005SRobert Watson 
386aa772005SRobert Watson 	mtx_lock(&adist_remote_mtx);
387aa772005SRobert Watson 	if (adhost->adh_reset) {
388a66ffea4SPawel Jakub Dawidek reset:
389aa772005SRobert Watson 		adhost->adh_reset = false;
390aa772005SRobert Watson 		if (trail_filefd(adist_trail) != -1)
391aa772005SRobert Watson 			trail_close(adist_trail);
392aa772005SRobert Watson 		trail_reset(adist_trail);
393aa772005SRobert Watson 		while (adhost->adh_remote == NULL)
394aa772005SRobert Watson 			cv_wait(&adist_remote_cond, &adist_remote_mtx);
395aa772005SRobert Watson 		trail_start(adist_trail, adhost->adh_trail_name,
396aa772005SRobert Watson 		    adhost->adh_trail_offset);
397aa772005SRobert Watson 		newfile = true;
398aa772005SRobert Watson 	}
399aa772005SRobert Watson 	mtx_unlock(&adist_remote_mtx);
400aa772005SRobert Watson 	while (trail_filefd(adist_trail) == -1) {
401aa772005SRobert Watson 		newfile = true;
402aa772005SRobert Watson 		wait_for_dir();
403a66ffea4SPawel Jakub Dawidek 		/*
404a66ffea4SPawel Jakub Dawidek 		 * We may have been disconnected and reconnected in the
405a66ffea4SPawel Jakub Dawidek 		 * meantime, check if reset is set.
406a66ffea4SPawel Jakub Dawidek 		 */
407a66ffea4SPawel Jakub Dawidek 		mtx_lock(&adist_remote_mtx);
408a66ffea4SPawel Jakub Dawidek 		if (adhost->adh_reset)
409a66ffea4SPawel Jakub Dawidek 			goto reset;
410a66ffea4SPawel Jakub Dawidek 		mtx_unlock(&adist_remote_mtx);
411aa772005SRobert Watson 		if (trail_filefd(adist_trail) == -1)
412aa772005SRobert Watson 			trail_next(adist_trail);
413aa772005SRobert Watson 	}
414aa772005SRobert Watson 	if (newfile) {
415aa772005SRobert Watson 		pjdlog_debug(1, "Trail file \"%s/%s\" opened.",
416aa772005SRobert Watson 		    adhost->adh_directory,
417aa772005SRobert Watson 		    trail_filename(adist_trail));
418aa772005SRobert Watson 		(void)wait_for_file_init(trail_filefd(adist_trail));
419aa772005SRobert Watson 	}
420aa772005SRobert Watson 	return (newfile);
421aa772005SRobert Watson }
422aa772005SRobert Watson 
423aa772005SRobert Watson static void *
read_thread(void * arg __unused)424aa772005SRobert Watson read_thread(void *arg __unused)
425aa772005SRobert Watson {
426aa772005SRobert Watson 	struct adreq *adreq;
427aa772005SRobert Watson 	ssize_t done;
428aa772005SRobert Watson 	bool newfile;
429aa772005SRobert Watson 
430aa772005SRobert Watson 	pjdlog_debug(1, "%s started.", __func__);
431aa772005SRobert Watson 
432aa772005SRobert Watson 	for (;;) {
433aa772005SRobert Watson 		newfile = read_thread_wait();
434aa772005SRobert Watson 		QUEUE_TAKE(adreq, &adist_free_list, 0);
435aa772005SRobert Watson 		if (newfile) {
436aa772005SRobert Watson 			adreq_fill(adreq, ADIST_CMD_OPEN,
437aa772005SRobert Watson 			    trail_filename(adist_trail), 0);
438aa772005SRobert Watson 			newfile = false;
439aa772005SRobert Watson 			goto move;
440aa772005SRobert Watson 		}
441aa772005SRobert Watson 
442aa772005SRobert Watson 		done = read(trail_filefd(adist_trail), adreq->adr_data,
443aa772005SRobert Watson 		    ADIST_BUF_SIZE);
444aa772005SRobert Watson 		if (done == -1) {
445aa772005SRobert Watson 			off_t offset;
446aa772005SRobert Watson 			int error;
447aa772005SRobert Watson 
448aa772005SRobert Watson 			error = errno;
449aa772005SRobert Watson 			offset = lseek(trail_filefd(adist_trail), 0, SEEK_CUR);
450aa772005SRobert Watson 			errno = error;
451aa772005SRobert Watson 			pjdlog_errno(LOG_ERR,
452aa772005SRobert Watson 			    "Error while reading \"%s/%s\" at offset %jd",
453aa772005SRobert Watson 			    adhost->adh_directory, trail_filename(adist_trail),
454aa772005SRobert Watson 			    offset);
455aa772005SRobert Watson 			trail_close(adist_trail);
456aa772005SRobert Watson 			adreq_fill(adreq, ADIST_CMD_ERROR, NULL, 0);
457aa772005SRobert Watson 			goto move;
458aa772005SRobert Watson 		} else if (done == 0) {
459aa772005SRobert Watson 			/* End of file. */
460aa772005SRobert Watson 			pjdlog_debug(3, "End of \"%s/%s\".",
461aa772005SRobert Watson 			    adhost->adh_directory, trail_filename(adist_trail));
462aa772005SRobert Watson 			if (!trail_switch(adist_trail)) {
463aa772005SRobert Watson 				/* More audit records can arrive. */
464aa772005SRobert Watson 				mtx_lock(&adist_free_list_lock);
465aa772005SRobert Watson 				TAILQ_INSERT_TAIL(&adist_free_list, adreq,
466aa772005SRobert Watson 				    adr_next);
467aa772005SRobert Watson 				mtx_unlock(&adist_free_list_lock);
468aa772005SRobert Watson 				wait_for_file();
469aa772005SRobert Watson 				continue;
470aa772005SRobert Watson 			}
471aa772005SRobert Watson 			adreq_fill(adreq, ADIST_CMD_CLOSE,
472aa772005SRobert Watson 			    trail_filename(adist_trail), 0);
473aa772005SRobert Watson 			trail_close(adist_trail);
474aa772005SRobert Watson 			goto move;
475aa772005SRobert Watson 		}
476aa772005SRobert Watson 
477aa772005SRobert Watson 		adreq_fill(adreq, ADIST_CMD_APPEND, adreq->adr_data, done);
478aa772005SRobert Watson move:
479aa772005SRobert Watson 		pjdlog_debug(3,
480aa772005SRobert Watson 		    "read thread: Moving request %p to the send queue (%hhu).",
481aa772005SRobert Watson 		    adreq, adreq->adr_cmd);
482aa772005SRobert Watson 		QUEUE_INSERT(adreq, &adist_send_list);
483aa772005SRobert Watson 	}
484aa772005SRobert Watson 	/* NOTREACHED */
485aa772005SRobert Watson 	return (NULL);
486aa772005SRobert Watson }
487aa772005SRobert Watson 
488aa772005SRobert Watson static void
keepalive_send(void)489aa772005SRobert Watson keepalive_send(void)
490aa772005SRobert Watson {
491aa772005SRobert Watson 	struct adreq *adreq;
492aa772005SRobert Watson 
493aa772005SRobert Watson 	rw_rlock(&adist_remote_lock);
494aa772005SRobert Watson 	if (adhost->adh_remote == NULL) {
495aa772005SRobert Watson 		rw_unlock(&adist_remote_lock);
496aa772005SRobert Watson 		return;
497aa772005SRobert Watson 	}
498aa772005SRobert Watson 	rw_unlock(&adist_remote_lock);
499aa772005SRobert Watson 
500aa772005SRobert Watson 	mtx_lock(&adist_free_list_lock);
501aa772005SRobert Watson 	adreq = TAILQ_FIRST(&adist_free_list);
502aa772005SRobert Watson 	if (adreq != NULL)
503aa772005SRobert Watson 		TAILQ_REMOVE(&adist_free_list, adreq, adr_next);
504aa772005SRobert Watson 	mtx_unlock(&adist_free_list_lock);
505aa772005SRobert Watson 	if (adreq == NULL)
506aa772005SRobert Watson 		return;
507aa772005SRobert Watson 
508aa772005SRobert Watson 	adreq_fill(adreq, ADIST_CMD_KEEPALIVE, NULL, 0);
509aa772005SRobert Watson 
510aa772005SRobert Watson 	QUEUE_INSERT(adreq, &adist_send_list);
511aa772005SRobert Watson 
512aa772005SRobert Watson 	pjdlog_debug(3, "keepalive_send: Request sent.");
513aa772005SRobert Watson }
514aa772005SRobert Watson 
515aa772005SRobert Watson static void *
send_thread(void * arg __unused)516aa772005SRobert Watson send_thread(void *arg __unused)
517aa772005SRobert Watson {
518aa772005SRobert Watson 	time_t lastcheck, now;
519aa772005SRobert Watson 	struct adreq *adreq;
520aa772005SRobert Watson 
521aa772005SRobert Watson 	pjdlog_debug(1, "%s started.", __func__);
522aa772005SRobert Watson 
523aa772005SRobert Watson 	lastcheck = time(NULL);
524aa772005SRobert Watson 
525aa772005SRobert Watson 	for (;;) {
526aa772005SRobert Watson 		pjdlog_debug(3, "send thread: Taking request.");
527aa772005SRobert Watson 		for (;;) {
528aa772005SRobert Watson 			QUEUE_TAKE(adreq, &adist_send_list, ADIST_KEEPALIVE);
529aa772005SRobert Watson 			if (adreq != NULL)
530aa772005SRobert Watson 				break;
531aa772005SRobert Watson 			now = time(NULL);
532aa772005SRobert Watson 			if (lastcheck + ADIST_KEEPALIVE <= now) {
533aa772005SRobert Watson 				keepalive_send();
534aa772005SRobert Watson 				lastcheck = now;
535aa772005SRobert Watson 			}
536aa772005SRobert Watson 		}
537aa772005SRobert Watson 		PJDLOG_ASSERT(adreq != NULL);
538aa772005SRobert Watson 		pjdlog_debug(3, "send thread: (%p) Got request %hhu.", adreq,
539aa772005SRobert Watson 		    adreq->adr_cmd);
540aa772005SRobert Watson 		/*
541aa772005SRobert Watson 		 * Protect connection from disappearing.
542aa772005SRobert Watson 		 */
543aa772005SRobert Watson 		rw_rlock(&adist_remote_lock);
544aa772005SRobert Watson 		/*
545aa772005SRobert Watson 		 * Move the request to the recv queue first to avoid race
546aa772005SRobert Watson 		 * where the recv thread receives the reply before we move
547aa772005SRobert Watson 		 * the request to the recv queue.
548aa772005SRobert Watson 		 */
549aa772005SRobert Watson 		QUEUE_INSERT(adreq, &adist_recv_list);
550aa772005SRobert Watson 		if (adhost->adh_remote == NULL ||
551aa772005SRobert Watson 		    proto_send(adhost->adh_remote, &adreq->adr_packet,
552aa772005SRobert Watson 		    ADPKT_SIZE(adreq)) == -1) {
553aa772005SRobert Watson 			rw_unlock(&adist_remote_lock);
554aa772005SRobert Watson 			pjdlog_debug(1,
555aa772005SRobert Watson 			    "send thread: (%p) Unable to send request.", adreq);
556aa772005SRobert Watson 			if (adhost->adh_remote != NULL)
557aa772005SRobert Watson 				sender_disconnect();
558aa772005SRobert Watson 			continue;
559aa772005SRobert Watson 		} else {
560aa772005SRobert Watson 			pjdlog_debug(3, "Request %p sent successfully.", adreq);
561aa772005SRobert Watson 			adreq_log(LOG_DEBUG, 2, -1, adreq,
562aa772005SRobert Watson 			    "send: (%p) Request sent: ", adreq);
563aa772005SRobert Watson 			rw_unlock(&adist_remote_lock);
564aa772005SRobert Watson 		}
565aa772005SRobert Watson 	}
566aa772005SRobert Watson 	/* NOTREACHED */
567aa772005SRobert Watson 	return (NULL);
568aa772005SRobert Watson }
569aa772005SRobert Watson 
570aa772005SRobert Watson static void
adrep_decode_header(struct adrep * adrep)571aa772005SRobert Watson adrep_decode_header(struct adrep *adrep)
572aa772005SRobert Watson {
573aa772005SRobert Watson 
574*58554c8dSPawel Jakub Dawidek 	/* Byte-swap only if the receiver is using different byte order. */
575aa772005SRobert Watson 	if (adrep->adrp_byteorder != ADIST_BYTEORDER) {
576aa772005SRobert Watson 		adrep->adrp_byteorder = ADIST_BYTEORDER;
577aa772005SRobert Watson 		adrep->adrp_seq = bswap64(adrep->adrp_seq);
578aa772005SRobert Watson 		adrep->adrp_error = bswap16(adrep->adrp_error);
579aa772005SRobert Watson 	}
580aa772005SRobert Watson }
581aa772005SRobert Watson 
582aa772005SRobert Watson static void *
recv_thread(void * arg __unused)583aa772005SRobert Watson recv_thread(void *arg __unused)
584aa772005SRobert Watson {
585aa772005SRobert Watson 	struct adrep adrep;
586aa772005SRobert Watson 	struct adreq *adreq;
587aa772005SRobert Watson 
588aa772005SRobert Watson 	pjdlog_debug(1, "%s started.", __func__);
589aa772005SRobert Watson 
590aa772005SRobert Watson 	for (;;) {
591aa772005SRobert Watson 		/* Wait until there is anything to receive. */
592aa772005SRobert Watson 		QUEUE_WAIT(&adist_recv_list);
593aa772005SRobert Watson 		pjdlog_debug(3, "recv thread: Got something.");
594aa772005SRobert Watson 		rw_rlock(&adist_remote_lock);
595aa772005SRobert Watson 		if (adhost->adh_remote == NULL) {
596aa772005SRobert Watson 			/*
597aa772005SRobert Watson 			 * Connection is dead.
5980785e8ceSPawel Jakub Dawidek 			 * There is a short race in sender_disconnect() between
5990785e8ceSPawel Jakub Dawidek 			 * setting adh_remote to NULL and removing entries from
6000785e8ceSPawel Jakub Dawidek 			 * the recv list, which can result in us being here.
6010785e8ceSPawel Jakub Dawidek 			 * To avoid just spinning, wait for 0.1s.
602aa772005SRobert Watson 			 */
603aa772005SRobert Watson 			rw_unlock(&adist_remote_lock);
6040785e8ceSPawel Jakub Dawidek 			usleep(100000);
605aa772005SRobert Watson 			continue;
606aa772005SRobert Watson 		}
607aa772005SRobert Watson 		if (proto_recv(adhost->adh_remote, &adrep,
608aa772005SRobert Watson 		    sizeof(adrep)) == -1) {
609aa772005SRobert Watson 			rw_unlock(&adist_remote_lock);
610aa772005SRobert Watson 			pjdlog_errno(LOG_ERR, "Unable to receive reply");
611aa772005SRobert Watson 			sender_disconnect();
612aa772005SRobert Watson 			continue;
613aa772005SRobert Watson 		}
614aa772005SRobert Watson 		rw_unlock(&adist_remote_lock);
615aa772005SRobert Watson 		adrep_decode_header(&adrep);
616aa772005SRobert Watson 		/*
617aa772005SRobert Watson 		 * Find the request that was just confirmed.
618aa772005SRobert Watson 		 */
619aa772005SRobert Watson 		mtx_lock(&adist_recv_list_lock);
620aa772005SRobert Watson 		TAILQ_FOREACH(adreq, &adist_recv_list, adr_next) {
621aa772005SRobert Watson 			if (adreq->adr_seq == adrep.adrp_seq) {
622aa772005SRobert Watson 				TAILQ_REMOVE(&adist_recv_list, adreq,
623aa772005SRobert Watson 				    adr_next);
624aa772005SRobert Watson 				break;
625aa772005SRobert Watson 			}
626aa772005SRobert Watson 		}
627aa772005SRobert Watson 		if (adreq == NULL) {
628aa772005SRobert Watson 			/*
629aa772005SRobert Watson 			 * If we disconnected in the meantime, just continue.
630aa772005SRobert Watson 			 * On disconnect sender_disconnect() clears the queue,
631aa772005SRobert Watson 			 * we can use that.
632aa772005SRobert Watson 			 */
633aa772005SRobert Watson 			if (TAILQ_EMPTY(&adist_recv_list)) {
6344f6aec90SEd Schouten 				mtx_unlock(&adist_recv_list_lock);
635aa772005SRobert Watson 				continue;
636aa772005SRobert Watson 			}
637aa772005SRobert Watson 			mtx_unlock(&adist_recv_list_lock);
638aa772005SRobert Watson 			pjdlog_error("Found no request matching received 'seq' field (%ju).",
639aa772005SRobert Watson 			    (uintmax_t)adrep.adrp_seq);
640aa772005SRobert Watson 			sender_disconnect();
641aa772005SRobert Watson 			continue;
642aa772005SRobert Watson 		}
643aa772005SRobert Watson 		mtx_unlock(&adist_recv_list_lock);
644aa772005SRobert Watson 		adreq_log(LOG_DEBUG, 2, -1, adreq,
645aa772005SRobert Watson 		    "recv thread: (%p) Request confirmed: ", adreq);
646aa772005SRobert Watson 		pjdlog_debug(3, "recv thread: (%p) Got request %hhu.", adreq,
647aa772005SRobert Watson 		    adreq->adr_cmd);
648aa772005SRobert Watson 		if (adrep.adrp_error != 0) {
649aa772005SRobert Watson 			pjdlog_error("Receiver returned error (%s), disconnecting.",
650aa772005SRobert Watson 			    adist_errstr((int)adrep.adrp_error));
651aa772005SRobert Watson 			sender_disconnect();
652aa772005SRobert Watson 			continue;
653aa772005SRobert Watson 		}
654aa772005SRobert Watson 		if (adreq->adr_cmd == ADIST_CMD_CLOSE)
655aa772005SRobert Watson 			trail_unlink(adist_trail, adreq->adr_data);
656aa772005SRobert Watson 		pjdlog_debug(3, "Request received successfully.");
657aa772005SRobert Watson 		QUEUE_INSERT(adreq, &adist_free_list);
658aa772005SRobert Watson 	}
659aa772005SRobert Watson 	/* NOTREACHED */
660aa772005SRobert Watson 	return (NULL);
661aa772005SRobert Watson }
662aa772005SRobert Watson 
663aa772005SRobert Watson static void
guard_check_connection(void)664aa772005SRobert Watson guard_check_connection(void)
665aa772005SRobert Watson {
666aa772005SRobert Watson 
667aa772005SRobert Watson 	PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
668aa772005SRobert Watson 
669aa772005SRobert Watson 	rw_rlock(&adist_remote_lock);
670aa772005SRobert Watson 	if (adhost->adh_remote != NULL) {
671aa772005SRobert Watson 		rw_unlock(&adist_remote_lock);
672aa772005SRobert Watson 		pjdlog_debug(3, "remote_guard: Connection to %s is ok.",
673aa772005SRobert Watson 		    adhost->adh_remoteaddr);
674aa772005SRobert Watson 		return;
675aa772005SRobert Watson 	}
676aa772005SRobert Watson 
677aa772005SRobert Watson 	/*
678aa772005SRobert Watson 	 * Upgrade the lock. It doesn't have to be atomic as no other thread
679aa772005SRobert Watson 	 * can change connection status from disconnected to connected.
680aa772005SRobert Watson 	 */
681aa772005SRobert Watson 	rw_unlock(&adist_remote_lock);
682aa772005SRobert Watson 	pjdlog_debug(1, "remote_guard: Reconnecting to %s.",
683aa772005SRobert Watson 	    adhost->adh_remoteaddr);
684aa772005SRobert Watson 	if (sender_connect() == 0) {
685aa772005SRobert Watson 		pjdlog_info("Successfully reconnected to %s.",
686aa772005SRobert Watson 		    adhost->adh_remoteaddr);
687aa772005SRobert Watson 	} else {
688aa772005SRobert Watson 		pjdlog_debug(1, "remote_guard: Reconnect to %s failed.",
689aa772005SRobert Watson 		    adhost->adh_remoteaddr);
690aa772005SRobert Watson 	}
691aa772005SRobert Watson }
692aa772005SRobert Watson 
693aa772005SRobert Watson /*
694aa772005SRobert Watson  * Thread guards remote connections and reconnects when needed, handles
695aa772005SRobert Watson  * signals, etc.
696aa772005SRobert Watson  */
697aa772005SRobert Watson static void *
guard_thread(void * arg __unused)698aa772005SRobert Watson guard_thread(void *arg __unused)
699aa772005SRobert Watson {
700aa772005SRobert Watson 	struct timespec timeout;
701aa772005SRobert Watson 	time_t lastcheck, now;
702aa772005SRobert Watson 	sigset_t mask;
703aa772005SRobert Watson 	int signo;
704aa772005SRobert Watson 
705aa772005SRobert Watson 	lastcheck = time(NULL);
706aa772005SRobert Watson 
707aa772005SRobert Watson 	PJDLOG_VERIFY(sigemptyset(&mask) == 0);
708aa772005SRobert Watson 	PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
709aa772005SRobert Watson 	PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
710aa772005SRobert Watson 
711aa772005SRobert Watson 	timeout.tv_sec = ADIST_KEEPALIVE;
712aa772005SRobert Watson 	timeout.tv_nsec = 0;
713aa772005SRobert Watson 	signo = -1;
714aa772005SRobert Watson 
715aa772005SRobert Watson 	for (;;) {
716aa772005SRobert Watson 		switch (signo) {
717aa772005SRobert Watson 		case SIGINT:
718aa772005SRobert Watson 		case SIGTERM:
719aa772005SRobert Watson 			sigexit_received = true;
720aa772005SRobert Watson 			pjdlog_exitx(EX_OK,
721aa772005SRobert Watson 			    "Termination signal received, exiting.");
722aa772005SRobert Watson 			break;
723aa772005SRobert Watson 		default:
724aa772005SRobert Watson 			break;
725aa772005SRobert Watson 		}
726aa772005SRobert Watson 
727aa772005SRobert Watson 		pjdlog_debug(3, "remote_guard: Checking connections.");
728aa772005SRobert Watson 		now = time(NULL);
729aa772005SRobert Watson 		if (lastcheck + ADIST_KEEPALIVE <= now) {
730aa772005SRobert Watson 			guard_check_connection();
731aa772005SRobert Watson 			lastcheck = now;
732aa772005SRobert Watson 		}
733aa772005SRobert Watson 		signo = sigtimedwait(&mask, NULL, &timeout);
734aa772005SRobert Watson 	}
735aa772005SRobert Watson 	/* NOTREACHED */
736aa772005SRobert Watson 	return (NULL);
737aa772005SRobert Watson }
738aa772005SRobert Watson 
739aa772005SRobert Watson void
adist_sender(struct adist_config * config,struct adist_host * adh)740aa772005SRobert Watson adist_sender(struct adist_config *config, struct adist_host *adh)
741aa772005SRobert Watson {
742aa772005SRobert Watson 	pthread_t td;
743aa772005SRobert Watson 	pid_t pid;
744aa772005SRobert Watson 	int error, mode, debuglevel;
745aa772005SRobert Watson 
746aa772005SRobert Watson 	/*
747aa772005SRobert Watson 	 * Create communication channel for sending connection requests from
748aa772005SRobert Watson 	 * child to parent.
749aa772005SRobert Watson 	 */
750aa772005SRobert Watson 	if (proto_connect(NULL, "socketpair://", -1, &adh->adh_conn) == -1) {
751aa772005SRobert Watson 		pjdlog_errno(LOG_ERR,
752aa772005SRobert Watson 		    "Unable to create connection sockets between child and parent");
753aa772005SRobert Watson 		return;
754aa772005SRobert Watson 	}
755aa772005SRobert Watson 
756aa772005SRobert Watson 	pid = fork();
757aa772005SRobert Watson 	if (pid == -1) {
758aa772005SRobert Watson 		pjdlog_errno(LOG_ERR, "Unable to fork");
759aa772005SRobert Watson 		proto_close(adh->adh_conn);
760aa772005SRobert Watson 		adh->adh_conn = NULL;
761aa772005SRobert Watson 		return;
762aa772005SRobert Watson 	}
763aa772005SRobert Watson 
764aa772005SRobert Watson 	if (pid > 0) {
765aa772005SRobert Watson 		/* This is parent. */
766aa772005SRobert Watson 		adh->adh_worker_pid = pid;
767aa772005SRobert Watson 		/* Declare that we are receiver. */
768aa772005SRobert Watson 		proto_recv(adh->adh_conn, NULL, 0);
769aa772005SRobert Watson 		return;
770aa772005SRobert Watson 	}
771aa772005SRobert Watson 
772aa772005SRobert Watson 	adcfg = config;
773aa772005SRobert Watson 	adhost = adh;
774aa772005SRobert Watson 
775aa772005SRobert Watson 	mode = pjdlog_mode_get();
776aa772005SRobert Watson 	debuglevel = pjdlog_debug_get();
777aa772005SRobert Watson 
778aa772005SRobert Watson 	/* Declare that we are sender. */
779aa772005SRobert Watson 	proto_send(adhost->adh_conn, NULL, 0);
780aa772005SRobert Watson 
781aa772005SRobert Watson 	descriptors_cleanup(adhost);
782aa772005SRobert Watson 
783aa772005SRobert Watson #ifdef TODO
784aa772005SRobert Watson 	descriptors_assert(adhost, mode);
785aa772005SRobert Watson #endif
786aa772005SRobert Watson 
787aa772005SRobert Watson 	pjdlog_init(mode);
788aa772005SRobert Watson 	pjdlog_debug_set(debuglevel);
789aa772005SRobert Watson 	pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
790aa772005SRobert Watson 	    role2str(adhost->adh_role));
791aa772005SRobert Watson #ifdef HAVE_SETPROCTITLE
792aa772005SRobert Watson 	setproctitle("[%s] (%s) ", adhost->adh_name,
793aa772005SRobert Watson 	    role2str(adhost->adh_role));
794aa772005SRobert Watson #endif
795aa772005SRobert Watson 
796aa772005SRobert Watson 	/*
797aa772005SRobert Watson 	 * The sender process should be able to remove entries from its
798aa772005SRobert Watson 	 * trail directory, but it should not be able to write to the
799aa772005SRobert Watson 	 * trail files, only read from them.
800aa772005SRobert Watson 	 */
801aa772005SRobert Watson 	adist_trail = trail_new(adhost->adh_directory, false);
802aa772005SRobert Watson 	if (adist_trail == NULL)
803aa772005SRobert Watson 		exit(EX_OSFILE);
804aa772005SRobert Watson 
805aa772005SRobert Watson 	if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)",
806aa772005SRobert Watson 	    role2str(adhost->adh_role), adhost->adh_name) != 0) {
807aa772005SRobert Watson 		exit(EX_CONFIG);
808aa772005SRobert Watson 	}
809aa772005SRobert Watson 	pjdlog_info("Privileges successfully dropped.");
810aa772005SRobert Watson 
811aa772005SRobert Watson 	/*
812aa772005SRobert Watson 	 * We can ignore wait_for_dir_init() failures. It will fall back to
813aa772005SRobert Watson 	 * using sleep(3).
814aa772005SRobert Watson 	 */
815aa772005SRobert Watson 	(void)wait_for_dir_init(trail_dirfd(adist_trail));
816aa772005SRobert Watson 
817aa772005SRobert Watson 	init_environment();
818aa772005SRobert Watson 	if (sender_connect() == 0) {
819aa772005SRobert Watson 		pjdlog_info("Successfully connected to %s.",
820aa772005SRobert Watson 		    adhost->adh_remoteaddr);
821aa772005SRobert Watson 	}
822aa772005SRobert Watson 	adhost->adh_reset = true;
823aa772005SRobert Watson 
824aa772005SRobert Watson 	/*
825aa772005SRobert Watson 	 * Create the guard thread first, so we can handle signals from the
826aa772005SRobert Watson 	 * very begining.
827aa772005SRobert Watson 	 */
828aa772005SRobert Watson 	error = pthread_create(&td, NULL, guard_thread, NULL);
829aa772005SRobert Watson 	PJDLOG_ASSERT(error == 0);
830aa772005SRobert Watson 	error = pthread_create(&td, NULL, send_thread, NULL);
831aa772005SRobert Watson 	PJDLOG_ASSERT(error == 0);
832aa772005SRobert Watson 	error = pthread_create(&td, NULL, recv_thread, NULL);
833aa772005SRobert Watson 	PJDLOG_ASSERT(error == 0);
834aa772005SRobert Watson 	(void)read_thread(NULL);
835aa772005SRobert Watson }
836