1159248Srwatson/*- 2159248Srwatson * Copyright (c) 2006 Robert N. M. Watson 3159248Srwatson * All rights reserved. 4159248Srwatson * 5159248Srwatson * This software was developed by Robert Watson for the TrustedBSD Project. 6159248Srwatson * 7159248Srwatson * Redistribution and use in source and binary forms, with or without 8159248Srwatson * modification, are permitted provided that the following conditions 9159248Srwatson * are met: 10159248Srwatson * 1. Redistributions of source code must retain the above copyright 11159248Srwatson * notice, this list of conditions and the following disclaimer. 12159248Srwatson * 2. Redistributions in binary form must reproduce the above copyright 13159248Srwatson * notice, this list of conditions and the following disclaimer in the 14159248Srwatson * documentation and/or other materials provided with the distribution. 15159248Srwatson * 16159248Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17159248Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18159248Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19159248Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20159248Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21159248Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22159248Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23159248Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24159248Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25159248Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26159248Srwatson * SUCH DAMAGE. 27159248Srwatson * 28185573Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditfilterd/auditfilterd.c#13 $ 29159248Srwatson */ 30159248Srwatson 31161630Srwatson/* 32161630Srwatson * Main file for the audit filter daemon, which presents audit records to a 33161630Srwatson * set of run-time registered loadable modules. This is the main event loop 34161630Srwatson * of the daemon, which handles starting up, waiting for records, and 35161630Srwatson * presenting records to configured modules. auditfilterd_conf.c handles the 36161630Srwatson * reading and management of the configuration, module list and module state, 37161630Srwatson * etc. 38161630Srwatson */ 39161630Srwatson 40159248Srwatson#include <sys/types.h> 41159248Srwatson#include <sys/stat.h> 42159248Srwatson#include <sys/time.h> 43159248Srwatson 44159248Srwatson#include <config/config.h> 45159248Srwatson#ifdef HAVE_FULL_QUEUE_H 46159248Srwatson#include <sys/queue.h> 47159248Srwatson#else 48159248Srwatson#include <compat/queue.h> 49159248Srwatson#endif 50159248Srwatson 51168777Srwatson#ifndef HAVE_CLOCK_GETTIME 52168777Srwatson#include <compat/clock_gettime.h> 53168777Srwatson#endif 54168777Srwatson 55159248Srwatson#include <bsm/libbsm.h> 56159248Srwatson#include <bsm/audit_filter.h> 57185573Srwatson#include <bsm/audit_internal.h> 58159248Srwatson 59159248Srwatson#include <err.h> 60159248Srwatson#include <fcntl.h> 61159248Srwatson#include <signal.h> 62159248Srwatson#include <stdio.h> 63159248Srwatson#include <stdlib.h> 64159248Srwatson#include <unistd.h> 65159248Srwatson 66159248Srwatson#include "auditfilterd.h" 67159248Srwatson 68159248Srwatson/* 69159248Srwatson * Global list of registered filters. 70159248Srwatson */ 71159248Srwatsonstruct auditfilter_module_list filter_list; 72159248Srwatson 73159248Srwatson/* 74159248Srwatson * Configuration and signal->main flags. 75159248Srwatson */ 76159248Srwatsonint debug; /* Debugging mode requested, don't detach. */ 77159248Srwatsonint reread_config; /* SIGHUP has been received. */ 78159248Srwatsonint quit; /* SIGQUIT/TERM/INT has been received. */ 79159248Srwatson 80159248Srwatsonstatic void 81159248Srwatsonusage(void) 82159248Srwatson{ 83159248Srwatson 84168777Srwatson fprintf(stderr, "auditfilterd [-d] [-c conffile] [-p pipefile]" 85159248Srwatson " [-t trailfile]\n"); 86159248Srwatson fprintf(stderr, " -c Specify configuration file (default: %s)\n", 87159248Srwatson AUDITFILTERD_CONFFILE); 88159248Srwatson fprintf(stderr, " -d Debugging mode, don't daemonize\n"); 89159248Srwatson fprintf(stderr, " -p Specify pipe file (default: %s)\n", 90159248Srwatson AUDITFILTERD_PIPEFILE); 91159248Srwatson fprintf(stderr, " -t Specify audit trail file (default: none)\n"); 92159248Srwatson exit(-1); 93159248Srwatson} 94159248Srwatson 95159248Srwatsonstatic void 96159248Srwatsonauditfilterd_init(void) 97159248Srwatson{ 98159248Srwatson 99159248Srwatson TAILQ_INIT(&filter_list); 100159248Srwatson} 101159248Srwatson 102159248Srwatsonstatic void 103159248Srwatsonsignal_handler(int signum) 104159248Srwatson{ 105159248Srwatson 106159248Srwatson switch (signum) { 107159248Srwatson case SIGHUP: 108159248Srwatson reread_config++; 109159248Srwatson break; 110159248Srwatson 111159248Srwatson case SIGINT: 112159248Srwatson case SIGTERM: 113159248Srwatson case SIGQUIT: 114159248Srwatson quit++; 115159248Srwatson break; 116159248Srwatson } 117159248Srwatson} 118159248Srwatson 119159248Srwatson/* 120159248Srwatson * Present raw BSM to a set of registered and interested filters. 121159248Srwatson */ 122159248Srwatsonstatic void 123161630Srwatsonpresent_rawrecord(struct timespec *ts, u_char *data, u_int len) 124159248Srwatson{ 125159248Srwatson struct auditfilter_module *am; 126159248Srwatson 127159248Srwatson TAILQ_FOREACH(am, &filter_list, am_list) { 128161630Srwatson if (am->am_rawrecord != NULL) 129161630Srwatson (am->am_rawrecord)(am, ts, data, len); 130159248Srwatson } 131159248Srwatson} 132159248Srwatson 133159248Srwatson/* 134159248Srwatson * Parse the BSM into a set of tokens, which will be pased to registered 135159248Srwatson * and interested filters. 136159248Srwatson */ 137159248Srwatson#define MAX_TOKENS 128 /* Maximum tokens we handle per record. */ 138159248Srwatsonstatic void 139159248Srwatsonpresent_tokens(struct timespec *ts, u_char *data, u_int len) 140159248Srwatson{ 141159248Srwatson struct auditfilter_module *am; 142159248Srwatson tokenstr_t tokens[MAX_TOKENS]; 143159248Srwatson u_int bytesread; 144159248Srwatson int tokencount; 145159248Srwatson 146159248Srwatson tokencount = 0; 147159248Srwatson while (bytesread < len) { 148159248Srwatson if (au_fetch_tok(&tokens[tokencount], data + bytesread, 149159248Srwatson len - bytesread) == -1) 150159248Srwatson break; 151159248Srwatson bytesread += tokens[tokencount].len; 152159248Srwatson tokencount++; 153159248Srwatson } 154159248Srwatson 155159248Srwatson TAILQ_FOREACH(am, &filter_list, am_list) { 156159248Srwatson if (am->am_record != NULL) 157161630Srwatson (am->am_record)(am, ts, tokencount, tokens); 158159248Srwatson } 159159248Srwatson} 160159248Srwatson 161159248Srwatson/* 162159248Srwatson * The main loop spins pulling records out of the record source and passing 163159248Srwatson * them to modules for processing. 164159248Srwatson */ 165159248Srwatsonstatic void 166159248Srwatsonmainloop_file(const char *conffile, const char *trailfile, FILE *trail_fp) 167159248Srwatson{ 168159248Srwatson struct timespec ts; 169159248Srwatson FILE *conf_fp; 170159248Srwatson u_char *buf; 171159248Srwatson int reclen; 172159248Srwatson 173159248Srwatson while (1) { 174159248Srwatson /* 175159248Srwatson * On SIGHUP, we reread the configuration file and reopen 176159248Srwatson * the trail file. 177159248Srwatson */ 178159248Srwatson if (reread_config) { 179159248Srwatson reread_config = 0; 180159248Srwatson warnx("rereading configuration"); 181159248Srwatson conf_fp = fopen(conffile, "r"); 182159248Srwatson if (conf_fp == NULL) 183159248Srwatson err(-1, "%s", conffile); 184159248Srwatson auditfilterd_conf(conffile, conf_fp); 185159248Srwatson fclose(conf_fp); 186159248Srwatson 187159248Srwatson fclose(trail_fp); 188159248Srwatson trail_fp = fopen(trailfile, "r"); 189159248Srwatson if (trail_fp == NULL) 190159248Srwatson err(-1, "%s", trailfile); 191159248Srwatson } 192159248Srwatson if (quit) { 193159248Srwatson warnx("quitting"); 194159248Srwatson break; 195159248Srwatson } 196159248Srwatson 197159248Srwatson /* 198159248Srwatson * For now, be relatively unrobust about incomplete records, 199159248Srwatson * but in the future will want to do better. Need to look 200159248Srwatson * more at the right blocking and signal behavior here. 201159248Srwatson */ 202159248Srwatson reclen = au_read_rec(trail_fp, &buf); 203159248Srwatson if (reclen == -1) 204159248Srwatson continue; 205159248Srwatson if (clock_gettime(CLOCK_REALTIME, &ts) < 0) 206159248Srwatson err(-1, "clock_gettime"); 207161630Srwatson present_rawrecord(&ts, buf, reclen); 208159248Srwatson present_tokens(&ts, buf, reclen); 209159248Srwatson free(buf); 210159248Srwatson } 211159248Srwatson} 212159248Srwatson 213159248Srwatson/* 214159248Srwatson * The main loop spins pulling records out of the record source and passing 215159248Srwatson * them to modules for processing. This version of the function accepts 216159248Srwatson * discrete record input from a file descriptor, as opposed to buffered input 217159248Srwatson * from a file stream. 218159248Srwatson */ 219159248Srwatsonstatic void 220185573Srwatsonmainloop_pipe(const char *conffile, const char *pipefile __unused, int pipe_fd) 221159248Srwatson{ 222159248Srwatson u_char record[MAX_AUDIT_RECORD_SIZE]; 223159248Srwatson struct timespec ts; 224159248Srwatson FILE *conf_fp; 225159248Srwatson int reclen; 226159248Srwatson 227159248Srwatson while (1) { 228159248Srwatson /* 229159248Srwatson * On SIGHUP, we reread the configuration file. Unlike with 230159248Srwatson * a trail file, we don't reopen the pipe, as we don't want 231159248Srwatson * to miss records which will be flushed if we do. 232159248Srwatson */ 233159248Srwatson if (reread_config) { 234159248Srwatson reread_config = 0; 235159248Srwatson warnx("rereading configuration"); 236159248Srwatson conf_fp = fopen(conffile, "r"); 237159248Srwatson if (conf_fp == NULL) 238159248Srwatson err(-1, "%s", conffile); 239159248Srwatson auditfilterd_conf(conffile, conf_fp); 240159248Srwatson fclose(conf_fp); 241159248Srwatson } 242159248Srwatson if (quit) { 243159248Srwatson warnx("quitting"); 244159248Srwatson break; 245159248Srwatson } 246159248Srwatson 247159248Srwatson /* 248159248Srwatson * For now, be relatively unrobust about incomplete records, 249159248Srwatson * but in the future will want to do better. Need to look 250159248Srwatson * more at the right blocking and signal behavior here. 251159248Srwatson */ 252159248Srwatson reclen = read(pipe_fd, record, MAX_AUDIT_RECORD_SIZE); 253159248Srwatson if (reclen < 0) 254159248Srwatson continue; 255159248Srwatson if (clock_gettime(CLOCK_REALTIME, &ts) < 0) 256159248Srwatson err(-1, "clock_gettime"); 257161630Srwatson present_rawrecord(&ts, record, reclen); 258159248Srwatson present_tokens(&ts, record, reclen); 259159248Srwatson } 260159248Srwatson} 261159248Srwatson 262159248Srwatsonint 263159248Srwatsonmain(int argc, char *argv[]) 264159248Srwatson{ 265159248Srwatson const char *pipefile, *trailfile, *conffile; 266159248Srwatson FILE *trail_fp, *conf_fp; 267159248Srwatson struct stat sb; 268159248Srwatson int pipe_fd; 269159248Srwatson int ch; 270159248Srwatson 271159248Srwatson conffile = AUDITFILTERD_CONFFILE; 272159248Srwatson trailfile = NULL; 273159248Srwatson pipefile = NULL; 274159248Srwatson while ((ch = getopt(argc, argv, "c:dp:t:")) != -1) { 275159248Srwatson switch (ch) { 276159248Srwatson case 'c': 277159248Srwatson conffile = optarg; 278159248Srwatson break; 279159248Srwatson 280159248Srwatson case 'd': 281159248Srwatson debug++; 282159248Srwatson break; 283159248Srwatson 284159248Srwatson case 't': 285159248Srwatson if (trailfile != NULL || pipefile != NULL) 286159248Srwatson usage(); 287159248Srwatson trailfile = optarg; 288159248Srwatson break; 289159248Srwatson 290159248Srwatson case 'p': 291159248Srwatson if (pipefile != NULL || trailfile != NULL) 292159248Srwatson usage(); 293159248Srwatson pipefile = optarg; 294159248Srwatson break; 295159248Srwatson 296159248Srwatson default: 297159248Srwatson usage(); 298159248Srwatson } 299159248Srwatson } 300159248Srwatson 301159248Srwatson argc -= optind; 302159248Srwatson argv += optind; 303159248Srwatson 304159248Srwatson if (argc != 0) 305159248Srwatson usage(); 306159248Srwatson 307159248Srwatson /* 308159248Srwatson * We allow only one of a pipe or a trail to be used. If none is 309159248Srwatson * specified, we provide a default pipe path. 310159248Srwatson */ 311159248Srwatson if (pipefile == NULL && trailfile == NULL) 312159248Srwatson pipefile = AUDITFILTERD_PIPEFILE; 313159248Srwatson 314159248Srwatson if (pipefile != NULL) { 315159248Srwatson pipe_fd = open(pipefile, O_RDONLY); 316159248Srwatson if (pipe_fd < 0) 317159248Srwatson err(-1, "open:%s", pipefile); 318159248Srwatson if (fstat(pipe_fd, &sb) < 0) 319159248Srwatson err(-1, "stat: %s", pipefile); 320159248Srwatson if (!S_ISCHR(sb.st_mode)) 321159248Srwatson errx(-1, "fstat: %s not device", pipefile); 322159248Srwatson } else { 323159248Srwatson trail_fp = fopen(trailfile, "r"); 324159248Srwatson if (trail_fp == NULL) 325159248Srwatson err(-1, "%s", trailfile); 326159248Srwatson } 327159248Srwatson 328159248Srwatson conf_fp = fopen(conffile, "r"); 329159248Srwatson if (conf_fp == NULL) 330159248Srwatson err(-1, "%s", conffile); 331159248Srwatson 332159248Srwatson auditfilterd_init(); 333159248Srwatson if (auditfilterd_conf(conffile, conf_fp) < 0) 334159248Srwatson exit(-1); 335159248Srwatson fclose(conf_fp); 336159248Srwatson 337159248Srwatson if (!debug) { 338159248Srwatson if (daemon(0, 0) < 0) 339159248Srwatson err(-1, "daemon"); 340159248Srwatson } 341159248Srwatson 342159248Srwatson signal(SIGHUP, signal_handler); 343159248Srwatson signal(SIGINT, signal_handler); 344159248Srwatson signal(SIGQUIT, signal_handler); 345159248Srwatson signal(SIGTERM, signal_handler); 346159248Srwatson 347159248Srwatson if (pipefile != NULL) 348159248Srwatson mainloop_pipe(conffile, pipefile, pipe_fd); 349159248Srwatson else 350159248Srwatson mainloop_file(conffile, trailfile, trail_fp); 351159248Srwatson 352159248Srwatson auditfilterd_conf_shutdown(); 353159248Srwatson return (0); 354159248Srwatson} 355