2 * Copyright (c) 2006 Robert N. M. Watson
5 * This software was developed by Robert Watson for the TrustedBSD Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Main file for the audit filter daemon, which presents audit records to a
31 * set of run-time registered loadable modules. This is the main event loop
32 * of the daemon, which handles starting up, waiting for records, and
33 * presenting records to configured modules. auditfilterd_conf.c handles the
34 * reading and management of the configuration, module list and module state,
38 #include <sys/types.h>
42 #include <config/config.h>
43 #ifdef HAVE_FULL_QUEUE_H
44 #include <sys/queue.h>
46 #include <compat/queue.h>
49 #ifndef HAVE_CLOCK_GETTIME
50 #include <compat/clock_gettime.h>
53 #include <bsm/libbsm.h>
54 #include <bsm/audit_filter.h>
55 #include <bsm/audit_internal.h>
64 #include "auditfilterd.h"
67 * Global list of registered filters.
69 struct auditfilter_module_list filter_list;
72 * Configuration and signal->main flags.
74 int debug; /* Debugging mode requested, don't detach. */
75 int reread_config; /* SIGHUP has been received. */
76 int quit; /* SIGQUIT/TERM/INT has been received. */
82 fprintf(stderr, "auditfilterd [-d] [-c conffile] [-p pipefile]"
84 fprintf(stderr, " -c Specify configuration file (default: %s)\n",
85 AUDITFILTERD_CONFFILE);
86 fprintf(stderr, " -d Debugging mode, don't daemonize\n");
87 fprintf(stderr, " -p Specify pipe file (default: %s)\n",
88 AUDITFILTERD_PIPEFILE);
89 fprintf(stderr, " -t Specify audit trail file (default: none)\n");
94 auditfilterd_init(void)
97 TAILQ_INIT(&filter_list);
101 signal_handler(int signum)
118 * Present raw BSM to a set of registered and interested filters.
121 present_rawrecord(struct timespec *ts, u_char *data, u_int len)
123 struct auditfilter_module *am;
125 TAILQ_FOREACH(am, &filter_list, am_list) {
126 if (am->am_rawrecord != NULL)
127 (am->am_rawrecord)(am, ts, data, len);
132 * Parse the BSM into a set of tokens, which will be passed to registered
133 * and interested filters.
135 #define MAX_TOKENS 128 /* Maximum tokens we handle per record. */
137 present_tokens(struct timespec *ts, u_char *data, u_int len)
139 struct auditfilter_module *am;
140 tokenstr_t tokens[MAX_TOKENS];
145 while (bytesread < len) {
146 if (au_fetch_tok(&tokens[tokencount], data + bytesread,
147 len - bytesread) == -1)
149 bytesread += tokens[tokencount].len;
153 TAILQ_FOREACH(am, &filter_list, am_list) {
154 if (am->am_record != NULL)
155 (am->am_record)(am, ts, tokencount, tokens);
160 * The main loop spins pulling records out of the record source and passing
161 * them to modules for processing.
164 mainloop_file(const char *conffile, const char *trailfile, FILE *trail_fp)
173 * On SIGHUP, we reread the configuration file and reopen
178 warnx("rereading configuration");
179 conf_fp = fopen(conffile, "r");
181 err(-1, "%s", conffile);
182 auditfilterd_conf(conffile, conf_fp);
186 trail_fp = fopen(trailfile, "r");
187 if (trail_fp == NULL)
188 err(-1, "%s", trailfile);
196 * For now, be relatively unrobust about incomplete records,
197 * but in the future will want to do better. Need to look
198 * more at the right blocking and signal behavior here.
200 reclen = au_read_rec(trail_fp, &buf);
203 if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
204 err(-1, "clock_gettime");
205 present_rawrecord(&ts, buf, reclen);
206 present_tokens(&ts, buf, reclen);
212 * The main loop spins pulling records out of the record source and passing
213 * them to modules for processing. This version of the function accepts
214 * discrete record input from a file descriptor, as opposed to buffered input
215 * from a file stream.
218 mainloop_pipe(const char *conffile, const char *pipefile __unused, int pipe_fd)
220 u_char record[MAX_AUDIT_RECORD_SIZE];
227 * On SIGHUP, we reread the configuration file. Unlike with
228 * a trail file, we don't reopen the pipe, as we don't want
229 * to miss records which will be flushed if we do.
233 warnx("rereading configuration");
234 conf_fp = fopen(conffile, "r");
236 err(-1, "%s", conffile);
237 auditfilterd_conf(conffile, conf_fp);
246 * For now, be relatively unrobust about incomplete records,
247 * but in the future will want to do better. Need to look
248 * more at the right blocking and signal behavior here.
250 reclen = read(pipe_fd, record, MAX_AUDIT_RECORD_SIZE);
253 if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
254 err(-1, "clock_gettime");
255 present_rawrecord(&ts, record, reclen);
256 present_tokens(&ts, record, reclen);
261 main(int argc, char *argv[])
263 const char *pipefile, *trailfile, *conffile;
264 FILE *trail_fp, *conf_fp;
269 conffile = AUDITFILTERD_CONFFILE;
272 while ((ch = getopt(argc, argv, "c:dp:t:")) != -1) {
283 if (trailfile != NULL || pipefile != NULL)
289 if (pipefile != NULL || trailfile != NULL)
306 * We allow only one of a pipe or a trail to be used. If none is
307 * specified, we provide a default pipe path.
309 if (pipefile == NULL && trailfile == NULL)
310 pipefile = AUDITFILTERD_PIPEFILE;
312 if (pipefile != NULL) {
313 pipe_fd = open(pipefile, O_RDONLY);
315 err(-1, "open:%s", pipefile);
316 if (fstat(pipe_fd, &sb) < 0)
317 err(-1, "stat: %s", pipefile);
318 if (!S_ISCHR(sb.st_mode))
319 errx(-1, "fstat: %s not device", pipefile);
321 trail_fp = fopen(trailfile, "r");
322 if (trail_fp == NULL)
323 err(-1, "%s", trailfile);
326 conf_fp = fopen(conffile, "r");
328 err(-1, "%s", conffile);
331 if (auditfilterd_conf(conffile, conf_fp) < 0)
336 if (daemon(0, 0) < 0)
340 signal(SIGHUP, signal_handler);
341 signal(SIGINT, signal_handler);
342 signal(SIGQUIT, signal_handler);
343 signal(SIGTERM, signal_handler);
345 if (pipefile != NULL)
346 mainloop_pipe(conffile, pipefile, pipe_fd);
348 mainloop_file(conffile, trailfile, trail_fp);
350 auditfilterd_conf_shutdown();