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 } 713