]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/openbsm/bin/auditfilterd/auditfilterd.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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
29 /*
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,
35  * etc.
36  */
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41
42 #include <config/config.h>
43 #ifdef HAVE_FULL_QUEUE_H
44 #include <sys/queue.h>
45 #else
46 #include <compat/queue.h>
47 #endif
48
49 #ifndef HAVE_CLOCK_GETTIME
50 #include <compat/clock_gettime.h>
51 #endif
52
53 #include <bsm/libbsm.h>
54 #include <bsm/audit_filter.h>
55 #include <bsm/audit_internal.h>
56
57 #include <err.h>
58 #include <fcntl.h>
59 #include <signal.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63
64 #include "auditfilterd.h"
65
66 /*
67  * Global list of registered filters.
68  */
69 struct auditfilter_module_list  filter_list;
70
71 /*
72  * Configuration and signal->main flags.
73  */
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. */
77
78 static void
79 usage(void)
80 {
81
82         fprintf(stderr, "auditfilterd [-d] [-c conffile] [-p pipefile]"
83             " [-t trailfile]\n");
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");
90         exit(-1);
91 }
92
93 static void
94 auditfilterd_init(void)
95 {
96
97         TAILQ_INIT(&filter_list);
98 }
99
100 static void
101 signal_handler(int signum)
102 {
103
104         switch (signum) {
105         case SIGHUP:
106                 reread_config++;
107                 break;
108
109         case SIGINT:
110         case SIGTERM:
111         case SIGQUIT:
112                 quit++;
113                 break;
114         }
115 }
116
117 /*
118  * Present raw BSM to a set of registered and interested filters.
119  */
120 static void
121 present_rawrecord(struct timespec *ts, u_char *data, u_int len)
122 {
123         struct auditfilter_module *am;
124
125         TAILQ_FOREACH(am, &filter_list, am_list) {
126                 if (am->am_rawrecord != NULL)
127                         (am->am_rawrecord)(am, ts, data, len);
128         }
129 }
130
131 /*
132  * Parse the BSM into a set of tokens, which will be passed to registered
133  * and interested filters.
134  */
135 #define MAX_TOKENS      128     /* Maximum tokens we handle per record. */
136 static void
137 present_tokens(struct timespec *ts, u_char *data, u_int len)
138 {
139         struct auditfilter_module *am;
140         tokenstr_t tokens[MAX_TOKENS];
141         u_int bytesread;
142         int tokencount;
143
144         tokencount = 0;
145         while (bytesread < len) {
146                 if (au_fetch_tok(&tokens[tokencount], data + bytesread,
147                     len - bytesread) == -1)
148                         break;
149                 bytesread += tokens[tokencount].len;
150                 tokencount++;
151         }
152
153         TAILQ_FOREACH(am, &filter_list, am_list) {
154                 if (am->am_record != NULL)
155                         (am->am_record)(am, ts, tokencount, tokens);
156         }
157 }
158
159 /*
160  * The main loop spins pulling records out of the record source and passing
161  * them to modules for processing.
162  */
163 static void
164 mainloop_file(const char *conffile, const char *trailfile, FILE *trail_fp)
165 {
166         struct timespec ts;
167         FILE *conf_fp;
168         u_char *buf;
169         int reclen;
170
171         while (1) {
172                 /*
173                  * On SIGHUP, we reread the configuration file and reopen
174                  * the trail file.
175                  */
176                 if (reread_config) {
177                         reread_config = 0;
178                         warnx("rereading configuration");
179                         conf_fp = fopen(conffile, "r");
180                         if (conf_fp == NULL)
181                                 err(-1, "%s", conffile);
182                         auditfilterd_conf(conffile, conf_fp);
183                         fclose(conf_fp);
184
185                         fclose(trail_fp);
186                         trail_fp = fopen(trailfile, "r");
187                         if (trail_fp == NULL)
188                                 err(-1, "%s", trailfile);
189                 }
190                 if (quit) {
191                         warnx("quitting");
192                         break;
193                 }
194
195                 /*
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.
199                  */
200                 reclen = au_read_rec(trail_fp, &buf);
201                 if (reclen == -1)
202                         continue;
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);
207                 free(buf);
208         }
209 }
210
211 /*
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.
216  */
217 static void
218 mainloop_pipe(const char *conffile, const char *pipefile __unused, int pipe_fd)
219 {
220         u_char record[MAX_AUDIT_RECORD_SIZE];
221         struct timespec ts;
222         FILE *conf_fp;
223         int reclen;
224
225         while (1) {
226                 /*
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.
230                  */
231                 if (reread_config) {
232                         reread_config = 0;
233                         warnx("rereading configuration");
234                         conf_fp = fopen(conffile, "r");
235                         if (conf_fp == NULL)
236                                 err(-1, "%s", conffile);
237                         auditfilterd_conf(conffile, conf_fp);
238                         fclose(conf_fp);
239                 }
240                 if (quit) {
241                         warnx("quitting");
242                         break;
243                 }
244
245                 /*
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.
249                  */
250                 reclen = read(pipe_fd, record, MAX_AUDIT_RECORD_SIZE);
251                 if (reclen < 0)
252                         continue;
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);
257         }
258 }
259
260 int
261 main(int argc, char *argv[])
262 {
263         const char *pipefile, *trailfile, *conffile;
264         FILE *trail_fp, *conf_fp;
265         struct stat sb;
266         int pipe_fd;
267         int ch;
268
269         conffile = AUDITFILTERD_CONFFILE;
270         trailfile = NULL;
271         pipefile = NULL;
272         while ((ch = getopt(argc, argv, "c:dp:t:")) != -1) {
273                 switch (ch) {
274                 case 'c':
275                         conffile = optarg;
276                         break;
277
278                 case 'd':
279                         debug++;
280                         break;
281
282                 case 't':
283                         if (trailfile != NULL || pipefile != NULL)
284                                 usage();
285                         trailfile = optarg;
286                         break;
287
288                 case 'p':
289                         if (pipefile != NULL || trailfile != NULL)
290                                 usage();
291                         pipefile = optarg;
292                         break;
293
294                 default:
295                         usage();
296                 }
297         }
298
299         argc -= optind;
300         argv += optind;
301
302         if (argc != 0)
303                 usage();
304
305         /*
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.
308          */
309         if (pipefile == NULL && trailfile == NULL)
310                 pipefile = AUDITFILTERD_PIPEFILE;
311
312         if (pipefile != NULL) {
313                 pipe_fd = open(pipefile, O_RDONLY);
314                 if (pipe_fd < 0)
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);
320         } else {
321                 trail_fp = fopen(trailfile, "r");
322                 if (trail_fp == NULL)
323                         err(-1, "%s", trailfile);
324         }
325
326         conf_fp = fopen(conffile, "r");
327         if (conf_fp == NULL)
328                 err(-1, "%s", conffile);
329
330         auditfilterd_init();
331         if (auditfilterd_conf(conffile, conf_fp) < 0)
332                 exit(-1);
333         fclose(conf_fp);
334
335         if (!debug) {
336                 if (daemon(0, 0) < 0)
337                         err(-1, "daemon");
338         }
339
340         signal(SIGHUP, signal_handler);
341         signal(SIGINT, signal_handler);
342         signal(SIGQUIT, signal_handler);
343         signal(SIGTERM, signal_handler);
344
345         if (pipefile != NULL)
346                 mainloop_pipe(conffile, pipefile, pipe_fd);
347         else
348                 mainloop_file(conffile, trailfile, trail_fp);
349
350         auditfilterd_conf_shutdown();
351         return (0);
352 }