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