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