]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/openbsm/bin/auditfilterd/auditfilterd.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / openbsm / bin / auditfilterd / auditfilterd.c
1 /*-
2  * Copyright (c) 2006 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * This software was developed by Robert Watson for the TrustedBSD Project.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditfilterd/auditfilterd.c#11 $
29  */
30
31 /*
32  * Main file for the audit filter daemon, which presents audit records to a
33  * set of run-time registered loadable modules.  This is the main event loop
34  * of the daemon, which handles starting up, waiting for records, and
35  * presenting records to configured modules.  auditfilterd_conf.c handles the
36  * reading and management of the configuration, module list and module state,
37  * etc.
38  */
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43
44 #include <config/config.h>
45 #ifdef HAVE_FULL_QUEUE_H
46 #include <sys/queue.h>
47 #else
48 #include <compat/queue.h>
49 #endif
50
51 #ifndef HAVE_CLOCK_GETTIME
52 #include <compat/clock_gettime.h>
53 #endif
54
55 #include <bsm/libbsm.h>
56 #include <bsm/audit_filter.h>
57
58 #include <err.h>
59 #include <fcntl.h>
60 #include <signal.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <unistd.h>
64
65 #include "auditfilterd.h"
66
67 /*
68  * Global list of registered filters.
69  */
70 struct auditfilter_module_list  filter_list;
71
72 /*
73  * Configuration and signal->main flags.
74  */
75 int     debug;          /* Debugging mode requested, don't detach. */
76 int     reread_config;  /* SIGHUP has been received. */
77 int     quit;           /* SIGQUIT/TERM/INT has been received. */
78
79 static void
80 usage(void)
81 {
82
83         fprintf(stderr, "auditfilterd [-d] [-c conffile] [-p pipefile]"
84             " [-t trailfile]\n");
85         fprintf(stderr, "  -c    Specify configuration file (default: %s)\n",
86             AUDITFILTERD_CONFFILE);
87         fprintf(stderr, "  -d    Debugging mode, don't daemonize\n");
88         fprintf(stderr, "  -p    Specify pipe file (default: %s)\n",
89             AUDITFILTERD_PIPEFILE);
90         fprintf(stderr, "  -t    Specify audit trail file (default: none)\n");
91         exit(-1);
92 }
93
94 static void
95 auditfilterd_init(void)
96 {
97
98         TAILQ_INIT(&filter_list);
99 }
100
101 static void
102 signal_handler(int signum)
103 {
104
105         switch (signum) {
106         case SIGHUP:
107                 reread_config++;
108                 break;
109
110         case SIGINT:
111         case SIGTERM:
112         case SIGQUIT:
113                 quit++;
114                 break;
115         }
116 }
117
118 /*
119  * Present raw BSM to a set of registered and interested filters.
120  */
121 static void
122 present_rawrecord(struct timespec *ts, u_char *data, u_int len)
123 {
124         struct auditfilter_module *am;
125
126         TAILQ_FOREACH(am, &filter_list, am_list) {
127                 if (am->am_rawrecord != NULL)
128                         (am->am_rawrecord)(am, ts, data, len);
129         }
130 }
131
132 /*
133  * Parse the BSM into a set of tokens, which will be pased to registered
134  * and interested filters.
135  */
136 #define MAX_TOKENS      128     /* Maximum tokens we handle per record. */
137 static void
138 present_tokens(struct timespec *ts, u_char *data, u_int len)
139 {
140         struct auditfilter_module *am;
141         tokenstr_t tokens[MAX_TOKENS];
142         u_int bytesread;
143         int tokencount;
144
145         tokencount = 0;
146         while (bytesread < len) {
147                 if (au_fetch_tok(&tokens[tokencount], data + bytesread,
148                     len - bytesread) == -1)
149                         break;
150                 bytesread += tokens[tokencount].len;
151                 tokencount++;
152         }
153
154         TAILQ_FOREACH(am, &filter_list, am_list) {
155                 if (am->am_record != NULL)
156                         (am->am_record)(am, ts, tokencount, tokens);
157         }
158 }
159
160 /*
161  * The main loop spins pulling records out of the record source and passing
162  * them to modules for processing.
163  */
164 static void
165 mainloop_file(const char *conffile, const char *trailfile, FILE *trail_fp)
166 {
167         struct timespec ts;
168         FILE *conf_fp;
169         u_char *buf;
170         int reclen;
171
172         while (1) {
173                 /*
174                  * On SIGHUP, we reread the configuration file and reopen
175                  * the trail file.
176                  */
177                 if (reread_config) {
178                         reread_config = 0;
179                         warnx("rereading configuration");
180                         conf_fp = fopen(conffile, "r");
181                         if (conf_fp == NULL)
182                                 err(-1, "%s", conffile);
183                         auditfilterd_conf(conffile, conf_fp);
184                         fclose(conf_fp);
185
186                         fclose(trail_fp);
187                         trail_fp = fopen(trailfile, "r");
188                         if (trail_fp == NULL)
189                                 err(-1, "%s", trailfile);
190                 }
191                 if (quit) {
192                         warnx("quitting");
193                         break;
194                 }
195
196                 /*
197                  * For now, be relatively unrobust about incomplete records,
198                  * but in the future will want to do better.  Need to look
199                  * more at the right blocking and signal behavior here.
200                  */
201                 reclen = au_read_rec(trail_fp, &buf);
202                 if (reclen == -1)
203                         continue;
204                 if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
205                         err(-1, "clock_gettime");
206                 present_rawrecord(&ts, buf, reclen);
207                 present_tokens(&ts, buf, reclen);
208                 free(buf);
209         }
210 }
211
212 /*
213  * The main loop spins pulling records out of the record source and passing
214  * them to modules for processing.  This version of the function accepts
215  * discrete record input from a file descriptor, as opposed to buffered input
216  * from a file stream.
217  */
218 static void
219 mainloop_pipe(const char *conffile, const char *pipefile, int pipe_fd)
220 {
221         u_char record[MAX_AUDIT_RECORD_SIZE];
222         struct timespec ts;
223         FILE *conf_fp;
224         int reclen;
225
226         while (1) {
227                 /*
228                  * On SIGHUP, we reread the configuration file.  Unlike with
229                  * a trail file, we don't reopen the pipe, as we don't want
230                  * to miss records which will be flushed if we do.
231                  */
232                 if (reread_config) {
233                         reread_config = 0;
234                         warnx("rereading configuration");
235                         conf_fp = fopen(conffile, "r");
236                         if (conf_fp == NULL)
237                                 err(-1, "%s", conffile);
238                         auditfilterd_conf(conffile, conf_fp);
239                         fclose(conf_fp);
240                 }
241                 if (quit) {
242                         warnx("quitting");
243                         break;
244                 }
245
246                 /*
247                  * For now, be relatively unrobust about incomplete records,
248                  * but in the future will want to do better.  Need to look
249                  * more at the right blocking and signal behavior here.
250                  */
251                 reclen = read(pipe_fd, record, MAX_AUDIT_RECORD_SIZE);
252                 if (reclen < 0)
253                         continue;
254                 if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
255                         err(-1, "clock_gettime");
256                 present_rawrecord(&ts, record, reclen);
257                 present_tokens(&ts, record, reclen);
258         }
259 }
260
261 int
262 main(int argc, char *argv[])
263 {
264         const char *pipefile, *trailfile, *conffile;
265         FILE *trail_fp, *conf_fp;
266         struct stat sb;
267         int pipe_fd;
268         int ch;
269
270         conffile = AUDITFILTERD_CONFFILE;
271         trailfile = NULL;
272         pipefile = NULL;
273         while ((ch = getopt(argc, argv, "c:dp:t:")) != -1) {
274                 switch (ch) {
275                 case 'c':
276                         conffile = optarg;
277                         break;
278
279                 case 'd':
280                         debug++;
281                         break;
282
283                 case 't':
284                         if (trailfile != NULL || pipefile != NULL)
285                                 usage();
286                         trailfile = optarg;
287                         break;
288
289                 case 'p':
290                         if (pipefile != NULL || trailfile != NULL)
291                                 usage();
292                         pipefile = optarg;
293                         break;
294
295                 default:
296                         usage();
297                 }
298         }
299
300         argc -= optind;
301         argv += optind;
302
303         if (argc != 0)
304                 usage();
305
306         /*
307          * We allow only one of a pipe or a trail to be used.  If none is
308          * specified, we provide a default pipe path.
309          */
310         if (pipefile == NULL && trailfile == NULL)
311                 pipefile = AUDITFILTERD_PIPEFILE;
312
313         if (pipefile != NULL) {
314                 pipe_fd = open(pipefile, O_RDONLY);
315                 if (pipe_fd < 0)
316                         err(-1, "open:%s", pipefile);
317                 if (fstat(pipe_fd, &sb) < 0)
318                         err(-1, "stat: %s", pipefile);
319                 if (!S_ISCHR(sb.st_mode))
320                         errx(-1, "fstat: %s not device", pipefile);
321         } else {
322                 trail_fp = fopen(trailfile, "r");
323                 if (trail_fp == NULL)
324                         err(-1, "%s", trailfile);
325         }
326
327         conf_fp = fopen(conffile, "r");
328         if (conf_fp == NULL)
329                 err(-1, "%s", conffile);
330
331         auditfilterd_init();
332         if (auditfilterd_conf(conffile, conf_fp) < 0)
333                 exit(-1);
334         fclose(conf_fp);
335
336         if (!debug) {
337                 if (daemon(0, 0) < 0)
338                         err(-1, "daemon");
339         }
340
341         signal(SIGHUP, signal_handler);
342         signal(SIGINT, signal_handler);
343         signal(SIGQUIT, signal_handler);
344         signal(SIGTERM, signal_handler);
345
346         if (pipefile != NULL)
347                 mainloop_pipe(conffile, pipefile, pipe_fd);
348         else
349                 mainloop_file(conffile, trailfile, trail_fp);
350
351         auditfilterd_conf_shutdown();
352         return (0);
353 }