]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openbsm/bin/auditreduce/auditreduce.c
Update nvi to 2.2.0-05ed8b9
[FreeBSD/FreeBSD.git] / contrib / openbsm / bin / auditreduce / auditreduce.c
1 /*-
2  * Copyright (c) 2004-2008 Apple Inc.
3  * Copyright (c) 2016 Robert N. M. Watson
4  * All rights reserved.
5  *
6  * Portions of this software were developed by BAE Systems, the University of
7  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
8  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
9  * Computing (TC) research program.
10  * 
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1.  Redistributions of source code must retain the above copyright
15  *     notice, this list of conditions and the following disclaimer. 
16  * 2.  Redistributions in binary form must reproduce the above copyright
17  *     notice, this list of conditions and the following disclaimer in the
18  *     documentation and/or other materials provided with the distribution. 
19  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
20  *     its contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission. 
22  * 
23  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 /* 
37  * Tool used to merge and select audit records from audit trail files 
38  */
39
40 /*
41  * XXX Currently we do not support merging of records from multiple
42  * XXX audit trail files
43  * XXX We assume that records are sorted chronologically - both wrt to 
44  * XXX the records present within the file and between the files themselves
45  */ 
46
47 #include <config/config.h>
48
49 #define _GNU_SOURCE             /* Required for strptime() on glibc2. */
50
51 #ifdef HAVE_FULL_QUEUE_H
52 #include <sys/queue.h>
53 #else
54 #include <compat/queue.h>
55 #endif
56
57 #ifdef HAVE_CAP_ENTER
58 #include <sys/capsicum.h>
59 #include <sys/wait.h>
60 #endif
61
62 #include <bsm/libbsm.h>
63
64 #include <err.h>
65 #include <fnmatch.h>
66 #include <grp.h>
67 #include <pwd.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <sysexits.h>
71 #include <string.h>
72 #include <time.h>
73 #include <unistd.h>
74 #include <regex.h>
75 #include <errno.h>
76
77 #ifndef HAVE_STRLCPY
78 #include <compat/strlcpy.h>
79 #endif
80
81 #include "auditreduce.h"
82
83 static TAILQ_HEAD(tailhead, re_entry) re_head =
84     TAILQ_HEAD_INITIALIZER(re_head);
85
86 extern char             *optarg;
87 extern int               optind, optopt, opterr,optreset;
88
89 static au_mask_t         maskp;         /* Class. */
90 static time_t            p_atime;       /* Created after this time. */
91 static time_t            p_btime;       /* Created before this time. */
92 static int               p_auid;        /* Audit id. */ 
93 static int               p_euid;        /* Effective user id. */
94 static int               p_egid;        /* Effective group id. */ 
95 static int               p_rgid;        /* Real group id. */ 
96 static int               p_ruid;        /* Real user id. */ 
97 static int               p_subid;       /* Subject id. */
98 static const char       *p_zone;        /* Zone. */
99
100 /*
101  * Maintain a dynamically sized array of events for -m
102  */
103 static uint16_t         *p_evec;        /* Event type list */
104 static int               p_evec_used;   /* Number of events used */
105 static int               p_evec_alloc;  /* Number of events allocated */
106
107 /*
108  * Following are the objects (-o option) that we can select upon.
109  */
110 static char     *p_fileobj = NULL;
111 static char     *p_msgqobj = NULL;
112 static char     *p_pidobj = NULL;
113 static char     *p_semobj = NULL;
114 static char     *p_shmobj = NULL;
115 static char     *p_sockobj = NULL; 
116
117 static uint32_t opttochk = 0;
118
119 static int      select_zone(const char *zone, uint32_t *optchkd);
120
121 static void
122 parse_regexp(char *re_string)
123 {
124         char *orig, *copy, re_error[64];
125         struct re_entry *rep;
126         int error, nstrs, i, len;
127
128         copy = strdup(re_string);
129         orig = copy;
130         len = strlen(copy);
131         for (nstrs = 0, i = 0; i < len; i++) {
132                 if (copy[i] == ',' && i > 0) {
133                         if (copy[i - 1] == '\\')
134                                 strlcpy(&copy[i - 1], &copy[i], len);
135                         else {
136                                 nstrs++;
137                                 copy[i] = '\0';
138                         }
139                 }
140         }
141         TAILQ_INIT(&re_head);
142         for (i = 0; i < nstrs + 1; i++) {
143                 rep = calloc(1, sizeof(*rep));
144                 if (rep == NULL) {
145                         (void) fprintf(stderr, "calloc: %s\n",
146                             strerror(errno));
147                         exit(1);
148                 }
149                 if (*copy == '~') {
150                         copy++;
151                         rep->re_negate = 1;
152                 }
153                 rep->re_pattern = strdup(copy);
154                 error = regcomp(&rep->re_regexp, rep->re_pattern,
155                     REG_EXTENDED | REG_NOSUB);
156                 if (error != 0) {
157                         regerror(error, &rep->re_regexp, re_error, 64);
158                         (void) fprintf(stderr, "regcomp: %s\n", re_error);
159                         exit(1);
160                 }
161                 TAILQ_INSERT_TAIL(&re_head, rep, re_glue);
162                 len = strlen(copy);
163                 copy += len + 1;
164         }
165         free(orig);
166 }
167
168 static void
169 usage(const char *msg)
170 {
171         fprintf(stderr, "%s\n", msg);
172         fprintf(stderr, "Usage: auditreduce [options] [file ...]\n");
173         fprintf(stderr, "\tOptions are : \n");
174         fprintf(stderr, "\t-A : all records\n");
175         fprintf(stderr, "\t-a YYYYMMDD[HH[[MM[SS]]] : after date\n");
176         fprintf(stderr, "\t-b YYYYMMDD[HH[[MM[SS]]] : before date\n");
177         fprintf(stderr, "\t-c <flags> : matching class\n");
178         fprintf(stderr, "\t-d YYYYMMDD : on date\n");
179         fprintf(stderr, "\t-e <uid|name>  : effective user\n");
180         fprintf(stderr, "\t-f <gid|group> : effective group\n");
181         fprintf(stderr, "\t-g <gid|group> : real group\n");
182         fprintf(stderr, "\t-j <pid> : subject id \n");
183         fprintf(stderr, "\t-m <evno|evname> : matching event\n");
184         fprintf(stderr, "\t-o objecttype=objectvalue\n");
185         fprintf(stderr, "\t\t file=<pathname>\n");
186         fprintf(stderr, "\t\t msgqid=<ID>\n");
187         fprintf(stderr, "\t\t pid=<ID>\n");
188         fprintf(stderr, "\t\t semid=<ID>\n");
189         fprintf(stderr, "\t\t shmid=<ID>\n");
190         fprintf(stderr, "\t-r <uid|name> : real user\n");
191         fprintf(stderr, "\t-u <uid|name> : audit user\n");
192         fprintf(stderr, "\t-v : select non-matching records\n");
193         fprintf(stderr, "\t-z <zone> : zone name\n");
194         exit(EX_USAGE);
195 }
196
197 /*
198  * Check if the given auid matches the selection criteria.
199  */
200 static int
201 select_auid(int au)
202 {
203
204         /* Check if we want to select on auid. */
205         if (ISOPTSET(opttochk, OPT_u)) {
206                 if (au != p_auid)
207                         return (0);
208         }
209         return (1);
210 }
211
212 /*
213  * Check if the given euid matches the selection criteria.
214  */
215 static int
216 select_euid(int euser)
217 {
218
219         /* Check if we want to select on euid. */
220         if (ISOPTSET(opttochk, OPT_e)) {
221                 if (euser != p_euid)
222                         return (0);
223         }
224         return (1);
225 }
226
227 /*
228  * Check if the given egid matches the selection criteria.
229  */
230 static int
231 select_egid(int egrp)
232 {
233
234         /* Check if we want to select on egid. */
235         if (ISOPTSET(opttochk, OPT_f)) {
236                 if (egrp != p_egid)
237                         return (0);
238         }
239         return (1);
240 }
241
242 /*
243  * Check if the given rgid matches the selection criteria.
244  */
245 static int
246 select_rgid(int grp)
247 {
248
249         /* Check if we want to select on rgid. */
250         if (ISOPTSET(opttochk, OPT_g)) {
251                 if (grp != p_rgid)
252                         return (0);
253         }
254         return (1);
255 }
256
257 /*
258  * Check if the given ruid matches the selection criteria.
259  */
260 static int
261 select_ruid(int user)
262 {
263
264         /* Check if we want to select on rgid. */
265         if (ISOPTSET(opttochk, OPT_r)) {
266                 if (user != p_ruid)
267                         return (0);
268         }
269         return (1);
270 }
271
272 /*
273  * Check if the given subject id (pid) matches the selection criteria.
274  */
275 static int
276 select_subid(int subid)
277 {
278
279         /* Check if we want to select on subject uid. */
280         if (ISOPTSET(opttochk, OPT_j)) {
281                 if (subid != p_subid)
282                         return (0);
283         }
284         return (1);
285 }
286
287
288 /*
289  * Check if object's pid maches the given pid.
290  */ 
291 static int
292 select_pidobj(uint32_t pid) 
293 {
294
295         if (ISOPTSET(opttochk, OPT_op)) {
296                 if (pid != (uint32_t)strtol(p_pidobj, (char **)NULL, 10))
297                         return (0);
298         } 
299         return (1);
300 }
301
302 /*
303  * Check if the given ipc object with the given type matches the selection
304  * criteria.
305  */
306 static int
307 select_ipcobj(u_char type, uint32_t id, uint32_t *optchkd)
308 {
309
310         if (type == AT_IPC_MSG) {
311                 SETOPT((*optchkd), OPT_om);
312                 if (ISOPTSET(opttochk, OPT_om)) {
313                         if (id != (uint32_t)strtol(p_msgqobj, (char **)NULL,
314                             10))
315                                 return (0);
316                 }
317                 return (1);
318         } else if (type == AT_IPC_SEM) {
319                 SETOPT((*optchkd), OPT_ose);
320                 if (ISOPTSET(opttochk, OPT_ose)) {
321                         if (id != (uint32_t)strtol(p_semobj, (char **)NULL, 10))
322                                 return (0);
323                 }
324                 return (1);
325         } else if (type == AT_IPC_SHM) {
326                 SETOPT((*optchkd), OPT_osh);
327                 if (ISOPTSET(opttochk, OPT_osh)) {
328                         if (id != (uint32_t)strtol(p_shmobj, (char **)NULL, 10))
329                                 return (0);
330                 }
331                 return (1);
332         }
333
334         /* Unknown type -- filter if *any* ipc filtering is required. */
335         if (ISOPTSET(opttochk, OPT_om) || ISOPTSET(opttochk, OPT_ose)
336             || ISOPTSET(opttochk, OPT_osh))
337                 return (0);
338
339         return (1);
340 }
341
342
343 /*
344  * Check if the file name matches selection criteria.
345  */
346 static int
347 select_filepath(char *path, uint32_t *optchkd)
348 {
349         struct re_entry *rep;
350         int match;
351
352         SETOPT((*optchkd), OPT_of);
353         match = 1;
354         if (ISOPTSET(opttochk, OPT_of)) {
355                 match = 0;
356                 TAILQ_FOREACH(rep, &re_head, re_glue) {
357                         if (regexec(&rep->re_regexp, path, 0, NULL,
358                             0) != REG_NOMATCH)
359                                 return (!rep->re_negate);
360                 }
361         }
362         return (match);
363 }
364
365 /*
366  * Returns 1 if the following pass the selection rules:
367  *
368  * before-time, 
369  * after time, 
370  * date, 
371  * class, 
372  * event 
373  */
374 static int
375 select_hdr32(tokenstr_t tok, uint32_t *optchkd)
376 {
377         uint16_t *ev;
378         int match;
379
380         SETOPT((*optchkd), (OPT_A | OPT_a | OPT_b | OPT_c | OPT_m | OPT_v));
381
382         /* The A option overrides a, b and d. */
383         if (!ISOPTSET(opttochk, OPT_A)) {
384                 if (ISOPTSET(opttochk, OPT_a)) {
385                         if (difftime((time_t)tok.tt.hdr32.s, p_atime) < 0) {
386                                 /* Record was created before p_atime. */
387                                 return (0);
388                         }
389                 }
390
391                 if (ISOPTSET(opttochk, OPT_b)) {
392                         if (difftime(p_btime, (time_t)tok.tt.hdr32.s) < 0) {
393                                 /* Record was created after p_btime. */
394                                 return (0);
395                         }
396                 }
397         }
398
399         if (ISOPTSET(opttochk, OPT_c)) {
400                 /*
401                  * Check if the classes represented by the event matches
402                  * given class.
403                  */
404                 if (au_preselect(tok.tt.hdr32.e_type, &maskp, AU_PRS_BOTH,
405                     AU_PRS_USECACHE) != 1)
406                         return (0);
407         }
408
409         /* Check if event matches. */
410         if (ISOPTSET(opttochk, OPT_m)) {
411                 match = 0;
412                 for (ev = p_evec; ev < &p_evec[p_evec_used]; ev++)
413                         if (tok.tt.hdr32.e_type == *ev)
414                                 match = 1;
415                 if (match == 0)
416                         return (0);
417         }
418                 
419         return (1);
420 }
421
422 static int
423 select_return32(tokenstr_t tok_ret32, tokenstr_t tok_hdr32, uint32_t *optchkd)
424 {
425         int sorf;
426
427         SETOPT((*optchkd), (OPT_c));
428         if (tok_ret32.tt.ret32.status == 0)
429                 sorf = AU_PRS_SUCCESS;
430         else
431                 sorf = AU_PRS_FAILURE;
432         if (ISOPTSET(opttochk, OPT_c)) {
433                 if (au_preselect(tok_hdr32.tt.hdr32.e_type, &maskp, sorf,
434                     AU_PRS_USECACHE) != 1)
435                         return (0);
436         }
437         return (1);
438 }
439
440 /*
441  * Return 1 if checks for the the following succeed
442  * auid, 
443  * euid, 
444  * egid, 
445  * rgid, 
446  * ruid, 
447  * process id
448  */
449 static int
450 select_proc32(tokenstr_t tok, uint32_t *optchkd)
451 {
452
453         SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_op));
454
455         if (!select_auid(tok.tt.proc32.auid))
456                 return (0);
457         if (!select_euid(tok.tt.proc32.euid))
458                 return (0);
459         if (!select_egid(tok.tt.proc32.egid))
460                 return (0);
461         if (!select_rgid(tok.tt.proc32.rgid))
462                 return (0);
463         if (!select_ruid(tok.tt.proc32.ruid))
464                 return (0);
465         if (!select_pidobj(tok.tt.proc32.pid))
466                 return (0);
467         return (1);
468 }
469
470 /*
471  * Return 1 if checks for the the following succeed
472  * auid, 
473  * euid, 
474  * egid, 
475  * rgid, 
476  * ruid, 
477  * subject id
478  */
479 static int
480 select_subj32(tokenstr_t tok, uint32_t *optchkd)
481 {
482
483         SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_j));
484
485         if (!select_auid(tok.tt.subj32.auid))
486                 return (0);
487         if (!select_euid(tok.tt.subj32.euid))
488                 return (0);
489         if (!select_egid(tok.tt.subj32.egid))
490                 return (0);
491         if (!select_rgid(tok.tt.subj32.rgid))
492                 return (0);
493         if (!select_ruid(tok.tt.subj32.ruid))
494                 return (0);
495         if (!select_subid(tok.tt.subj32.pid))
496                 return (0);
497         return (1);
498 }
499
500 /*
501  * Check if the given zone matches the selection criteria.
502   */
503 static int
504 select_zone(const char *zone, uint32_t *optchkd)
505 {
506
507         SETOPT((*optchkd), OPT_z);
508         if (ISOPTSET(opttochk, OPT_z) && p_zone != NULL) {
509                 if (fnmatch(p_zone, zone, FNM_PATHNAME) != 0)
510                         return (0);
511         }
512         return (1);
513 }
514
515 /*
516  * Read each record from the audit trail.  Check if it is selected after
517  * passing through each of the options 
518  */
519 static int
520 select_records(FILE *fp)
521 {
522         tokenstr_t tok_hdr32_copy;
523         u_char *buf;
524         tokenstr_t tok;
525         int reclen;
526         int bytesread;
527         int selected;
528         uint32_t optchkd;
529         int print;
530
531         int err = 0;
532         while ((reclen = au_read_rec(fp, &buf)) != -1) {
533                 optchkd = 0;
534                 bytesread = 0;
535                 selected = 1;
536                 while ((selected == 1) && (bytesread < reclen)) {
537                         if (-1 == au_fetch_tok(&tok, buf + bytesread,
538                             reclen - bytesread)) {
539                                 /* Is this an incomplete record? */
540                                 err = 1;
541                                 break;
542                         }
543
544                         /*
545                          * For each token type we have have different
546                          * selection criteria.
547                          */
548                         switch(tok.id) {
549                         case AUT_HEADER32:
550                                         selected = select_hdr32(tok,
551                                             &optchkd);
552                                         bcopy(&tok, &tok_hdr32_copy,
553                                             sizeof(tok));
554                                         break;
555
556                         case AUT_PROCESS32:
557                                         selected = select_proc32(tok,
558                                             &optchkd);
559                                         break;
560
561                         case AUT_SUBJECT32:
562                                         selected = select_subj32(tok,
563                                             &optchkd);
564                                         break;
565
566                         case AUT_IPC:
567                                         selected = select_ipcobj(
568                                             tok.tt.ipc.type, tok.tt.ipc.id,
569                                             &optchkd); 
570                                         break;
571
572                         case AUT_PATH:
573                                         selected = select_filepath(
574                                             tok.tt.path.path, &optchkd);
575                                         break;  
576
577                         case AUT_RETURN32:
578                                 selected = select_return32(tok,
579                                     tok_hdr32_copy, &optchkd);
580                                 break;
581
582                         case AUT_ZONENAME:
583                                 selected = select_zone(tok.tt.zonename.zonename, &optchkd);
584                                 break;
585
586                         default:
587                                 break;
588                         }
589                         bytesread += tok.len;
590                 }
591                 /* Check if all the options were matched. */
592                 print = ((selected == 1) && (!err) && (!(opttochk & ~optchkd)));
593                 if (ISOPTSET(opttochk, OPT_v))
594                         print = !print;
595                 if (print)
596                         (void) fwrite(buf, 1, reclen, stdout);
597                 free(buf);
598         }
599         return (0);
600 }
601
602 /* 
603  * The -o option has the form object_type=object_value.  Identify the object
604  * components.
605  */
606 static void
607 parse_object_type(char *name, char *val)
608 {
609         if (val == NULL)
610                 return;
611
612         if (!strcmp(name, FILEOBJ)) {
613                 p_fileobj = val;
614                 parse_regexp(val);
615                 SETOPT(opttochk, OPT_of);
616         } else if (!strcmp(name, MSGQIDOBJ)) {
617                 p_msgqobj = val;
618                 SETOPT(opttochk, OPT_om);
619         } else if (!strcmp(name, PIDOBJ)) {
620                 p_pidobj = val;
621                 SETOPT(opttochk, OPT_op);
622         } else if (!strcmp(name, SEMIDOBJ)) {
623                 p_semobj = val;
624                 SETOPT(opttochk, OPT_ose);
625         } else if (!strcmp(name, SHMIDOBJ)) {
626                 p_shmobj = val;
627                 SETOPT(opttochk, OPT_osh);
628         } else if (!strcmp(name, SOCKOBJ)) {
629                 p_sockobj = val;
630                 SETOPT(opttochk, OPT_oso);
631         } else
632                 usage("unknown value for -o");
633 }
634
635 int
636 main(int argc, char **argv)
637 {
638         struct group *grp;
639         struct passwd *pw;
640         struct tm tm;
641         au_event_t *n;
642         FILE *fp;
643         int i;
644         char *objval, *converr;
645         int ch;
646         char timestr[128];
647         char *fname;
648         uint16_t *etp;
649 #ifdef HAVE_CAP_ENTER
650         int retval, status;
651         pid_t childpid, pid;
652 #endif
653
654         converr = NULL;
655
656         while ((ch = getopt(argc, argv, "Aa:b:c:d:e:f:g:j:m:o:r:u:vz:")) != -1) {
657                 switch(ch) {
658                 case 'A':
659                         SETOPT(opttochk, OPT_A);
660                         break;
661
662                 case 'a':
663                         if (ISOPTSET(opttochk, OPT_a)) {
664                                 usage("d is exclusive with a and b");
665                         }
666                         SETOPT(opttochk, OPT_a);
667                         bzero(&tm, sizeof(tm));
668                         strptime(optarg, "%Y%m%d%H%M%S", &tm);
669                         strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
670                             &tm);
671                         /* fprintf(stderr, "Time converted = %s\n", timestr); */
672                         p_atime = mktime(&tm);
673                         break;  
674
675                 case 'b':
676                         if (ISOPTSET(opttochk, OPT_b)) {
677                                 usage("d is exclusive with a and b");
678                         }
679                         SETOPT(opttochk, OPT_b);
680                         bzero(&tm, sizeof(tm));
681                         strptime(optarg, "%Y%m%d%H%M%S", &tm);
682                         strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
683                             &tm);
684                         /* fprintf(stderr, "Time converted = %s\n", timestr); */
685                         p_btime = mktime(&tm);
686                         break;  
687
688                 case 'c':
689                         if (0 != getauditflagsbin(optarg, &maskp)) {
690                                 /* Incorrect class */
691                                 usage("Incorrect class");
692                         }
693                         SETOPT(opttochk, OPT_c);
694                         break;
695
696                 case 'd':
697                         if (ISOPTSET(opttochk, OPT_b) || ISOPTSET(opttochk,
698                             OPT_a))
699                                 usage("'d' is exclusive with 'a' and 'b'");
700                         SETOPT(opttochk, OPT_d);
701                         bzero(&tm, sizeof(tm));
702                         strptime(optarg, "%Y%m%d", &tm);
703                         strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
704                         /* fprintf(stderr, "Time converted = %s\n", timestr); */
705                         p_atime = mktime(&tm);
706                         tm.tm_hour = 23;
707                         tm.tm_min = 59;
708                         tm.tm_sec = 59;
709                         strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
710                         /* fprintf(stderr, "Time converted = %s\n", timestr); */
711                         p_btime = mktime(&tm);
712                         break;
713
714                 case 'e':
715                         p_euid = strtol(optarg, &converr, 10);
716                         if (*converr != '\0') {
717                                 /* Try the actual name */
718                                 if ((pw = getpwnam(optarg)) == NULL)
719                                         break;
720                                 p_euid = pw->pw_uid;
721                         }
722                         SETOPT(opttochk, OPT_e);
723                         break;
724
725                 case 'f':
726                         p_egid = strtol(optarg, &converr, 10);
727                         if (*converr != '\0') {
728                                 /* Try actual group name. */
729                                 if ((grp = getgrnam(optarg)) == NULL)
730                                         break;
731                                 p_egid = grp->gr_gid;
732                         }
733                         SETOPT(opttochk, OPT_f);
734                         break;
735
736                 case 'g':
737                         p_rgid = strtol(optarg, &converr, 10);
738                         if (*converr != '\0') {
739                                 /* Try actual group name. */
740                                 if ((grp = getgrnam(optarg)) == NULL) 
741                                         break;
742                                 p_rgid = grp->gr_gid;
743                         }
744                         SETOPT(opttochk, OPT_g);
745                         break;
746
747                 case 'j':
748                         p_subid = strtol(optarg, (char **)NULL, 10);
749                         SETOPT(opttochk, OPT_j);
750                         break;
751
752                 case 'm':
753                         if (p_evec == NULL) {
754                                 p_evec_alloc = 32;
755                                 p_evec = malloc(sizeof(*etp) * p_evec_alloc);
756                                 if (p_evec == NULL)
757                                         err(1, "malloc");
758                         } else if (p_evec_alloc == p_evec_used) {
759                                 p_evec_alloc <<= 1;
760                                 p_evec = realloc(p_evec,
761                                     sizeof(*p_evec) * p_evec_alloc);
762                                 if (p_evec == NULL)
763                                         err(1, "realloc");
764                         }
765                         etp = &p_evec[p_evec_used++];
766                         *etp = strtol(optarg, (char **)NULL, 10);
767                         if (*etp == 0) {
768                                 /* Could be the string representation. */
769                                 n = getauevnonam(optarg);
770                                 if (n == NULL)
771                                         usage("Incorrect event name");
772                                 *etp = *n;
773                         }
774                         SETOPT(opttochk, OPT_m);
775                         break;
776
777                 case 'o':
778                         objval = strchr(optarg, '=');
779                         if (objval != NULL) {
780                                 *objval = '\0';
781                                 objval += 1;                    
782                                 parse_object_type(optarg, objval);
783                         }
784                         break;
785
786                 case 'r':
787                         p_ruid = strtol(optarg, &converr, 10);
788                         if (*converr != '\0') {
789                                 if ((pw = getpwnam(optarg)) == NULL)
790                                         break;
791                                 p_ruid = pw->pw_uid;
792                         }
793                         SETOPT(opttochk, OPT_r);
794                         break;
795
796                 case 'u':
797                         p_auid = strtol(optarg, &converr, 10);
798                         if (*converr != '\0') {
799                                 if ((pw = getpwnam(optarg)) == NULL)
800                                         break;
801                                 p_auid = pw->pw_uid;
802                         }
803                         SETOPT(opttochk, OPT_u);
804                         break;
805
806                 case 'v':
807                         SETOPT(opttochk, OPT_v);
808                         break;
809
810                 case 'z':
811                         p_zone = optarg;
812                         SETOPT(opttochk, OPT_z);
813                         break;
814
815                 case '?':
816                 default:
817                         usage("Unknown option");
818                 }
819         }
820         argv += optind;
821         argc -= optind;
822
823         if (argc == 0) {
824 #ifdef HAVE_CAP_ENTER
825                 retval = cap_enter();
826                 if (retval != 0 && errno != ENOSYS)
827                         err(EXIT_FAILURE, "cap_enter");
828 #endif
829                 if (select_records(stdin) == -1)
830                         errx(EXIT_FAILURE,
831                             "Couldn't select records from stdin");
832                 exit(EXIT_SUCCESS);
833         }
834
835         /*
836          * XXX: We should actually be merging records here.
837          */
838         for (i = 0; i < argc; i++) {
839                 fname = argv[i];
840                 fp = fopen(fname, "r");
841                 if (fp == NULL)
842                         errx(EXIT_FAILURE, "Couldn't open %s", fname);
843
844                 /*
845                  * If operating with sandboxing, create a sandbox process for
846                  * each trail file we operate on.  This avoids the need to do
847                  * fancy things with file descriptors, etc, when iterating on
848                  * a list of arguments.
849                  *
850                  * NB: Unlike praudit(1), auditreduce(1) terminates if it hits
851                  * any errors.  Propagate the error from the child to the
852                  * parent if any problems arise.
853                  */
854 #ifdef HAVE_CAP_ENTER
855                 childpid = fork();
856                 if (childpid == 0) {
857                         /* Child. */
858                         retval = cap_enter();
859                         if (retval != 0 && errno != ENOSYS)
860                                 errx(EXIT_FAILURE, "cap_enter");
861                         if (select_records(fp) == -1)
862                                 errx(EXIT_FAILURE,
863                                     "Couldn't select records %s", fname);
864                         exit(0);
865                 }
866
867                 /* Parent.  Await child termination, check exit value. */
868                 while ((pid = waitpid(childpid, &status, 0)) != childpid);
869                 if (WEXITSTATUS(status) != 0)
870                         exit(EXIT_FAILURE);
871 #else
872                 if (select_records(fp) == -1)
873                         errx(EXIT_FAILURE, "Couldn't select records %s",
874                             fname);
875 #endif
876                 fclose(fp);
877         }
878         exit(EXIT_SUCCESS);
879 }