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