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