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