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