1243730Srwatson/*- 2243730Srwatson * Copyright (c) 2012 The FreeBSD Foundation 3243730Srwatson * All rights reserved. 4243730Srwatson * 5243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from 6243730Srwatson * the FreeBSD Foundation. 7243730Srwatson * 8243730Srwatson * Redistribution and use in source and binary forms, with or without 9243730Srwatson * modification, are permitted provided that the following conditions 10243730Srwatson * are met: 11243730Srwatson * 1. Redistributions of source code must retain the above copyright 12243730Srwatson * notice, this list of conditions and the following disclaimer. 13243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14243730Srwatson * notice, this list of conditions and the following disclaimer in the 15243730Srwatson * documentation and/or other materials provided with the distribution. 16243730Srwatson * 17243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20243730Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27243730Srwatson * SUCH DAMAGE. 28243730Srwatson */ 29243730Srwatson 30243734Srwatson#include <config/config.h> 31243730Srwatson 32243730Srwatson#include <sys/param.h> 33243730Srwatson#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP) 34243730Srwatson#include <sys/endian.h> 35243730Srwatson#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 36243730Srwatson#ifdef HAVE_MACHINE_ENDIAN_H 37243730Srwatson#include <machine/endian.h> 38243730Srwatson#else /* !HAVE_MACHINE_ENDIAN_H */ 39243730Srwatson#ifdef HAVE_ENDIAN_H 40243730Srwatson#include <endian.h> 41243730Srwatson#else /* !HAVE_ENDIAN_H */ 42243730Srwatson#error "No supported endian.h" 43243730Srwatson#endif /* !HAVE_ENDIAN_H */ 44243730Srwatson#endif /* !HAVE_MACHINE_ENDIAN_H */ 45243730Srwatson#include <compat/endian.h> 46243730Srwatson#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 47243730Srwatson#include <sys/queue.h> 48243730Srwatson#include <sys/stat.h> 49243730Srwatson#include <sys/time.h> 50243730Srwatson 51243730Srwatson#include <err.h> 52243730Srwatson#include <errno.h> 53243730Srwatson#include <fcntl.h> 54243730Srwatson#ifdef HAVE_LIBUTIL_H 55243730Srwatson#include <libutil.h> 56243730Srwatson#endif 57243730Srwatson#include <pthread.h> 58243730Srwatson#include <pwd.h> 59243730Srwatson#include <signal.h> 60243730Srwatson#include <stdint.h> 61243730Srwatson#include <stdio.h> 62243730Srwatson#include <string.h> 63243730Srwatson#include <sysexits.h> 64243730Srwatson#include <unistd.h> 65243730Srwatson 66243730Srwatson#ifndef HAVE_STRLCPY 67243730Srwatson#include <compat/strlcpy.h> 68243730Srwatson#endif 69243730Srwatson#ifndef HAVE_FSTATAT 70243730Srwatson#include "fstatat.h" 71243730Srwatson#endif 72243730Srwatson#ifndef HAVE_OPENAT 73243730Srwatson#include "openat.h" 74243730Srwatson#endif 75243730Srwatson#ifndef HAVE_RENAMEAT 76243730Srwatson#include "renameat.h" 77243730Srwatson#endif 78243730Srwatson 79243730Srwatson#include "auditdistd.h" 80243734Srwatson#include "pjdlog.h" 81243730Srwatson#include "proto.h" 82243730Srwatson#include "sandbox.h" 83243730Srwatson#include "subr.h" 84243730Srwatson#include "synch.h" 85243730Srwatson#include "trail.h" 86243730Srwatson 87243730Srwatsonstatic struct adist_config *adcfg; 88243730Srwatsonstatic struct adist_host *adhost; 89243730Srwatson 90243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_free_list; 91243730Srwatsonstatic pthread_mutex_t adist_free_list_lock; 92243730Srwatsonstatic pthread_cond_t adist_free_list_cond; 93243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_disk_list; 94243730Srwatsonstatic pthread_mutex_t adist_disk_list_lock; 95243730Srwatsonstatic pthread_cond_t adist_disk_list_cond; 96243730Srwatsonstatic TAILQ_HEAD(, adreq) adist_send_list; 97243730Srwatsonstatic pthread_mutex_t adist_send_list_lock; 98243730Srwatsonstatic pthread_cond_t adist_send_list_cond; 99243730Srwatson 100243730Srwatsonstatic void 101243730Srwatsonadreq_clear(struct adreq *adreq) 102243730Srwatson{ 103243730Srwatson 104243730Srwatson adreq->adr_error = -1; 105243730Srwatson adreq->adr_byteorder = ADIST_BYTEORDER_UNDEFINED; 106243730Srwatson adreq->adr_cmd = ADIST_CMD_UNDEFINED; 107243730Srwatson adreq->adr_seq = 0; 108243730Srwatson adreq->adr_datasize = 0; 109243730Srwatson} 110243730Srwatson 111243730Srwatsonstatic void 112243730Srwatsoninit_environment(void) 113243730Srwatson{ 114243730Srwatson struct adreq *adreq; 115243730Srwatson unsigned int ii; 116243730Srwatson 117243730Srwatson TAILQ_INIT(&adist_free_list); 118243730Srwatson mtx_init(&adist_free_list_lock); 119243730Srwatson cv_init(&adist_free_list_cond); 120243730Srwatson TAILQ_INIT(&adist_disk_list); 121243730Srwatson mtx_init(&adist_disk_list_lock); 122243730Srwatson cv_init(&adist_disk_list_cond); 123243730Srwatson TAILQ_INIT(&adist_send_list); 124243730Srwatson mtx_init(&adist_send_list_lock); 125243730Srwatson cv_init(&adist_send_list_cond); 126243730Srwatson 127243730Srwatson for (ii = 0; ii < ADIST_QUEUE_SIZE; ii++) { 128243730Srwatson adreq = malloc(sizeof(*adreq) + ADIST_BUF_SIZE); 129243730Srwatson if (adreq == NULL) { 130243730Srwatson pjdlog_exitx(EX_TEMPFAIL, 131243730Srwatson "Unable to allocate %zu bytes of memory for adreq object.", 132243730Srwatson sizeof(*adreq) + ADIST_BUF_SIZE); 133243730Srwatson } 134243730Srwatson adreq_clear(adreq); 135243730Srwatson TAILQ_INSERT_TAIL(&adist_free_list, adreq, adr_next); 136243730Srwatson } 137243730Srwatson} 138243730Srwatson 139243730Srwatsonstatic void 140243730Srwatsonadreq_decode_and_validate_header(struct adreq *adreq) 141243730Srwatson{ 142243730Srwatson 143243730Srwatson /* Byte-swap only is the sender is using different byte order. */ 144243730Srwatson if (adreq->adr_byteorder != ADIST_BYTEORDER) { 145243730Srwatson adreq->adr_byteorder = ADIST_BYTEORDER; 146243730Srwatson adreq->adr_seq = bswap64(adreq->adr_seq); 147243730Srwatson adreq->adr_datasize = bswap32(adreq->adr_datasize); 148243730Srwatson } 149243730Srwatson 150243730Srwatson /* Validate packet header. */ 151243730Srwatson 152243730Srwatson if (adreq->adr_datasize > ADIST_BUF_SIZE) { 153243730Srwatson pjdlog_exitx(EX_PROTOCOL, "Invalid datasize received (%ju).", 154243730Srwatson (uintmax_t)adreq->adr_datasize); 155243730Srwatson } 156243730Srwatson 157243730Srwatson switch (adreq->adr_cmd) { 158243730Srwatson case ADIST_CMD_OPEN: 159243730Srwatson case ADIST_CMD_APPEND: 160243730Srwatson case ADIST_CMD_CLOSE: 161243730Srwatson if (adreq->adr_datasize == 0) { 162243730Srwatson pjdlog_exitx(EX_PROTOCOL, 163243730Srwatson "Invalid datasize received (%ju).", 164243730Srwatson (uintmax_t)adreq->adr_datasize); 165243730Srwatson } 166243730Srwatson break; 167243730Srwatson case ADIST_CMD_KEEPALIVE: 168243730Srwatson case ADIST_CMD_ERROR: 169243730Srwatson if (adreq->adr_datasize > 0) { 170243730Srwatson pjdlog_exitx(EX_PROTOCOL, 171243730Srwatson "Invalid datasize received (%ju).", 172243730Srwatson (uintmax_t)adreq->adr_datasize); 173243730Srwatson } 174243730Srwatson break; 175243730Srwatson default: 176243730Srwatson pjdlog_exitx(EX_PROTOCOL, "Invalid command received (%hhu).", 177243730Srwatson adreq->adr_cmd); 178243730Srwatson } 179243730Srwatson} 180243730Srwatson 181243730Srwatsonstatic void 182243730Srwatsonadreq_validate_data(const struct adreq *adreq) 183243730Srwatson{ 184243730Srwatson 185243730Srwatson /* Validate packet data. */ 186243730Srwatson 187243730Srwatson switch (adreq->adr_cmd) { 188243730Srwatson case ADIST_CMD_OPEN: 189243730Srwatson case ADIST_CMD_CLOSE: 190243730Srwatson /* 191243730Srwatson * File name must end up with '\0' and there must be no '\0' 192243730Srwatson * in the middle. 193243730Srwatson */ 194243730Srwatson if (adreq->adr_data[adreq->adr_datasize - 1] != '\0' || 195243730Srwatson strchr(adreq->adr_data, '\0') != 196243730Srwatson (const char *)adreq->adr_data + adreq->adr_datasize - 1) { 197243730Srwatson pjdlog_exitx(EX_PROTOCOL, 198243730Srwatson "Invalid file name received."); 199243730Srwatson } 200243730Srwatson break; 201243730Srwatson } 202243730Srwatson} 203243730Srwatson 204243730Srwatson/* 205243730Srwatson * Thread receives requests from the sender. 206243730Srwatson */ 207243730Srwatsonstatic void * 208243730Srwatsonrecv_thread(void *arg __unused) 209243730Srwatson{ 210243730Srwatson struct adreq *adreq; 211243730Srwatson 212243730Srwatson for (;;) { 213243730Srwatson pjdlog_debug(3, "recv: Taking free request."); 214243730Srwatson QUEUE_TAKE(adreq, &adist_free_list, 0); 215243730Srwatson pjdlog_debug(3, "recv: (%p) Got request.", adreq); 216243730Srwatson 217243730Srwatson if (proto_recv(adhost->adh_remote, &adreq->adr_packet, 218243730Srwatson sizeof(adreq->adr_packet)) == -1) { 219243730Srwatson pjdlog_exit(EX_TEMPFAIL, 220243730Srwatson "Unable to receive request header"); 221243730Srwatson } 222243730Srwatson adreq_decode_and_validate_header(adreq); 223243730Srwatson 224243730Srwatson switch (adreq->adr_cmd) { 225243730Srwatson case ADIST_CMD_KEEPALIVE: 226243730Srwatson adreq->adr_error = 0; 227243730Srwatson adreq_log(LOG_DEBUG, 2, -1, adreq, 228243730Srwatson "recv: (%p) Got request header: ", adreq); 229243730Srwatson pjdlog_debug(3, 230243730Srwatson "recv: (%p) Moving request to the send queue.", 231243730Srwatson adreq); 232243730Srwatson QUEUE_INSERT(adreq, &adist_send_list); 233243730Srwatson continue; 234243730Srwatson case ADIST_CMD_ERROR: 235243730Srwatson pjdlog_error("An error occured on the sender while reading \"%s/%s\".", 236243730Srwatson adhost->adh_directory, adhost->adh_trail_name); 237243730Srwatson adreq_log(LOG_DEBUG, 2, ADIST_ERROR_READ, adreq, 238243730Srwatson "recv: (%p) Got request header: ", adreq); 239243730Srwatson pjdlog_debug(3, 240243730Srwatson "recv: (%p) Moving request to the send queue.", 241243730Srwatson adreq); 242243730Srwatson QUEUE_INSERT(adreq, &adist_disk_list); 243243730Srwatson continue; 244243730Srwatson case ADIST_CMD_OPEN: 245243730Srwatson case ADIST_CMD_APPEND: 246243730Srwatson case ADIST_CMD_CLOSE: 247243730Srwatson if (proto_recv(adhost->adh_remote, adreq->adr_data, 248243730Srwatson adreq->adr_datasize) == -1) { 249243730Srwatson pjdlog_exit(EX_TEMPFAIL, 250243730Srwatson "Unable to receive request data"); 251243730Srwatson } 252243730Srwatson adreq_validate_data(adreq); 253243730Srwatson adreq_log(LOG_DEBUG, 2, -1, adreq, 254243730Srwatson "recv: (%p) Got request header: ", adreq); 255243730Srwatson pjdlog_debug(3, 256243730Srwatson "recv: (%p) Moving request to the disk queue.", 257243730Srwatson adreq); 258243730Srwatson QUEUE_INSERT(adreq, &adist_disk_list); 259243730Srwatson break; 260243730Srwatson default: 261243730Srwatson PJDLOG_ABORT("Invalid condition."); 262243730Srwatson } 263243730Srwatson } 264243730Srwatson /* NOTREACHED */ 265243730Srwatson return (NULL); 266243730Srwatson} 267243730Srwatson 268243730Srwatson/* 269243730Srwatson * Function that opens trail file requested by the sender. 270243730Srwatson * If the file already exist, it has to be the most recent file and it can 271243730Srwatson * only be open for append. 272243730Srwatson * If the file doesn't already exist, it has to be "older" than all existing 273243730Srwatson * files. 274243730Srwatson */ 275243730Srwatsonstatic int 276243730Srwatsonreceiver_open(const char *filename) 277243730Srwatson{ 278243730Srwatson int fd; 279243730Srwatson 280243730Srwatson /* 281243730Srwatson * Previous file should be closed by now. Sending OPEN request without 282243730Srwatson * sending CLOSE for the previous file is a sender bug. 283243730Srwatson */ 284243730Srwatson if (adhost->adh_trail_fd != -1) { 285243730Srwatson pjdlog_error("Sender requested opening file \"%s\" without first closing \"%s\".", 286243730Srwatson filename, adhost->adh_trail_name); 287243730Srwatson return (ADIST_ERROR_WRONG_ORDER); 288243730Srwatson } 289243730Srwatson 290243730Srwatson if (!trail_validate_name(filename, NULL)) { 291243730Srwatson pjdlog_error("Sender wants to open file \"%s\", which has invalid name.", 292243730Srwatson filename); 293243730Srwatson return (ADIST_ERROR_INVALID_NAME); 294243730Srwatson } 295243730Srwatson 296243730Srwatson switch (trail_name_compare(filename, adhost->adh_trail_name)) { 297243730Srwatson case TRAIL_RENAMED: 298243730Srwatson if (!trail_is_not_terminated(adhost->adh_trail_name)) { 299243730Srwatson pjdlog_error("Terminated trail \"%s/%s\" was unterminated on the sender as \"%s/%s\"?", 300243730Srwatson adhost->adh_directory, adhost->adh_trail_name, 301243730Srwatson adhost->adh_directory, filename); 302243730Srwatson return (ADIST_ERROR_INVALID_NAME); 303243730Srwatson } 304243730Srwatson if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 305243730Srwatson adhost->adh_trail_dirfd, filename) == -1) { 306243730Srwatson pjdlog_errno(LOG_ERR, 307243730Srwatson "Unable to rename file \"%s/%s\" to \"%s/%s\"", 308243730Srwatson adhost->adh_directory, adhost->adh_trail_name, 309243730Srwatson adhost->adh_directory, filename); 310243730Srwatson PJDLOG_ASSERT(errno > 0); 311243730Srwatson return (ADIST_ERROR_RENAME); 312243730Srwatson } 313243730Srwatson pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".", 314243730Srwatson adhost->adh_directory, adhost->adh_trail_name, 315243730Srwatson adhost->adh_directory, filename); 316243730Srwatson /* FALLTHROUGH */ 317243730Srwatson case TRAIL_IDENTICAL: 318243730Srwatson /* Opening existing file. */ 319243730Srwatson fd = openat(adhost->adh_trail_dirfd, filename, 320243730Srwatson O_WRONLY | O_APPEND | O_NOFOLLOW); 321243730Srwatson if (fd == -1) { 322243730Srwatson pjdlog_errno(LOG_ERR, 323243730Srwatson "Unable to open file \"%s/%s\" for append", 324243730Srwatson adhost->adh_directory, filename); 325243730Srwatson PJDLOG_ASSERT(errno > 0); 326243730Srwatson return (ADIST_ERROR_OPEN); 327243730Srwatson } 328243730Srwatson pjdlog_debug(1, "Opened file \"%s/%s\".", 329243730Srwatson adhost->adh_directory, filename); 330243730Srwatson break; 331243730Srwatson case TRAIL_NEWER: 332243730Srwatson /* Opening new file. */ 333243730Srwatson fd = openat(adhost->adh_trail_dirfd, filename, 334243730Srwatson O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); 335243730Srwatson if (fd == -1) { 336243730Srwatson pjdlog_errno(LOG_ERR, 337243730Srwatson "Unable to create file \"%s/%s\"", 338243730Srwatson adhost->adh_directory, filename); 339243730Srwatson PJDLOG_ASSERT(errno > 0); 340243730Srwatson return (ADIST_ERROR_CREATE); 341243730Srwatson } 342243730Srwatson pjdlog_debug(1, "Created file \"%s/%s\".", 343243730Srwatson adhost->adh_directory, filename); 344243730Srwatson break; 345243730Srwatson case TRAIL_OLDER: 346243730Srwatson /* Trying to open old file. */ 347243730Srwatson pjdlog_error("Sender wants to open an old file \"%s\".", filename); 348243730Srwatson return (ADIST_ERROR_OPEN_OLD); 349243730Srwatson default: 350243730Srwatson PJDLOG_ABORT("Unknown return value from trail_name_compare()."); 351243730Srwatson } 352243730Srwatson PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename, 353243730Srwatson sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name)); 354243730Srwatson adhost->adh_trail_fd = fd; 355243730Srwatson return (0); 356243730Srwatson} 357243730Srwatson 358243730Srwatson/* 359243730Srwatson * Function appends data to the trail file that is currently open. 360243730Srwatson */ 361243730Srwatsonstatic int 362243730Srwatsonreceiver_append(const unsigned char *data, size_t size) 363243730Srwatson{ 364243730Srwatson ssize_t done; 365243730Srwatson size_t osize; 366243730Srwatson 367243730Srwatson /* We should have opened trail file. */ 368243730Srwatson if (adhost->adh_trail_fd == -1) { 369243730Srwatson pjdlog_error("Sender requested append without first opening file."); 370243730Srwatson return (ADIST_ERROR_WRONG_ORDER); 371243730Srwatson } 372243730Srwatson 373243730Srwatson osize = size; 374243730Srwatson while (size > 0) { 375243730Srwatson done = write(adhost->adh_trail_fd, data, size); 376243730Srwatson if (done == -1) { 377243730Srwatson if (errno == EINTR) 378243730Srwatson continue; 379243730Srwatson pjdlog_errno(LOG_ERR, "Write to \"%s/%s\" failed", 380243730Srwatson adhost->adh_directory, adhost->adh_trail_name); 381243730Srwatson PJDLOG_ASSERT(errno > 0); 382243730Srwatson return (ADIST_ERROR_WRITE); 383243730Srwatson } 384243730Srwatson pjdlog_debug(3, "Wrote %zd bytes into \"%s/%s\".", done, 385243730Srwatson adhost->adh_directory, adhost->adh_trail_name); 386243730Srwatson size -= done; 387243730Srwatson } 388243730Srwatson pjdlog_debug(2, "Appended %zu bytes to file \"%s/%s\".", 389243730Srwatson osize, adhost->adh_directory, adhost->adh_trail_name); 390243730Srwatson return (0); 391243730Srwatson} 392243730Srwatson 393243730Srwatsonstatic int 394243730Srwatsonreceiver_close(const char *filename) 395243730Srwatson{ 396243730Srwatson 397243730Srwatson /* We should have opened trail file. */ 398243730Srwatson if (adhost->adh_trail_fd == -1) { 399243730Srwatson pjdlog_error("Sender requested closing file without first opening it."); 400243730Srwatson return (ADIST_ERROR_WRONG_ORDER); 401243730Srwatson } 402243730Srwatson 403243730Srwatson /* Validate if we can do the rename. */ 404243730Srwatson if (!trail_validate_name(adhost->adh_trail_name, filename)) { 405243730Srwatson pjdlog_error("Sender wants to close file \"%s\" using name \"%s\".", 406243730Srwatson adhost->adh_trail_name, filename); 407243730Srwatson return (ADIST_ERROR_INVALID_NAME); 408243730Srwatson } 409243730Srwatson 410243730Srwatson PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0); 411243730Srwatson adhost->adh_trail_fd = -1; 412243730Srwatson 413243730Srwatson pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory, 414243730Srwatson adhost->adh_trail_name); 415243730Srwatson 416243730Srwatson if (strcmp(adhost->adh_trail_name, filename) == 0) { 417243730Srwatson /* File name didn't change, we are done here. */ 418243730Srwatson return (0); 419243730Srwatson } 420243730Srwatson 421243730Srwatson if (renameat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 422243730Srwatson adhost->adh_trail_dirfd, filename) == -1) { 423243730Srwatson pjdlog_errno(LOG_ERR, "Unable to rename \"%s\" to \"%s\"", 424243730Srwatson adhost->adh_trail_name, filename); 425243730Srwatson PJDLOG_ASSERT(errno > 0); 426243730Srwatson return (ADIST_ERROR_RENAME); 427243730Srwatson } 428243730Srwatson pjdlog_debug(1, "Renamed file \"%s/%s\" to \"%s/%s\".", 429243730Srwatson adhost->adh_directory, adhost->adh_trail_name, 430243730Srwatson adhost->adh_directory, filename); 431243730Srwatson PJDLOG_VERIFY(strlcpy(adhost->adh_trail_name, filename, 432243730Srwatson sizeof(adhost->adh_trail_name)) < sizeof(adhost->adh_trail_name)); 433243730Srwatson 434243730Srwatson return (0); 435243730Srwatson} 436243730Srwatson 437243730Srwatsonstatic int 438243730Srwatsonreceiver_error(void) 439243730Srwatson{ 440243730Srwatson 441243730Srwatson /* We should have opened trail file. */ 442243730Srwatson if (adhost->adh_trail_fd == -1) { 443243730Srwatson pjdlog_error("Sender send read error, but file is not open."); 444243730Srwatson return (ADIST_ERROR_WRONG_ORDER); 445243730Srwatson } 446243730Srwatson 447243730Srwatson PJDLOG_VERIFY(close(adhost->adh_trail_fd) == 0); 448243730Srwatson adhost->adh_trail_fd = -1; 449243730Srwatson 450243730Srwatson pjdlog_debug(1, "Closed file \"%s/%s\".", adhost->adh_directory, 451243730Srwatson adhost->adh_trail_name); 452243730Srwatson 453243730Srwatson return (0); 454243730Srwatson} 455243730Srwatson 456243730Srwatsonstatic void * 457243730Srwatsondisk_thread(void *arg __unused) 458243730Srwatson{ 459243730Srwatson struct adreq *adreq; 460243730Srwatson 461243730Srwatson for (;;) { 462243730Srwatson pjdlog_debug(3, "disk: Taking request."); 463243730Srwatson QUEUE_TAKE(adreq, &adist_disk_list, 0); 464243730Srwatson adreq_log(LOG_DEBUG, 3, -1, adreq, "disk: (%p) Got request: ", 465243730Srwatson adreq); 466243730Srwatson /* Handle the actual request. */ 467243730Srwatson switch (adreq->adr_cmd) { 468243730Srwatson case ADIST_CMD_OPEN: 469243730Srwatson adreq->adr_error = receiver_open(adreq->adr_data); 470243730Srwatson break; 471243730Srwatson case ADIST_CMD_APPEND: 472243730Srwatson adreq->adr_error = receiver_append(adreq->adr_data, 473243730Srwatson adreq->adr_datasize); 474243730Srwatson break; 475243730Srwatson case ADIST_CMD_CLOSE: 476243730Srwatson adreq->adr_error = receiver_close(adreq->adr_data); 477243730Srwatson break; 478243730Srwatson case ADIST_CMD_ERROR: 479243730Srwatson adreq->adr_error = receiver_error(); 480243730Srwatson break; 481243730Srwatson default: 482243730Srwatson PJDLOG_ABORT("Unexpected command (cmd=%hhu).", 483243730Srwatson adreq->adr_cmd); 484243730Srwatson } 485243730Srwatson if (adreq->adr_error != 0) { 486243730Srwatson adreq_log(LOG_ERR, 0, adreq->adr_error, adreq, 487243730Srwatson "Request failed: "); 488243730Srwatson } 489243730Srwatson pjdlog_debug(3, "disk: (%p) Moving request to the send queue.", 490243730Srwatson adreq); 491243730Srwatson QUEUE_INSERT(adreq, &adist_send_list); 492243730Srwatson } 493243730Srwatson /* NOTREACHED */ 494243730Srwatson return (NULL); 495243730Srwatson} 496243730Srwatson 497243730Srwatson/* 498243730Srwatson * Thread sends requests back to primary node. 499243730Srwatson */ 500243730Srwatsonstatic void * 501243730Srwatsonsend_thread(void *arg __unused) 502243730Srwatson{ 503243730Srwatson struct adreq *adreq; 504243730Srwatson struct adrep adrep; 505243730Srwatson 506243730Srwatson for (;;) { 507243730Srwatson pjdlog_debug(3, "send: Taking request."); 508243730Srwatson QUEUE_TAKE(adreq, &adist_send_list, 0); 509243730Srwatson adreq_log(LOG_DEBUG, 3, -1, adreq, "send: (%p) Got request: ", 510243730Srwatson adreq); 511243730Srwatson adrep.adrp_byteorder = ADIST_BYTEORDER; 512243730Srwatson adrep.adrp_seq = adreq->adr_seq; 513243730Srwatson adrep.adrp_error = adreq->adr_error; 514243730Srwatson if (proto_send(adhost->adh_remote, &adrep, 515243730Srwatson sizeof(adrep)) == -1) { 516243730Srwatson pjdlog_exit(EX_TEMPFAIL, "Unable to send reply"); 517243730Srwatson } 518243730Srwatson pjdlog_debug(3, "send: (%p) Moving request to the free queue.", 519243730Srwatson adreq); 520243730Srwatson adreq_clear(adreq); 521243730Srwatson QUEUE_INSERT(adreq, &adist_free_list); 522243730Srwatson } 523243730Srwatson /* NOTREACHED */ 524243730Srwatson return (NULL); 525243730Srwatson} 526243730Srwatson 527243730Srwatsonstatic void 528243730Srwatsonreceiver_directory_create(void) 529243730Srwatson{ 530243730Srwatson struct passwd *pw; 531243730Srwatson 532243730Srwatson /* 533243730Srwatson * According to getpwnam(3) we have to clear errno before calling the 534243730Srwatson * function to be able to distinguish between an error and missing 535243730Srwatson * entry (with is not treated as error by getpwnam(3)). 536243730Srwatson */ 537243730Srwatson errno = 0; 538243730Srwatson pw = getpwnam(ADIST_USER); 539243730Srwatson if (pw == NULL) { 540243730Srwatson if (errno != 0) { 541243730Srwatson pjdlog_exit(EX_NOUSER, 542243730Srwatson "Unable to find info about '%s' user", ADIST_USER); 543243730Srwatson } else { 544243730Srwatson pjdlog_exitx(EX_NOUSER, "User '%s' doesn't exist.", 545243730Srwatson ADIST_USER); 546243730Srwatson } 547243730Srwatson } 548243730Srwatson 549243730Srwatson if (mkdir(adhost->adh_directory, 0700) == -1) { 550243730Srwatson pjdlog_exit(EX_OSFILE, "Unable to create directory \"%s\"", 551243730Srwatson adhost->adh_directory); 552243730Srwatson } 553243730Srwatson if (chown(adhost->adh_directory, pw->pw_uid, pw->pw_gid) == -1) { 554243730Srwatson pjdlog_errno(LOG_ERR, 555243730Srwatson "Unable to change owner of the directory \"%s\"", 556243730Srwatson adhost->adh_directory); 557243730Srwatson (void)rmdir(adhost->adh_directory); 558243730Srwatson exit(EX_OSFILE); 559243730Srwatson } 560243730Srwatson} 561243730Srwatson 562243730Srwatsonstatic void 563243730Srwatsonreceiver_directory_open(void) 564243730Srwatson{ 565243730Srwatson 566243730Srwatson#ifdef HAVE_FDOPENDIR 567243730Srwatson adhost->adh_trail_dirfd = open(adhost->adh_directory, 568243730Srwatson O_RDONLY | O_DIRECTORY); 569243730Srwatson if (adhost->adh_trail_dirfd == -1) { 570243730Srwatson if (errno == ENOENT) { 571243730Srwatson receiver_directory_create(); 572243730Srwatson adhost->adh_trail_dirfd = open(adhost->adh_directory, 573243730Srwatson O_RDONLY | O_DIRECTORY); 574243730Srwatson } 575243730Srwatson if (adhost->adh_trail_dirfd == -1) { 576243730Srwatson pjdlog_exit(EX_CONFIG, 577243730Srwatson "Unable to open directory \"%s\"", 578243730Srwatson adhost->adh_directory); 579243730Srwatson } 580243730Srwatson } 581243730Srwatson adhost->adh_trail_dirfp = fdopendir(adhost->adh_trail_dirfd); 582243730Srwatson if (adhost->adh_trail_dirfp == NULL) { 583243730Srwatson pjdlog_exit(EX_CONFIG, "Unable to fdopen directory \"%s\"", 584243730Srwatson adhost->adh_directory); 585243730Srwatson } 586243730Srwatson#else 587243730Srwatson struct stat sb; 588243730Srwatson 589243730Srwatson if (stat(adhost->adh_directory, &sb) == -1) { 590243730Srwatson if (errno == ENOENT) { 591243730Srwatson receiver_directory_create(); 592243730Srwatson } else { 593243730Srwatson pjdlog_exit(EX_CONFIG, 594243730Srwatson "Unable to stat directory \"%s\"", 595243730Srwatson adhost->adh_directory); 596243730Srwatson } 597243730Srwatson } 598243730Srwatson adhost->adh_trail_dirfp = opendir(adhost->adh_directory); 599243730Srwatson if (adhost->adh_trail_dirfp == NULL) { 600243730Srwatson pjdlog_exit(EX_CONFIG, "Unable to open directory \"%s\"", 601243730Srwatson adhost->adh_directory); 602243730Srwatson } 603243730Srwatson adhost->adh_trail_dirfd = dirfd(adhost->adh_trail_dirfp); 604243730Srwatson#endif 605243730Srwatson} 606243730Srwatson 607243730Srwatsonstatic void 608243730Srwatsonreceiver_connect(void) 609243730Srwatson{ 610243730Srwatson uint64_t trail_size; 611243730Srwatson struct stat sb; 612243730Srwatson 613243730Srwatson PJDLOG_ASSERT(adhost->adh_trail_dirfp != NULL); 614243730Srwatson 615243730Srwatson trail_last(adhost->adh_trail_dirfp, adhost->adh_trail_name, 616243730Srwatson sizeof(adhost->adh_trail_name)); 617243730Srwatson 618243730Srwatson if (adhost->adh_trail_name[0] == '\0') { 619243730Srwatson trail_size = 0; 620243730Srwatson } else { 621243730Srwatson if (fstatat(adhost->adh_trail_dirfd, adhost->adh_trail_name, 622243730Srwatson &sb, AT_SYMLINK_NOFOLLOW) == -1) { 623243730Srwatson pjdlog_exit(EX_CONFIG, "Unable to stat \"%s/%s\"", 624243730Srwatson adhost->adh_directory, adhost->adh_trail_name); 625243730Srwatson } 626243730Srwatson if (!S_ISREG(sb.st_mode)) { 627243730Srwatson pjdlog_exitx(EX_CONFIG, 628243730Srwatson "File \"%s/%s\" is not a regular file.", 629243730Srwatson adhost->adh_directory, adhost->adh_trail_name); 630243730Srwatson } 631243730Srwatson trail_size = sb.st_size; 632243730Srwatson } 633243730Srwatson trail_size = htole64(trail_size); 634243730Srwatson if (proto_send(adhost->adh_remote, &trail_size, 635243730Srwatson sizeof(trail_size)) == -1) { 636243730Srwatson pjdlog_exit(EX_TEMPFAIL, 637243730Srwatson "Unable to send size of the most recent trail file"); 638243730Srwatson } 639243730Srwatson if (proto_send(adhost->adh_remote, adhost->adh_trail_name, 640243730Srwatson sizeof(adhost->adh_trail_name)) == -1) { 641243730Srwatson pjdlog_exit(EX_TEMPFAIL, 642243730Srwatson "Unable to send name of the most recent trail file"); 643243730Srwatson } 644243730Srwatson} 645243730Srwatson 646243730Srwatsonvoid 647243730Srwatsonadist_receiver(struct adist_config *config, struct adist_host *adh) 648243730Srwatson{ 649243730Srwatson sigset_t mask; 650243730Srwatson pthread_t td; 651243730Srwatson pid_t pid; 652243730Srwatson int error, mode, debuglevel; 653243730Srwatson 654243730Srwatson pid = fork(); 655243730Srwatson if (pid == -1) { 656243730Srwatson pjdlog_errno(LOG_ERR, "Unable to fork"); 657243730Srwatson proto_close(adh->adh_remote); 658243730Srwatson adh->adh_remote = NULL; 659243730Srwatson return; 660243730Srwatson } 661243730Srwatson 662243730Srwatson if (pid > 0) { 663243730Srwatson /* This is parent. */ 664243730Srwatson proto_close(adh->adh_remote); 665243730Srwatson adh->adh_remote = NULL; 666243730Srwatson adh->adh_worker_pid = pid; 667243730Srwatson return; 668243730Srwatson } 669243730Srwatson 670243730Srwatson adcfg = config; 671243730Srwatson adhost = adh; 672243730Srwatson mode = pjdlog_mode_get(); 673243730Srwatson debuglevel = pjdlog_debug_get(); 674243730Srwatson 675243730Srwatson descriptors_cleanup(adhost); 676243730Srwatson 677243730Srwatson// descriptors_assert(adhost, mode); 678243730Srwatson 679243730Srwatson pjdlog_init(mode); 680243730Srwatson pjdlog_debug_set(debuglevel); 681243730Srwatson pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, 682243730Srwatson role2str(adhost->adh_role)); 683243730Srwatson#ifdef HAVE_SETPROCTITLE 684243730Srwatson setproctitle("%s (%s)", adhost->adh_name, role2str(adhost->adh_role)); 685243730Srwatson#endif 686243730Srwatson 687243730Srwatson PJDLOG_VERIFY(sigemptyset(&mask) == 0); 688243730Srwatson PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); 689243730Srwatson 690243730Srwatson /* Error in setting timeout is not critical, but why should it fail? */ 691243730Srwatson if (proto_timeout(adhost->adh_remote, adcfg->adc_timeout) == -1) 692243730Srwatson pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); 693243730Srwatson 694243730Srwatson init_environment(); 695243730Srwatson 696243730Srwatson adhost->adh_trail_fd = -1; 697243730Srwatson receiver_directory_open(); 698243730Srwatson 699243730Srwatson if (sandbox(ADIST_USER, true, "auditdistd: %s (%s)", 700243730Srwatson role2str(adhost->adh_role), adhost->adh_name) != 0) { 701243730Srwatson exit(EX_CONFIG); 702243730Srwatson } 703243730Srwatson pjdlog_info("Privileges successfully dropped."); 704243730Srwatson 705243730Srwatson receiver_connect(); 706243730Srwatson 707243730Srwatson error = pthread_create(&td, NULL, recv_thread, adhost); 708243730Srwatson PJDLOG_ASSERT(error == 0); 709243730Srwatson error = pthread_create(&td, NULL, disk_thread, adhost); 710243730Srwatson PJDLOG_ASSERT(error == 0); 711243730Srwatson (void)send_thread(adhost); 712243730Srwatson} 713