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