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