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
adreq_clear(struct adreq * adreq)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
init_environment(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
adreq_decode_and_validate_header(struct adreq * adreq)140 adreq_decode_and_validate_header(struct adreq *adreq)
141 {
142
143 /* Byte-swap only if 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
adreq_validate_data(const struct adreq * adreq)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 *
recv_thread(void * arg __unused)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
receiver_open(const char * filename)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
receiver_append(const unsigned char * data,size_t size)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
receiver_close(const char * filename)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
receiver_error(void)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 *
disk_thread(void * arg __unused)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 *
send_thread(void * arg __unused)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
receiver_directory_create(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
receiver_directory_open(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
receiver_connect(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
adist_receiver(struct adist_config * config,struct adist_host * adh)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 }
713