receiver.c revision 256281
1234285Sdim/*- 2234285Sdim * Copyright (c) 2012 The FreeBSD Foundation 3234285Sdim * All rights reserved. 4234285Sdim * 5234285Sdim * This software was developed by Pawel Jakub Dawidek under sponsorship from 6234285Sdim * the FreeBSD Foundation. 7234285Sdim * 8234285Sdim * Redistribution and use in source and binary forms, with or without 9234285Sdim * modification, are permitted provided that the following conditions 10234285Sdim * are met: 11234285Sdim * 1. Redistributions of source code must retain the above copyright 12234285Sdim * notice, this list of conditions and the following disclaimer. 13234285Sdim * 2. Redistributions in binary form must reproduce the above copyright 14234285Sdim * notice, this list of conditions and the following disclaimer in the 15234285Sdim * documentation and/or other materials provided with the distribution. 16234285Sdim * 17234285Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18234285Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19234285Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20234285Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21234285Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22234285Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23234285Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26234285Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27234285Sdim * SUCH DAMAGE. 28234285Sdim * 29249423Sdim * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/receiver.c#3 $ 30234285Sdim */ 31234285Sdim 32234285Sdim#include <config/config.h> 33234285Sdim 34234285Sdim#include <sys/param.h> 35234285Sdim#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP) 36234285Sdim#include <sys/endian.h> 37234285Sdim#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 38234285Sdim#ifdef HAVE_MACHINE_ENDIAN_H 39234285Sdim#include <machine/endian.h> 40234285Sdim#else /* !HAVE_MACHINE_ENDIAN_H */ 41234285Sdim#ifdef HAVE_ENDIAN_H 42234285Sdim#include <endian.h> 43234285Sdim#else /* !HAVE_ENDIAN_H */ 44234285Sdim#error "No supported endian.h" 45263508Sdim#endif /* !HAVE_ENDIAN_H */ 46234285Sdim#endif /* !HAVE_MACHINE_ENDIAN_H */ 47263508Sdim#include <compat/endian.h> 48263508Sdim#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 49263508Sdim#include <sys/queue.h> 50234285Sdim#include <sys/stat.h> 51234285Sdim#include <sys/time.h> 52234285Sdim 53239462Sdim#include <err.h> 54234285Sdim#include <errno.h> 55234285Sdim#include <fcntl.h> 56234285Sdim#ifdef HAVE_LIBUTIL_H 57234285Sdim#include <libutil.h> 58234285Sdim#endif 59234285Sdim#include <pthread.h> 60234285Sdim#include <pwd.h> 61234285Sdim#include <signal.h> 62234285Sdim#include <stdint.h> 63234285Sdim#include <stdio.h> 64234285Sdim#include <string.h> 65234285Sdim#include <sysexits.h> 66234285Sdim#include <unistd.h> 67234285Sdim 68234285Sdim#ifndef HAVE_STRLCPY 69234285Sdim#include <compat/strlcpy.h> 70234285Sdim#endif 71234285Sdim#ifndef HAVE_FSTATAT 72234285Sdim#include "fstatat.h" 73234285Sdim#endif 74234285Sdim#ifndef HAVE_OPENAT 75234285Sdim#include "openat.h" 76234285Sdim#endif 77234285Sdim#ifndef HAVE_RENAMEAT 78234285Sdim#include "renameat.h" 79234285Sdim#endif 80234285Sdim 81234285Sdim#include "auditdistd.h" 82234285Sdim#include "pjdlog.h" 83234285Sdim#include "proto.h" 84234285Sdim#include "sandbox.h" 85234285Sdim#include "subr.h" 86234285Sdim#include "synch.h" 87234285Sdim#include "trail.h" 88234285Sdim 89234285Sdimstatic struct adist_config *adcfg; 90234285Sdimstatic struct adist_host *adhost; 91234285Sdim 92234285Sdimstatic TAILQ_HEAD(, adreq) adist_free_list; 93234285Sdimstatic pthread_mutex_t adist_free_list_lock; 94234285Sdimstatic pthread_cond_t adist_free_list_cond; 95234285Sdimstatic TAILQ_HEAD(, adreq) adist_disk_list; 96234285Sdimstatic pthread_mutex_t adist_disk_list_lock; 97249423Sdimstatic pthread_cond_t adist_disk_list_cond; 98234285Sdimstatic TAILQ_HEAD(, adreq) adist_send_list; 99249423Sdimstatic pthread_mutex_t adist_send_list_lock; 100234285Sdimstatic pthread_cond_t adist_send_list_cond; 101234285Sdim 102234285Sdimstatic void 103234285Sdimadreq_clear(struct adreq *adreq) 104234285Sdim{ 105234285Sdim 106234285Sdim adreq->adr_error = -1; 107234285Sdim adreq->adr_byteorder = ADIST_BYTEORDER_UNDEFINED; 108234285Sdim adreq->adr_cmd = ADIST_CMD_UNDEFINED; 109234285Sdim adreq->adr_seq = 0; 110234285Sdim adreq->adr_datasize = 0; 111234285Sdim} 112234285Sdim 113234285Sdimstatic void 114234285Sdiminit_environment(void) 115234285Sdim{ 116234285Sdim struct adreq *adreq; 117234285Sdim unsigned int ii; 118234285Sdim 119234285Sdim TAILQ_INIT(&adist_free_list); 120234285Sdim mtx_init(&adist_free_list_lock); 121234285Sdim cv_init(&adist_free_list_cond); 122234285Sdim TAILQ_INIT(&adist_disk_list); 123234285Sdim mtx_init(&adist_disk_list_lock); 124234285Sdim cv_init(&adist_disk_list_cond); 125234285Sdim TAILQ_INIT(&adist_send_list); 126234285Sdim mtx_init(&adist_send_list_lock); 127234285Sdim cv_init(&adist_send_list_cond); 128234285Sdim 129234285Sdim for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) { 130234285Sdim adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE); 131234285Sdim if (adreq == NULL) { 132234285Sdim pjdlog_exitx(EX_TEMPFAIL, 133234285Sdim "Unable to allocate %zu bytes of memory for adreq object.", 134234285Sdim sizeof(*adreq) + ADIST_BUF_SIZE); 135249423Sdim } 136234285Sdim adreq_clear(adreq); 137249423Sdim TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next); 138234285Sdim } 139234285Sdim} 140234285Sdim 141234285Sdimstatic void 142234285Sdimadreq_decode_and_validate_header(struct adreq *adreq) 143234285Sdim{ 144234285Sdim 145234285Sdim /* Byte-swap only is the sender is using different byte order. */ 146234285Sdim if (adreq->adr_byteorder != ADIST_BYTEORDER) { 147234285Sdim adreq->adr_byteorder = ADIST_BYTEORDER; 148234285Sdim adreq->adr_seq = bswap64(adreq->adr_seq); 149234285Sdim adreq->adr_datasize = bswap32(adreq->adr_datasize); 150234285Sdim } 151234285Sdim 152234285Sdim /* Validate packet header. */ 153234285Sdim 154234285Sdim if (adreq->adr_datasize > ADIST_BUF_SIZE) { 155234285Sdim pjdlog_exitx(EX_PROTOCOL, "Invalid datasize received (%ju).", 156234285Sdim (uintmax_t)adreq->adr_datasize); 157234285Sdim } 158234285Sdim 159234285Sdim switch (adreq->adr_cmd) { 160234285Sdim case ADIST_CMD_OPEN: 161234285Sdim case ADIST_CMD_APPEND: 162234285Sdim case ADIST_CMD_CLOSE: 163234285Sdim if (adreq->adr_datasize == 0) { 164234285Sdim pjdlog_exitx(EX_PROTOCOL, 165234285Sdim "Invalid datasize received (%ju).", 166234285Sdim (uintmax_t)adreq->adr_datasize); 167234285Sdim } 168234285Sdim break; 169234285Sdim case ADIST_CMD_KEEPALIVE: 170234285Sdim case ADIST_CMD_ERROR: 171234285Sdim if (adreq->adr_datasize > 0) { 172234285Sdim pjdlog_exitx(EX_PROTOCOL, 173234285Sdim "Invalid datasize received (%ju).", 174234285Sdim (uintmax_t)adreq->adr_datasize); 175234285Sdim } 176234285Sdim break; 177234285Sdim default: 178234285Sdim pjdlog_exitx(EX_PROTOCOL, "Invalid command received (%hhu).", 179234285Sdim adreq->adr_cmd); 180234285Sdim } 181234285Sdim} 182234285Sdim 183234285Sdimstatic void 184234285Sdimadreq_validate_data(const struct adreq *adreq) 185234285Sdim{ 186234285Sdim 187234285Sdim /* Validate packet data. */ 188234285Sdim 189234285Sdim switch (adreq->adr_cmd) { 190234285Sdim case ADIST_CMD_OPEN: 191234285Sdim case ADIST_CMD_CLOSE: 192234285Sdim /* 193234285Sdim * File name must end up with '\0' and there must be no '\0' 194234285Sdim * in the middle. 195234285Sdim */ 196234285Sdim if (adreq->adr_data[adreq->adr_datasize - 1] != '\0' || 197234285Sdim strchr(adreq->adr_data, '\0') != 198234285Sdim (const char *)adreq->adr_data + adreq->adr_datasize - 1) { 199234285Sdim pjdlog_exitx(EX_PROTOCOL, 200234285Sdim "Invalid file name received."); 201234285Sdim } 202234285Sdim break; 203234285Sdim } 204234285Sdim} 205234285Sdim 206234285Sdim/* 207234285Sdim * Thread receives requests from the sender. 208234285Sdim */ 209234285Sdimstatic void * 210234285Sdimrecv_thread(void *arg __unused) 211234285Sdim{ 212234285Sdim struct adreq *adreq; 213234285Sdim 214234285Sdim for (;;) { 215234285Sdim pjdlog_debug(3, "recv: Taking free request."); 216234285Sdim QUEUE_TAKE(adreq, &adist_free_list, 0); 217234285Sdim pjdlog_debug(3, "recv: (%p) Got request.", adreq); 218234285Sdim 219234285Sdim if (proto_recv(adhost->adh_remote, &adreq->adr_packet, 220234285Sdim sizeof(adreq->adr_packet)) == -1) { 221234285Sdim pjdlog_exit(EX_TEMPFAIL, 222234285Sdim "Unable to receive request header"); 223234285Sdim } 224234285Sdim adreq_decode_and_validate_header(adreq); 225234285Sdim 226234285Sdim switch (adreq->adr_cmd) { 227234285Sdim case ADIST_CMD_KEEPALIVE: 228234285Sdim adreq->adr_error = 0; 229234285Sdim adreq_log(LOG_DEBUG, 2, -1, adreq, 230234285Sdim "recv: (%p) Got request header: ", adreq); 231234285Sdim pjdlog_debug(3, 232234285Sdim "recv: (%p) Moving request to the send queue.", 233234285Sdim adreq); 234234285Sdim QUEUE_INSERT(adreq, &adist_send_list); 235234285Sdim continue; 236234285Sdim case ADIST_CMD_ERROR: 237234285Sdim pjdlog_error("An error occured on the sender while reading \"%s/%s\".", 238234285Sdim adhost->adh_directory, adhost->adh_trail_name); 239234285Sdim adreq_log(LOG_DEBUG, 2, ADIST_ERROR_READ, adreq, 240234285Sdim "recv: (%p) Got request header: ", adreq); 241234285Sdim pjdlog_debug(3, 242234285Sdim "recv: (%p) Moving request to the send queue.", 243234285Sdim adreq); 244234285Sdim QUEUE_INSERT(adreq, &adist_disk_list); 245234285Sdim continue; 246234285Sdim case ADIST_CMD_OPEN: 247234285Sdim case ADIST_CMD_APPEND: 248234285Sdim case ADIST_CMD_CLOSE: 249234285Sdim if (proto_recv(adhost->adh_remote, adreq->adr_data, 250234285Sdim adreq->adr_datasize) == -1) { 251234285Sdim pjdlog_exit(EX_TEMPFAIL, 252234285Sdim "Unable to receive request data"); 253234285Sdim } 254234285Sdim adreq_validate_data(adreq); 255234285Sdim adreq_log(LOG_DEBUG, 2, -1, adreq, 256234285Sdim "recv: (%p) Got request header: ", adreq); 257234285Sdim pjdlog_debug(3, 258234285Sdim "recv: (%p) Moving request to the disk queue.", 259234285Sdim adreq); 260234285Sdim QUEUE_INSERT(adreq, &adist_disk_list); 261234285Sdim break; 262234285Sdim default: 263234285Sdim PJDLOG_ABORT("Invalid condition."); 264234285Sdim } 265234285Sdim } 266234285Sdim /* NOTREACHED */ 267234285Sdim return (NULL); 268234285Sdim} 269234285Sdim 270234285Sdim/* 271234285Sdim * Function that opens trail file requested by the sender. 272234285Sdim * If the file already exist, it has to be the most recent file and it can 273234285Sdim * only be open for append. 274234285Sdim * If the file doesn't already exist, it has to be "older" than all existing 275234285Sdim * files. 276234285Sdim */ 277234285Sdimstatic int 278234285Sdimreceiver_open(const char *filename) 279234285Sdim{ 280234285Sdim int fd; 281234285Sdim 282234285Sdim /* 283234285Sdim * Previous file should be closed by now. Sending OPEN request without 284234285Sdim * sending CLOSE for the previous file is a sender bug. 285234285Sdim */ 286234285Sdim if (adhost->adh_trail_fd != -1) { 287234285Sdim pjdlog_error("Sender requested opening file \"%s\" without first closing \"%s\".", 288234285Sdim filename, adhost->adh_trail_name); 289234285Sdim return (ADIST_ERROR_WRONG_ORDER); 290234285Sdim } 291234285Sdim 292234285Sdim if (!trail_validate_name(filename, NULL)) { 293234285Sdim pjdlog_error("Sender wants to open file \"%s\", which has invalid name.", 294234285Sdim filename); 295234285Sdim return (ADIST_ERROR_INVALID_NAME); 296234285Sdim } 297234285Sdim 298234285Sdim switch (trail_name_compare(filename, adhost->adh_trail_name)) { 299234285Sdim case TRAIL_RENAMED: 300234285Sdim if (!trail_is_not_terminated(adhost->adh_trail_name)) { 301234285Sdim pjdlog_error("Terminated trail \"%s/%s\" was unterminated on the sender as \"%s/%s\"?", 302234285Sdim adhost->adh_directory, adhost->adh_trail_name, 303234285Sdim adhost->adh_directory, filename); 304234285Sdim return (ADIST_ERROR_INVALID_NAME); 305234285Sdim } 306234285Sdim if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 307234285Sdim adhost->adh_trail_dirfd, filename) == -1) { 308234285Sdim pjdlog_errno(LOG_ERR, 309234285Sdim "Unable to rename file \"%s/%s\" to \"%s/%s\"", 310234285Sdim adhost->adh_directory, adhost->adh_trail_name, 311234285Sdim adhost->adh_directory, filename); 312234285Sdim PJDLOG_ASSERT(errno > 0); 313234285Sdim return (ADIST_ERROR_RENAME); 314234285Sdim } 315234285Sdim pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".", 316234285Sdim adhost->adh_directory, adhost->adh_trail_name, 317234285Sdim adhost->adh_directory, filename); 318234285Sdim /* FALLTHROUGH */ 319234285Sdim case TRAIL_IDENTICAL: 320234285Sdim /* Opening existing file. */ 321239462Sdim fd = openat(adhost->adh_trail_dirfd, filename, 322234285Sdim O_WRONLY | O_APPEND | O_NOFOLLOW); 323234285Sdim if (fd == -1) { 324234285Sdim pjdlog_errno(LOG_ERR, 325234285Sdim "Unable to open file \"%s/%s\" for append", 326234285Sdim adhost->adh_directory, filename); 327234285Sdim PJDLOG_ASSERT(errno > 0); 328234285Sdim return (ADIST_ERROR_OPEN); 329234285Sdim } 330234285Sdim pjdlog_debug(1, "Opened file \"%s/%s\".", 331234285Sdim adhost->adh_directory, filename); 332234285Sdim break; 333234285Sdim case TRAIL_NEWER: 334234285Sdim /* Opening new file. */ 335249423Sdim fd = openat(adhost->adh_trail_dirfd, filename, 336234285Sdim O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); 337234285Sdim if (fd == -1) { 338234285Sdim pjdlog_errno(LOG_ERR, 339234285Sdim "Unable to create file \"%s/%s\"", 340234285Sdim adhost->adh_directory, filename); 341234285Sdim PJDLOG_ASSERT(errno > 0); 342234285Sdim return (ADIST_ERROR_CREATE); 343234285Sdim } 344249423Sdim pjdlog_debug(1, "Created file \"%s/%s\".", 345234285Sdim adhost->adh_directory, filename); 346234285Sdim break; 347234285Sdim case TRAIL_OLDER: 348234285Sdim /* Trying to open old file. */ 349234285Sdim pjdlog_error("Sender wants to open an old file \"%s\".", filename); 350234285Sdim return (ADIST_ERROR_OPEN_OLD); 351234285Sdim default: 352234285Sdim PJDLOG_ABORT("Unknown return value from trail_name_compare()."); 353234285Sdim } 354234285Sdim PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename, 355234285Sdim sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name)); 356239462Sdim adhost->adh_trail_fd = fd; 357234285Sdim return (0); 358234285Sdim} 359234285Sdim 360234285Sdim/* 361234285Sdim * Function appends data to the trail file that is currently open. 362234285Sdim */ 363234285Sdimstatic int 364234285Sdimreceiver_append(const unsigned char *data, size_t size) 365234285Sdim{ 366234285Sdim ssize_t done; 367234285Sdim size_t osize; 368234285Sdim 369234285Sdim /* We should have opened trail file. */ 370234285Sdim if (adhost->adh_trail_fd == -1) { 371234285Sdim pjdlog_error("Sender requested append without first opening file."); 372234285Sdim return (ADIST_ERROR_WRONG_ORDER); 373234285Sdim } 374234285Sdim 375234285Sdim osize = size; 376234285Sdim while (size > 0) { 377234285Sdim done = write(adhost->adh_trail_fd, data, size); 378234285Sdim if (done == -1) { 379234285Sdim if (errno == EINTR) 380234285Sdim continue; 381234285Sdim pjdlog_errno(LOG_ERR, "Write to \"%s/%s\" failed", 382234285Sdim adhost->adh_directory, adhost->adh_trail_name); 383234285Sdim PJDLOG_ASSERT(errno > 0); 384234285Sdim return (ADIST_ERROR_WRITE); 385234285Sdim } 386234285Sdim pjdlog_debug(3, "Wrote %zd bytes into \"%s/%s\".", done, 387234285Sdim adhost->adh_directory, adhost->adh_trail_name); 388234285Sdim size -= done; 389234285Sdim } 390234285Sdim pjdlog_debug(2, "Appended %zu bytes to file \"%s/%s\".", 391234285Sdim osize, adhost->adh_directory, adhost->adh_trail_name); 392263508Sdim return (0); 393263508Sdim} 394263508Sdim 395234285Sdimstatic int 396234285Sdimreceiver_close(const char *filename) 397234285Sdim{ 398234285Sdim 399234285Sdim /* We should have opened trail file. */ 400234285Sdim if (adhost->adh_trail_fd == -1) { 401234285Sdim pjdlog_error("Sender requested closing file without first opening it."); 402234285Sdim return (ADIST_ERROR_WRONG_ORDER); 403234285Sdim } 404234285Sdim 405234285Sdim /* Validate if we can do the rename. */ 406234285Sdim if (!trail_validate_name(adhost->adh_trail_name, filename)) { 407234285Sdim pjdlog_error("Sender wants to close file \"%s\" using name \"%s\".", 408234285Sdim adhost->adh_trail_name, filename); 409234285Sdim return (ADIST_ERROR_INVALID_NAME); 410234285Sdim } 411234285Sdim 412234285Sdim PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0); 413234285Sdim adhost->adh_trail_fd = -1; 414234285Sdim 415234285Sdim pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory, 416234285Sdim adhost->adh_trail_name); 417234285Sdim 418234285Sdim if (strcmp(adhost->adh_trail_name, filename) == 0) { 419234285Sdim /* File name didn't change, we are done here. */ 420234285Sdim return (0); 421234285Sdim } 422234285Sdim 423234285Sdim if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 424234285Sdim adhost->adh_trail_dirfd, filename) == -1) { 425234285Sdim pjdlog_errno(LOG_ERR, "Unable to rename \"%s\" to \"%s\"", 426234285Sdim adhost->adh_trail_name, filename); 427234285Sdim PJDLOG_ASSERT(errno > 0); 428234285Sdim return (ADIST_ERROR_RENAME); 429234285Sdim } 430234285Sdim pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".", 431234285Sdim adhost->adh_directory, adhost->adh_trail_name, 432234285Sdim adhost->adh_directory, filename); 433234285Sdim PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename, 434234285Sdim sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name)); 435234285Sdim 436234285Sdim return (0); 437234285Sdim} 438234285Sdim 439234285Sdimstatic int 440234285Sdimreceiver_error(void) 441234285Sdim{ 442234285Sdim 443234285Sdim /* We should have opened trail file. */ 444234285Sdim if (adhost->adh_trail_fd == -1) { 445234285Sdim pjdlog_error("Sender send read error, but file is not open."); 446234285Sdim return (ADIST_ERROR_WRONG_ORDER); 447234285Sdim } 448234285Sdim 449234285Sdim PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0); 450234285Sdim adhost->adh_trail_fd = -1; 451263508Sdim 452234285Sdim pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory, 453234285Sdim adhost->adh_trail_name); 454234285Sdim 455234285Sdim return (0); 456234285Sdim} 457234285Sdim 458234285Sdimstatic void * 459263508Sdimdisk_thread(void *arg __unused) 460234285Sdim{ 461234285Sdim struct adreq *adreq; 462234285Sdim 463263508Sdim for (;;) { 464234285Sdim pjdlog_debug(3, "disk: Taking request."); 465234285Sdim QUEUE_TAKE(adreq, &adist_disk_list, 0); 466234285Sdim adreq_log(LOG_DEBUG, 3, -1, adreq, "disk: (%p) Got request: ", 467234285Sdim adreq); 468234285Sdim /* Handle the actual request. */ 469234285Sdim switch (adreq->adr_cmd) { 470234285Sdim case ADIST_CMD_OPEN: 471234285Sdim adreq->adr_error = receiver_open(adreq->adr_data); 472234285Sdim break; 473234285Sdim case ADIST_CMD_APPEND: 474234285Sdim adreq->adr_error = receiver_append(adreq->adr_data, 475234285Sdim adreq->adr_datasize); 476234285Sdim break; 477234285Sdim case ADIST_CMD_CLOSE: 478234285Sdim adreq->adr_error = receiver_close(adreq->adr_data); 479234285Sdim break; 480234285Sdim case ADIST_CMD_ERROR: 481234285Sdim adreq->adr_error = receiver_error(); 482234285Sdim break; 483234285Sdim default: 484234285Sdim PJDLOG_ABORT("Unexpected command (cmd=%hhu).", 485234285Sdim adreq->adr_cmd); 486234285Sdim } 487249423Sdim if (adreq->adr_error != 0) { 488234285Sdim adreq_log(LOG_ERR, 0, adreq->adr_error, adreq, 489234285Sdim "Request failed: "); 490234285Sdim } 491234285Sdim pjdlog_debug(3, "disk: (%p) Moving request to the send queue.", 492234285Sdim adreq); 493234285Sdim QUEUE_INSERT(adreq, &adist_send_list); 494234285Sdim } 495234285Sdim /* NOTREACHED */ 496234285Sdim return (NULL); 497234285Sdim} 498249423Sdim 499234285Sdim/* 500234285Sdim * Thread sends requests back to primary node. 501234285Sdim */ 502234285Sdimstatic void * 503234285Sdimsend_thread(void *arg __unused) 504234285Sdim{ 505234285Sdim struct adreq *adreq; 506234285Sdim struct adrep adrep; 507234285Sdim 508234285Sdim for (;;) { 509234285Sdim pjdlog_debug(3, "send: Taking request."); 510234285Sdim QUEUE_TAKE(adreq, &adist_send_list, 0); 511234285Sdim adreq_log(LOG_DEBUG, 3, -1, adreq, "send: (%p) Got request: ", 512234285Sdim adreq); 513234285Sdim adrep.adrp_byteorder = ADIST_BYTEORDER; 514234285Sdim adrep.adrp_seq = adreq->adr_seq; 515234285Sdim adrep.adrp_error = adreq->adr_error; 516234285Sdim if (proto_send(adhost->adh_remote, &adrep, 517234285Sdim sizeof(adrep)) == -1) { 518234285Sdim pjdlog_exit(EX_TEMPFAIL, "Unable to send reply"); 519234285Sdim } 520234285Sdim pjdlog_debug(3, "send: (%p) Moving request to the free queue.", 521234285Sdim adreq); 522234285Sdim adreq_clear(adreq); 523234285Sdim QUEUE_INSERT(adreq, &adist_free_list); 524234285Sdim } 525234285Sdim /* NOTREACHED */ 526234285Sdim return (NULL); 527234285Sdim} 528234285Sdim 529234285Sdimstatic void 530234285Sdimreceiver_directory_create(void) 531234285Sdim{ 532234285Sdim struct passwd *pw; 533234285Sdim 534234285Sdim /* 535234285Sdim * According to getpwnam(3) we have to clear errno before calling the 536234285Sdim * function to be able to distinguish between an error and missing 537234285Sdim * entry (with is not treated as error by getpwnam(3)). 538234285Sdim */ 539234285Sdim errno = 0; 540234285Sdim pw = getpwnam(ADIST_USER); 541234285Sdim if (pw == NULL) { 542234285Sdim if (errno != 0) { 543234285Sdim pjdlog_exit(EX_NOUSER, 544234285Sdim "Unable to find info about '%s' user", ADIST_USER); 545234285Sdim } else { 546234285Sdim pjdlog_exitx(EX_NOUSER, "User '%s' doesn't exist.", 547234285Sdim ADIST_USER); 548234285Sdim } 549234285Sdim } 550234285Sdim 551234285Sdim if (mkdir(adhost->adh_directory, 0700) == -1) { 552234285Sdim pjdlog_exit(EX_OSFILE, "Unable to create directory \"%s\"", 553234285Sdim adhost->adh_directory); 554234285Sdim } 555234285Sdim if (chown(adhost->adh_directory, pw->pw_uid, pw->pw_gid) == -1) { 556234285Sdim pjdlog_errno(LOG_ERR, 557234285Sdim "Unable to change owner of the directory \"%s\"", 558234285Sdim adhost->adh_directory); 559234285Sdim (void)rmdir(adhost->adh_directory); 560234285Sdim exit(EX_OSFILE); 561234285Sdim } 562234285Sdim} 563234285Sdim 564234285Sdimstatic void 565234285Sdimreceiver_directory_open(void) 566234285Sdim{ 567234285Sdim 568234285Sdim#ifdef HAVE_FDOPENDIR 569234285Sdim adhost->adh_trail_dirfd = open(adhost->adh_directory, 570234285Sdim O_RDONLY | O_DIRECTORY); 571234285Sdim if (adhost->adh_trail_dirfd == -1) { 572234285Sdim if (errno == ENOENT) { 573234285Sdim receiver_directory_create(); 574234285Sdim adhost->adh_trail_dirfd = open(adhost->adh_directory, 575234285Sdim O_RDONLY | O_DIRECTORY); 576234285Sdim } 577234285Sdim if (adhost->adh_trail_dirfd == -1) { 578234285Sdim pjdlog_exit(EX_CONFIG, 579234285Sdim "Unable to open directory \"%s\"", 580234285Sdim adhost->adh_directory); 581234285Sdim } 582234285Sdim } 583234285Sdim adhost->adh_trail_dirfp = fdopendir(adhost->adh_trail_dirfd); 584234285Sdim if (adhost->adh_trail_dirfp == NULL) { 585234285Sdim pjdlog_exit(EX_CONFIG, "Unable to fdopen directory \"%s\"", 586234285Sdim adhost->adh_directory); 587234285Sdim } 588234285Sdim#else 589234285Sdim struct stat sb; 590234285Sdim 591234285Sdim if (stat(adhost->adh_directory, &sb) == -1) { 592234285Sdim if (errno == ENOENT) { 593234285Sdim receiver_directory_create(); 594234285Sdim } else { 595234285Sdim pjdlog_exit(EX_CONFIG, 596234285Sdim "Unable to stat directory \"%s\"", 597234285Sdim adhost->adh_directory); 598234285Sdim } 599234285Sdim } 600234285Sdim adhost->adh_trail_dirfp = opendir(adhost->adh_directory); 601234285Sdim if (adhost->adh_trail_dirfp == NULL) { 602234285Sdim pjdlog_exit(EX_CONFIG, "Unable to open directory \"%s\"", 603234285Sdim adhost->adh_directory); 604234285Sdim } 605234285Sdim adhost->adh_trail_dirfd = dirfd(adhost->adh_trail_dirfp); 606249423Sdim#endif 607234285Sdim} 608234285Sdim 609234285Sdimstatic void 610234285Sdimreceiver_connect(void) 611234285Sdim{ 612234285Sdim uint64_t trail_size; 613234285Sdim struct stat sb; 614234285Sdim 615234285Sdim PJDLOG_ASSERT(adhost->adh_trail_dirfp != NULL); 616234285Sdim 617234285Sdim trail_last(adhost->adh_trail_dirfp, adhost->adh_trail_name, 618234285Sdim sizeof(adhost->adh_trail_name)); 619234285Sdim 620234285Sdim if (adhost->adh_trail_name[0] == '\0') { 621234285Sdim trail_size = 0; 622234285Sdim } else { 623234285Sdim if (fstatat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 624234285Sdim &sb, AT_SYMLINK_NOFOLLOW) == -1) { 625234285Sdim pjdlog_exit(EX_CONFIG, "Unable to stat \"%s/%s\"", 626234285Sdim adhost->adh_directory, adhost->adh_trail_name); 627234285Sdim } 628234285Sdim if (!S_ISREG(sb.st_mode)) { 629234285Sdim pjdlog_exitx(EX_CONFIG, 630234285Sdim "File \"%s/%s\" is not a regular file.", 631234285Sdim adhost->adh_directory, adhost->adh_trail_name); 632234285Sdim } 633234285Sdim trail_size = sb.st_size; 634234285Sdim } 635234285Sdim trail_size = htole64(trail_size); 636234285Sdim if (proto_send(adhost->adh_remote, &trail_size, 637234285Sdim sizeof(trail_size)) == -1) { 638234285Sdim pjdlog_exit(EX_TEMPFAIL, 639234285Sdim "Unable to send size of the most recent trail file"); 640234285Sdim } 641234285Sdim if (proto_send(adhost->adh_remote, adhost->adh_trail_name, 642234285Sdim sizeof(adhost->adh_trail_name)) == -1) { 643234285Sdim pjdlog_exit(EX_TEMPFAIL, 644234285Sdim "Unable to send name of the most recent trail file"); 645234285Sdim } 646234285Sdim} 647234285Sdim 648234285Sdimvoid 649234285Sdimadist_receiver(struct adist_config *config, struct adist_host *adh) 650234285Sdim{ 651234285Sdim sigset_t mask; 652234285Sdim pthread_t td; 653234285Sdim pid_t pid; 654234285Sdim 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} 715