1185573Srwatson/*-
2185573Srwatson * Copyright (c) 2004-2008 Apple Inc.
3155131Srwatson * All rights reserved.
4155131Srwatson *
5155131Srwatson * Redistribution and use in source and binary forms, with or without
6155131Srwatson * modification, are permitted provided that the following conditions
7155131Srwatson * are met:
8155131Srwatson * 1.  Redistributions of source code must retain the above copyright
9155131Srwatson *     notice, this list of conditions and the following disclaimer.
10155131Srwatson * 2.  Redistributions in binary form must reproduce the above copyright
11155131Srwatson *     notice, this list of conditions and the following disclaimer in the
12155131Srwatson *     documentation and/or other materials provided with the distribution.
13185573Srwatson * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14155131Srwatson *     its contributors may be used to endorse or promote products derived
15155131Srwatson *     from this software without specific prior written permission.
16155131Srwatson *
17155131Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18155131Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19155131Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20155131Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21155131Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22155131Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23155131Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24155131Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25155131Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26155131Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27155131Srwatson * POSSIBILITY OF SUCH DAMAGE.
28155131Srwatson *
29187214Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditreduce/auditreduce.c#31 $
30155131Srwatson */
31155131Srwatson
32155131Srwatson/*
33155131Srwatson * Tool used to merge and select audit records from audit trail files
34155131Srwatson */
35155131Srwatson
36155131Srwatson/*
37155131Srwatson * XXX Currently we do not support merging of records from multiple
38155131Srwatson * XXX audit trail files
39155131Srwatson * XXX We assume that records are sorted chronologically - both wrt to
40155131Srwatson * XXX the records present within the file and between the files themselves
41155131Srwatson */
42155131Srwatson
43162621Srwatson#include <config/config.h>
44187214Srwatson
45187214Srwatson#define	_GNU_SOURCE		/* Required for strptime() on glibc2. */
46187214Srwatson
47162621Srwatson#ifdef HAVE_FULL_QUEUE_H
48162621Srwatson#include <sys/queue.h>
49162621Srwatson#else
50162621Srwatson#include <compat/queue.h>
51162621Srwatson#endif
52162621Srwatson
53155131Srwatson#include <bsm/libbsm.h>
54155131Srwatson
55159248Srwatson#include <err.h>
56159248Srwatson#include <grp.h>
57159248Srwatson#include <pwd.h>
58155131Srwatson#include <stdio.h>
59155131Srwatson#include <stdlib.h>
60155131Srwatson#include <sysexits.h>
61155131Srwatson#include <string.h>
62155131Srwatson#include <time.h>
63155131Srwatson#include <unistd.h>
64162621Srwatson#include <regex.h>
65162621Srwatson#include <errno.h>
66155131Srwatson
67185573Srwatson#ifndef HAVE_STRLCPY
68185573Srwatson#include <compat/strlcpy.h>
69185573Srwatson#endif
70185573Srwatson
71155131Srwatson#include "auditreduce.h"
72155131Srwatson
73162621Srwatsonstatic TAILQ_HEAD(tailhead, re_entry) re_head =
74162621Srwatson    TAILQ_HEAD_INITIALIZER(re_head);
75162621Srwatson
76155131Srwatsonextern char		*optarg;
77155131Srwatsonextern int		 optind, optopt, opterr,optreset;
78155131Srwatson
79155131Srwatsonstatic au_mask_t	 maskp;		/* Class. */
80155131Srwatsonstatic time_t		 p_atime;	/* Created after this time. */
81155131Srwatsonstatic time_t		 p_btime;	/* Created before this time. */
82155131Srwatsonstatic int		 p_auid;	/* Audit id. */
83155131Srwatsonstatic int		 p_euid;	/* Effective user id. */
84155131Srwatsonstatic int		 p_egid;	/* Effective group id. */
85155131Srwatsonstatic int		 p_rgid;	/* Real group id. */
86155131Srwatsonstatic int		 p_ruid;	/* Real user id. */
87155131Srwatsonstatic int		 p_subid;	/* Subject id. */
88155131Srwatson
89155131Srwatson/*
90185573Srwatson * Maintain a dynamically sized array of events for -m
91185573Srwatson */
92185573Srwatsonstatic uint16_t		*p_evec;	/* Event type list */
93185573Srwatsonstatic int		 p_evec_used;	/* Number of events used */
94185573Srwatsonstatic int		 p_evec_alloc;	/* Number of events allocated */
95185573Srwatson
96185573Srwatson/*
97155131Srwatson * Following are the objects (-o option) that we can select upon.
98155131Srwatson */
99155131Srwatsonstatic char	*p_fileobj = NULL;
100155131Srwatsonstatic char	*p_msgqobj = NULL;
101155131Srwatsonstatic char	*p_pidobj = NULL;
102155131Srwatsonstatic char	*p_semobj = NULL;
103155131Srwatsonstatic char	*p_shmobj = NULL;
104155131Srwatsonstatic char	*p_sockobj = NULL;
105155131Srwatson
106155131Srwatsonstatic uint32_t opttochk = 0;
107155131Srwatson
108155131Srwatsonstatic void
109162621Srwatsonparse_regexp(char *re_string)
110162621Srwatson{
111162621Srwatson	char *orig, *copy, re_error[64];
112162621Srwatson	struct re_entry *rep;
113162621Srwatson	int error, nstrs, i, len;
114162621Srwatson
115162621Srwatson	copy = strdup(re_string);
116162621Srwatson	orig = copy;
117162621Srwatson	len = strlen(copy);
118162621Srwatson	for (nstrs = 0, i = 0; i < len; i++) {
119162621Srwatson		if (copy[i] == ',' && i > 0) {
120162621Srwatson			if (copy[i - 1] == '\\')
121185573Srwatson				strlcpy(&copy[i - 1], &copy[i], len);
122162621Srwatson			else {
123162621Srwatson				nstrs++;
124162621Srwatson				copy[i] = '\0';
125162621Srwatson			}
126162621Srwatson		}
127162621Srwatson	}
128162621Srwatson	TAILQ_INIT(&re_head);
129162621Srwatson	for (i = 0; i < nstrs + 1; i++) {
130162621Srwatson		rep = calloc(1, sizeof(*rep));
131162621Srwatson		if (rep == NULL) {
132162621Srwatson			(void) fprintf(stderr, "calloc: %s\n",
133162621Srwatson			    strerror(errno));
134162621Srwatson			exit(1);
135162621Srwatson		}
136162621Srwatson		if (*copy == '~') {
137162621Srwatson			copy++;
138162621Srwatson			rep->re_negate = 1;
139162621Srwatson		}
140162621Srwatson		rep->re_pattern = strdup(copy);
141162621Srwatson		error = regcomp(&rep->re_regexp, rep->re_pattern,
142162621Srwatson		    REG_EXTENDED | REG_NOSUB);
143162621Srwatson		if (error != 0) {
144162621Srwatson			regerror(error, &rep->re_regexp, re_error, 64);
145162621Srwatson			(void) fprintf(stderr, "regcomp: %s\n", re_error);
146162621Srwatson			exit(1);
147162621Srwatson		}
148162621Srwatson		TAILQ_INSERT_TAIL(&re_head, rep, re_glue);
149162621Srwatson		len = strlen(copy);
150162621Srwatson		copy += len + 1;
151162621Srwatson	}
152162621Srwatson	free(orig);
153162621Srwatson}
154162621Srwatson
155162621Srwatsonstatic void
156155131Srwatsonusage(const char *msg)
157155131Srwatson{
158155131Srwatson	fprintf(stderr, "%s\n", msg);
159162621Srwatson	fprintf(stderr, "Usage: auditreduce [options] [file ...]\n");
160155131Srwatson	fprintf(stderr, "\tOptions are : \n");
161155131Srwatson	fprintf(stderr, "\t-A : all records\n");
162155131Srwatson	fprintf(stderr, "\t-a YYYYMMDD[HH[[MM[SS]]] : after date\n");
163155131Srwatson	fprintf(stderr, "\t-b YYYYMMDD[HH[[MM[SS]]] : before date\n");
164155131Srwatson	fprintf(stderr, "\t-c <flags> : matching class\n");
165155131Srwatson	fprintf(stderr, "\t-d YYYYMMDD : on date\n");
166155131Srwatson	fprintf(stderr, "\t-e <uid|name>  : effective user\n");
167155131Srwatson	fprintf(stderr, "\t-f <gid|group> : effective group\n");
168155131Srwatson	fprintf(stderr, "\t-g <gid|group> : real group\n");
169155131Srwatson	fprintf(stderr, "\t-j <pid> : subject id \n");
170155131Srwatson	fprintf(stderr, "\t-m <evno|evname> : matching event\n");
171155131Srwatson	fprintf(stderr, "\t-o objecttype=objectvalue\n");
172155131Srwatson	fprintf(stderr, "\t\t file=<pathname>\n");
173155131Srwatson	fprintf(stderr, "\t\t msgqid=<ID>\n");
174155131Srwatson	fprintf(stderr, "\t\t pid=<ID>\n");
175155131Srwatson	fprintf(stderr, "\t\t semid=<ID>\n");
176155131Srwatson	fprintf(stderr, "\t\t shmid=<ID>\n");
177155131Srwatson	fprintf(stderr, "\t-r <uid|name> : real user\n");
178155131Srwatson	fprintf(stderr, "\t-u <uid|name> : audit user\n");
179185573Srwatson	fprintf(stderr, "\t-v : select non-matching records\n");
180155131Srwatson	exit(EX_USAGE);
181155131Srwatson}
182155131Srwatson
183155131Srwatson/*
184155131Srwatson * Check if the given auid matches the selection criteria.
185155131Srwatson */
186155131Srwatsonstatic int
187155131Srwatsonselect_auid(int au)
188155131Srwatson{
189155131Srwatson
190155131Srwatson	/* Check if we want to select on auid. */
191155131Srwatson	if (ISOPTSET(opttochk, OPT_u)) {
192155131Srwatson		if (au != p_auid)
193155131Srwatson			return (0);
194155131Srwatson	}
195155131Srwatson	return (1);
196155131Srwatson}
197155131Srwatson
198155131Srwatson/*
199155131Srwatson * Check if the given euid matches the selection criteria.
200155131Srwatson */
201155131Srwatsonstatic int
202155131Srwatsonselect_euid(int euser)
203155131Srwatson{
204155131Srwatson
205155131Srwatson	/* Check if we want to select on euid. */
206155131Srwatson	if (ISOPTSET(opttochk, OPT_e)) {
207155131Srwatson		if (euser != p_euid)
208155131Srwatson			return (0);
209155131Srwatson	}
210155131Srwatson	return (1);
211155131Srwatson}
212155131Srwatson
213155131Srwatson/*
214155131Srwatson * Check if the given egid matches the selection criteria.
215155131Srwatson */
216155131Srwatsonstatic int
217155131Srwatsonselect_egid(int egrp)
218155131Srwatson{
219155131Srwatson
220155131Srwatson	/* Check if we want to select on egid. */
221155131Srwatson	if (ISOPTSET(opttochk, OPT_f)) {
222155131Srwatson		if (egrp != p_egid)
223155131Srwatson			return (0);
224155131Srwatson	}
225155131Srwatson	return (1);
226155131Srwatson}
227155131Srwatson
228155131Srwatson/*
229155131Srwatson * Check if the given rgid matches the selection criteria.
230155131Srwatson */
231155131Srwatsonstatic int
232155131Srwatsonselect_rgid(int grp)
233155131Srwatson{
234155131Srwatson
235155131Srwatson	/* Check if we want to select on rgid. */
236155131Srwatson	if (ISOPTSET(opttochk, OPT_g)) {
237155131Srwatson		if (grp != p_rgid)
238155131Srwatson			return (0);
239155131Srwatson	}
240155131Srwatson	return (1);
241155131Srwatson}
242155131Srwatson
243155131Srwatson/*
244155131Srwatson * Check if the given ruid matches the selection criteria.
245155131Srwatson */
246155131Srwatsonstatic int
247155131Srwatsonselect_ruid(int user)
248155131Srwatson{
249155131Srwatson
250155131Srwatson	/* Check if we want to select on rgid. */
251155131Srwatson	if (ISOPTSET(opttochk, OPT_r)) {
252155131Srwatson		if (user != p_ruid)
253155131Srwatson			return (0);
254155131Srwatson	}
255155131Srwatson	return (1);
256155131Srwatson}
257155131Srwatson
258155131Srwatson/*
259155131Srwatson * Check if the given subject id (pid) matches the selection criteria.
260155131Srwatson */
261155131Srwatsonstatic int
262155131Srwatsonselect_subid(int subid)
263155131Srwatson{
264155131Srwatson
265155131Srwatson	/* Check if we want to select on subject uid. */
266155131Srwatson	if (ISOPTSET(opttochk, OPT_j)) {
267155131Srwatson		if (subid != p_subid)
268155131Srwatson			return (0);
269155131Srwatson	}
270155131Srwatson	return (1);
271155131Srwatson}
272155131Srwatson
273155131Srwatson
274155131Srwatson/*
275155131Srwatson * Check if object's pid maches the given pid.
276155131Srwatson */
277155131Srwatsonstatic int
278155131Srwatsonselect_pidobj(uint32_t pid)
279155131Srwatson{
280155131Srwatson
281155131Srwatson	if (ISOPTSET(opttochk, OPT_op)) {
282185573Srwatson		if (pid != (uint32_t)strtol(p_pidobj, (char **)NULL, 10))
283155131Srwatson			return (0);
284155131Srwatson	}
285155131Srwatson	return (1);
286155131Srwatson}
287155131Srwatson
288155131Srwatson/*
289155131Srwatson * Check if the given ipc object with the given type matches the selection
290155131Srwatson * criteria.
291155131Srwatson */
292155131Srwatsonstatic int
293155131Srwatsonselect_ipcobj(u_char type, uint32_t id, uint32_t *optchkd)
294155131Srwatson{
295155131Srwatson
296155131Srwatson	if (type == AT_IPC_MSG) {
297155131Srwatson		SETOPT((*optchkd), OPT_om);
298155131Srwatson		if (ISOPTSET(opttochk, OPT_om)) {
299185573Srwatson			if (id != (uint32_t)strtol(p_msgqobj, (char **)NULL,
300185573Srwatson			    10))
301155131Srwatson				return (0);
302155131Srwatson		}
303155131Srwatson		return (1);
304155131Srwatson	} else if (type == AT_IPC_SEM) {
305155131Srwatson		SETOPT((*optchkd), OPT_ose);
306155131Srwatson		if (ISOPTSET(opttochk, OPT_ose)) {
307185573Srwatson			if (id != (uint32_t)strtol(p_semobj, (char **)NULL, 10))
308155131Srwatson				return (0);
309155131Srwatson		}
310155131Srwatson		return (1);
311155131Srwatson	} else if (type == AT_IPC_SHM) {
312155131Srwatson		SETOPT((*optchkd), OPT_osh);
313155131Srwatson		if (ISOPTSET(opttochk, OPT_osh)) {
314185573Srwatson			if (id != (uint32_t)strtol(p_shmobj, (char **)NULL, 10))
315155131Srwatson				return (0);
316155131Srwatson		}
317155131Srwatson		return (1);
318155131Srwatson	}
319155131Srwatson
320155131Srwatson	/* Unknown type -- filter if *any* ipc filtering is required. */
321155131Srwatson	if (ISOPTSET(opttochk, OPT_om) || ISOPTSET(opttochk, OPT_ose)
322155131Srwatson	    || ISOPTSET(opttochk, OPT_osh))
323155131Srwatson		return (0);
324155131Srwatson
325155131Srwatson	return (1);
326155131Srwatson}
327155131Srwatson
328155131Srwatson
329155131Srwatson/*
330155131Srwatson * Check if the file name matches selection criteria.
331155131Srwatson */
332155131Srwatsonstatic int
333155131Srwatsonselect_filepath(char *path, uint32_t *optchkd)
334155131Srwatson{
335162621Srwatson	struct re_entry *rep;
336162621Srwatson	int match;
337155131Srwatson
338155131Srwatson	SETOPT((*optchkd), OPT_of);
339162621Srwatson	match = 1;
340155131Srwatson	if (ISOPTSET(opttochk, OPT_of)) {
341162621Srwatson		match = 0;
342162621Srwatson		TAILQ_FOREACH(rep, &re_head, re_glue) {
343162621Srwatson			if (regexec(&rep->re_regexp, path, 0, NULL,
344162621Srwatson			    0) != REG_NOMATCH)
345162621Srwatson				return (!rep->re_negate);
346155131Srwatson		}
347155131Srwatson	}
348162621Srwatson	return (match);
349155131Srwatson}
350155131Srwatson
351155131Srwatson/*
352155131Srwatson * Returns 1 if the following pass the selection rules:
353155131Srwatson *
354155131Srwatson * before-time,
355155131Srwatson * after time,
356155131Srwatson * date,
357155131Srwatson * class,
358155131Srwatson * event
359155131Srwatson */
360155131Srwatsonstatic int
361155131Srwatsonselect_hdr32(tokenstr_t tok, uint32_t *optchkd)
362155131Srwatson{
363185573Srwatson	uint16_t *ev;
364185573Srwatson	int match;
365155131Srwatson
366185573Srwatson	SETOPT((*optchkd), (OPT_A | OPT_a | OPT_b | OPT_c | OPT_m | OPT_v));
367155131Srwatson
368155131Srwatson	/* The A option overrides a, b and d. */
369155131Srwatson	if (!ISOPTSET(opttochk, OPT_A)) {
370155131Srwatson		if (ISOPTSET(opttochk, OPT_a)) {
371155131Srwatson			if (difftime((time_t)tok.tt.hdr32.s, p_atime) < 0) {
372155131Srwatson				/* Record was created before p_atime. */
373155131Srwatson				return (0);
374155131Srwatson			}
375155131Srwatson		}
376155131Srwatson
377155131Srwatson		if (ISOPTSET(opttochk, OPT_b)) {
378155131Srwatson			if (difftime(p_btime, (time_t)tok.tt.hdr32.s) < 0) {
379155131Srwatson				/* Record was created after p_btime. */
380155131Srwatson				return (0);
381155131Srwatson			}
382155131Srwatson		}
383155131Srwatson	}
384155131Srwatson
385155131Srwatson	if (ISOPTSET(opttochk, OPT_c)) {
386155131Srwatson		/*
387155131Srwatson		 * Check if the classes represented by the event matches
388155131Srwatson		 * given class.
389155131Srwatson		 */
390155131Srwatson		if (au_preselect(tok.tt.hdr32.e_type, &maskp, AU_PRS_BOTH,
391155131Srwatson		    AU_PRS_USECACHE) != 1)
392155131Srwatson			return (0);
393155131Srwatson	}
394155131Srwatson
395155131Srwatson	/* Check if event matches. */
396155131Srwatson	if (ISOPTSET(opttochk, OPT_m)) {
397185573Srwatson		match = 0;
398185573Srwatson		for (ev = p_evec; ev < &p_evec[p_evec_used]; ev++)
399185573Srwatson			if (tok.tt.hdr32.e_type == *ev)
400185573Srwatson				match = 1;
401185573Srwatson		if (match == 0)
402155131Srwatson			return (0);
403155131Srwatson	}
404155131Srwatson
405155131Srwatson	return (1);
406155131Srwatson}
407155131Srwatson
408162621Srwatsonstatic int
409162621Srwatsonselect_return32(tokenstr_t tok_ret32, tokenstr_t tok_hdr32, uint32_t *optchkd)
410162621Srwatson{
411162621Srwatson	int sorf;
412162621Srwatson
413162621Srwatson	SETOPT((*optchkd), (OPT_c));
414162621Srwatson	if (tok_ret32.tt.ret32.status == 0)
415162621Srwatson		sorf = AU_PRS_SUCCESS;
416162621Srwatson	else
417162621Srwatson		sorf = AU_PRS_FAILURE;
418162621Srwatson	if (ISOPTSET(opttochk, OPT_c)) {
419162621Srwatson		if (au_preselect(tok_hdr32.tt.hdr32.e_type, &maskp, sorf,
420162621Srwatson		    AU_PRS_USECACHE) != 1)
421162621Srwatson			return (0);
422162621Srwatson	}
423162621Srwatson	return (1);
424162621Srwatson}
425162621Srwatson
426155131Srwatson/*
427155131Srwatson * Return 1 if checks for the the following succeed
428155131Srwatson * auid,
429155131Srwatson * euid,
430155131Srwatson * egid,
431155131Srwatson * rgid,
432155131Srwatson * ruid,
433155131Srwatson * process id
434155131Srwatson */
435155131Srwatsonstatic int
436155131Srwatsonselect_proc32(tokenstr_t tok, uint32_t *optchkd)
437155131Srwatson{
438155131Srwatson
439155131Srwatson	SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_op));
440155131Srwatson
441155131Srwatson	if (!select_auid(tok.tt.proc32.auid))
442155131Srwatson		return (0);
443155131Srwatson	if (!select_euid(tok.tt.proc32.euid))
444155131Srwatson		return (0);
445155131Srwatson	if (!select_egid(tok.tt.proc32.egid))
446155131Srwatson		return (0);
447155131Srwatson	if (!select_rgid(tok.tt.proc32.rgid))
448155131Srwatson		return (0);
449155131Srwatson	if (!select_ruid(tok.tt.proc32.ruid))
450155131Srwatson		return (0);
451155131Srwatson	if (!select_pidobj(tok.tt.proc32.pid))
452155131Srwatson		return (0);
453155131Srwatson	return (1);
454155131Srwatson}
455155131Srwatson
456155131Srwatson/*
457155131Srwatson * Return 1 if checks for the the following succeed
458155131Srwatson * auid,
459155131Srwatson * euid,
460155131Srwatson * egid,
461155131Srwatson * rgid,
462155131Srwatson * ruid,
463155131Srwatson * subject id
464155131Srwatson */
465155131Srwatsonstatic int
466155131Srwatsonselect_subj32(tokenstr_t tok, uint32_t *optchkd)
467155131Srwatson{
468155131Srwatson
469155131Srwatson	SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_j));
470155131Srwatson
471155131Srwatson	if (!select_auid(tok.tt.subj32.auid))
472155131Srwatson		return (0);
473155131Srwatson	if (!select_euid(tok.tt.subj32.euid))
474155131Srwatson		return (0);
475155131Srwatson	if (!select_egid(tok.tt.subj32.egid))
476155131Srwatson		return (0);
477155131Srwatson	if (!select_rgid(tok.tt.subj32.rgid))
478155131Srwatson		return (0);
479155131Srwatson	if (!select_ruid(tok.tt.subj32.ruid))
480155131Srwatson		return (0);
481155131Srwatson	if (!select_subid(tok.tt.subj32.pid))
482155131Srwatson		return (0);
483155131Srwatson	return (1);
484155131Srwatson}
485155131Srwatson
486155131Srwatson/*
487155131Srwatson * Read each record from the audit trail.  Check if it is selected after
488155131Srwatson * passing through each of the options
489155131Srwatson */
490155131Srwatsonstatic int
491155131Srwatsonselect_records(FILE *fp)
492155131Srwatson{
493162621Srwatson	tokenstr_t tok_hdr32_copy;
494155131Srwatson	u_char *buf;
495155131Srwatson	tokenstr_t tok;
496155131Srwatson	int reclen;
497155131Srwatson	int bytesread;
498155131Srwatson	int selected;
499155131Srwatson	uint32_t optchkd;
500185573Srwatson	int print;
501155131Srwatson
502155131Srwatson	int err = 0;
503155131Srwatson	while ((reclen = au_read_rec(fp, &buf)) != -1) {
504155131Srwatson		optchkd = 0;
505155131Srwatson		bytesread = 0;
506155131Srwatson		selected = 1;
507155131Srwatson		while ((selected == 1) && (bytesread < reclen)) {
508155131Srwatson			if (-1 == au_fetch_tok(&tok, buf + bytesread,
509155131Srwatson			    reclen - bytesread)) {
510155131Srwatson				/* Is this an incomplete record? */
511155131Srwatson				err = 1;
512155131Srwatson				break;
513155131Srwatson			}
514155131Srwatson
515155131Srwatson			/*
516155131Srwatson			 * For each token type we have have different
517155131Srwatson			 * selection criteria.
518155131Srwatson			 */
519155131Srwatson			switch(tok.id) {
520185573Srwatson			case AUT_HEADER32:
521155131Srwatson					selected = select_hdr32(tok,
522155131Srwatson					    &optchkd);
523162621Srwatson					bcopy(&tok, &tok_hdr32_copy,
524162621Srwatson					    sizeof(tok));
525155131Srwatson					break;
526155131Srwatson
527185573Srwatson			case AUT_PROCESS32:
528155131Srwatson					selected = select_proc32(tok,
529155131Srwatson					    &optchkd);
530155131Srwatson					break;
531155131Srwatson
532185573Srwatson			case AUT_SUBJECT32:
533155131Srwatson					selected = select_subj32(tok,
534155131Srwatson					    &optchkd);
535155131Srwatson					break;
536155131Srwatson
537185573Srwatson			case AUT_IPC:
538155131Srwatson					selected = select_ipcobj(
539155131Srwatson					    tok.tt.ipc.type, tok.tt.ipc.id,
540155131Srwatson					    &optchkd);
541155131Srwatson					break;
542155131Srwatson
543185573Srwatson			case AUT_PATH:
544155131Srwatson					selected = select_filepath(
545155131Srwatson					    tok.tt.path.path, &optchkd);
546155131Srwatson					break;
547155131Srwatson
548185573Srwatson			case AUT_RETURN32:
549162621Srwatson				selected = select_return32(tok,
550162621Srwatson				    tok_hdr32_copy, &optchkd);
551162621Srwatson				break;
552162621Srwatson
553155131Srwatson			default:
554155131Srwatson				break;
555155131Srwatson			}
556155131Srwatson			bytesread += tok.len;
557155131Srwatson		}
558185573Srwatson		/* Check if all the options were matched. */
559185573Srwatson		print = ((selected == 1) && (!err) && (!(opttochk & ~optchkd)));
560185573Srwatson		if (ISOPTSET(opttochk, OPT_v))
561185573Srwatson			print = !print;
562185573Srwatson		if (print)
563185573Srwatson			(void) fwrite(buf, 1, reclen, stdout);
564155131Srwatson		free(buf);
565155131Srwatson	}
566155131Srwatson	return (0);
567155131Srwatson}
568155131Srwatson
569155131Srwatson/*
570155131Srwatson * The -o option has the form object_type=object_value.  Identify the object
571155131Srwatson * components.
572155131Srwatson */
573186647Srwatsonstatic void
574155131Srwatsonparse_object_type(char *name, char *val)
575155131Srwatson{
576155131Srwatson	if (val == NULL)
577155131Srwatson		return;
578155131Srwatson
579155131Srwatson	if (!strcmp(name, FILEOBJ)) {
580155131Srwatson		p_fileobj = val;
581162621Srwatson		parse_regexp(val);
582155131Srwatson		SETOPT(opttochk, OPT_of);
583155131Srwatson	} else if (!strcmp(name, MSGQIDOBJ)) {
584155131Srwatson		p_msgqobj = val;
585155131Srwatson		SETOPT(opttochk, OPT_om);
586155131Srwatson	} else if (!strcmp(name, PIDOBJ)) {
587155131Srwatson		p_pidobj = val;
588155131Srwatson		SETOPT(opttochk, OPT_op);
589155131Srwatson	} else if (!strcmp(name, SEMIDOBJ)) {
590155131Srwatson		p_semobj = val;
591155131Srwatson		SETOPT(opttochk, OPT_ose);
592155131Srwatson	} else if (!strcmp(name, SHMIDOBJ)) {
593155131Srwatson		p_shmobj = val;
594155131Srwatson		SETOPT(opttochk, OPT_osh);
595155131Srwatson	} else if (!strcmp(name, SOCKOBJ)) {
596155131Srwatson		p_sockobj = val;
597155131Srwatson		SETOPT(opttochk, OPT_oso);
598155131Srwatson	} else
599155131Srwatson		usage("unknown value for -o");
600155131Srwatson}
601155131Srwatson
602155131Srwatsonint
603155131Srwatsonmain(int argc, char **argv)
604155131Srwatson{
605155131Srwatson	struct group *grp;
606155131Srwatson	struct passwd *pw;
607155131Srwatson	struct tm tm;
608155131Srwatson	au_event_t *n;
609155131Srwatson	FILE *fp;
610155131Srwatson	int i;
611155131Srwatson	char *objval, *converr;
612155364Srwatson	int ch;
613155131Srwatson	char timestr[128];
614155131Srwatson	char *fname;
615185573Srwatson	uint16_t *etp;
616155131Srwatson
617155131Srwatson	converr = NULL;
618155131Srwatson
619185573Srwatson	while ((ch = getopt(argc, argv, "Aa:b:c:d:e:f:g:j:m:o:r:u:v")) != -1) {
620155131Srwatson		switch(ch) {
621155131Srwatson		case 'A':
622155131Srwatson			SETOPT(opttochk, OPT_A);
623155131Srwatson			break;
624155131Srwatson
625155131Srwatson		case 'a':
626155131Srwatson			if (ISOPTSET(opttochk, OPT_a)) {
627155131Srwatson				usage("d is exclusive with a and b");
628155131Srwatson			}
629155131Srwatson			SETOPT(opttochk, OPT_a);
630171537Srwatson			bzero(&tm, sizeof(tm));
631155131Srwatson			strptime(optarg, "%Y%m%d%H%M%S", &tm);
632155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
633155131Srwatson			    &tm);
634155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
635155131Srwatson			p_atime = mktime(&tm);
636155131Srwatson			break;
637155131Srwatson
638155131Srwatson		case 'b':
639155131Srwatson			if (ISOPTSET(opttochk, OPT_b)) {
640155131Srwatson				usage("d is exclusive with a and b");
641155131Srwatson			}
642155131Srwatson			SETOPT(opttochk, OPT_b);
643171537Srwatson			bzero(&tm, sizeof(tm));
644155131Srwatson			strptime(optarg, "%Y%m%d%H%M%S", &tm);
645155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
646155131Srwatson			    &tm);
647155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
648155131Srwatson			p_btime = mktime(&tm);
649155131Srwatson			break;
650155131Srwatson
651155131Srwatson		case 'c':
652155131Srwatson			if (0 != getauditflagsbin(optarg, &maskp)) {
653155131Srwatson				/* Incorrect class */
654155131Srwatson				usage("Incorrect class");
655155131Srwatson			}
656155131Srwatson			SETOPT(opttochk, OPT_c);
657155131Srwatson			break;
658155131Srwatson
659155131Srwatson		case 'd':
660155131Srwatson			if (ISOPTSET(opttochk, OPT_b) || ISOPTSET(opttochk,
661155131Srwatson			    OPT_a))
662155131Srwatson				usage("'d' is exclusive with 'a' and 'b'");
663155131Srwatson			SETOPT(opttochk, OPT_d);
664171537Srwatson			bzero(&tm, sizeof(tm));
665155131Srwatson			strptime(optarg, "%Y%m%d", &tm);
666155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
667155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
668155131Srwatson			p_atime = mktime(&tm);
669155131Srwatson			tm.tm_hour = 23;
670155131Srwatson			tm.tm_min = 59;
671155131Srwatson			tm.tm_sec = 59;
672155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
673155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
674155131Srwatson			p_btime = mktime(&tm);
675155131Srwatson			break;
676155131Srwatson
677155131Srwatson		case 'e':
678155131Srwatson			p_euid = strtol(optarg, &converr, 10);
679155131Srwatson			if (*converr != '\0') {
680155131Srwatson				/* Try the actual name */
681155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
682155131Srwatson					break;
683155131Srwatson				p_euid = pw->pw_uid;
684155131Srwatson			}
685155131Srwatson			SETOPT(opttochk, OPT_e);
686155131Srwatson			break;
687155131Srwatson
688155131Srwatson		case 'f':
689155131Srwatson			p_egid = strtol(optarg, &converr, 10);
690155131Srwatson			if (*converr != '\0') {
691155131Srwatson				/* Try actual group name. */
692155131Srwatson				if ((grp = getgrnam(optarg)) == NULL)
693155131Srwatson					break;
694155131Srwatson				p_egid = grp->gr_gid;
695155131Srwatson			}
696155131Srwatson			SETOPT(opttochk, OPT_f);
697155131Srwatson			break;
698155131Srwatson
699155131Srwatson		case 'g':
700155131Srwatson			p_rgid = strtol(optarg, &converr, 10);
701155131Srwatson			if (*converr != '\0') {
702155131Srwatson				/* Try actual group name. */
703155131Srwatson				if ((grp = getgrnam(optarg)) == NULL)
704155131Srwatson					break;
705155131Srwatson				p_rgid = grp->gr_gid;
706155131Srwatson			}
707155131Srwatson			SETOPT(opttochk, OPT_g);
708155131Srwatson			break;
709155131Srwatson
710155131Srwatson		case 'j':
711155131Srwatson			p_subid = strtol(optarg, (char **)NULL, 10);
712155131Srwatson			SETOPT(opttochk, OPT_j);
713155131Srwatson			break;
714155131Srwatson
715155131Srwatson		case 'm':
716185573Srwatson			if (p_evec == NULL) {
717185573Srwatson				p_evec_alloc = 32;
718185573Srwatson				p_evec = malloc(sizeof(*etp) * p_evec_alloc);
719185573Srwatson				if (p_evec == NULL)
720185573Srwatson					err(1, "malloc");
721185573Srwatson			} else if (p_evec_alloc == p_evec_used) {
722185573Srwatson				p_evec_alloc <<= 1;
723185573Srwatson				p_evec = realloc(p_evec,
724185573Srwatson				    sizeof(*p_evec) * p_evec_alloc);
725185573Srwatson				if (p_evec == NULL)
726185573Srwatson					err(1, "realloc");
727185573Srwatson			}
728185573Srwatson			etp = &p_evec[p_evec_used++];
729185573Srwatson			*etp = strtol(optarg, (char **)NULL, 10);
730185573Srwatson			if (*etp == 0) {
731155131Srwatson				/* Could be the string representation. */
732155131Srwatson				n = getauevnonam(optarg);
733155131Srwatson				if (n == NULL)
734155131Srwatson					usage("Incorrect event name");
735185573Srwatson				*etp = *n;
736155131Srwatson			}
737155131Srwatson			SETOPT(opttochk, OPT_m);
738155131Srwatson			break;
739155131Srwatson
740155131Srwatson		case 'o':
741155131Srwatson			objval = strchr(optarg, '=');
742155131Srwatson			if (objval != NULL) {
743155131Srwatson				*objval = '\0';
744155131Srwatson				objval += 1;
745155131Srwatson				parse_object_type(optarg, objval);
746155131Srwatson			}
747155131Srwatson			break;
748155131Srwatson
749155131Srwatson		case 'r':
750155131Srwatson			p_ruid = strtol(optarg, &converr, 10);
751155131Srwatson			if (*converr != '\0') {
752155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
753155131Srwatson					break;
754155131Srwatson				p_ruid = pw->pw_uid;
755155131Srwatson			}
756155131Srwatson			SETOPT(opttochk, OPT_r);
757155131Srwatson			break;
758155131Srwatson
759155131Srwatson		case 'u':
760155131Srwatson			p_auid = strtol(optarg, &converr, 10);
761155131Srwatson			if (*converr != '\0') {
762155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
763155131Srwatson					break;
764155131Srwatson				p_auid = pw->pw_uid;
765155131Srwatson			}
766155131Srwatson			SETOPT(opttochk, OPT_u);
767155131Srwatson			break;
768155131Srwatson
769185573Srwatson		case 'v':
770185573Srwatson			SETOPT(opttochk, OPT_v);
771185573Srwatson			break;
772185573Srwatson
773155131Srwatson		case '?':
774155131Srwatson		default:
775155131Srwatson			usage("Unknown option");
776155131Srwatson		}
777155131Srwatson	}
778155131Srwatson	argv += optind;
779155131Srwatson	argc -= optind;
780155131Srwatson
781162621Srwatson	if (argc == 0) {
782162621Srwatson		if (select_records(stdin) == -1)
783162621Srwatson			errx(EXIT_FAILURE,
784162621Srwatson			    "Couldn't select records from stdin");
785162621Srwatson		exit(EXIT_SUCCESS);
786162621Srwatson	}
787155131Srwatson
788155131Srwatson	/*
789155131Srwatson	 * XXX: We should actually be merging records here.
790155131Srwatson	 */
791155131Srwatson	for (i = 0; i < argc; i++) {
792155131Srwatson		fname = argv[i];
793155131Srwatson		fp = fopen(fname, "r");
794155131Srwatson		if (fp == NULL)
795155131Srwatson			errx(EXIT_FAILURE, "Couldn't open %s", fname);
796155131Srwatson		if (select_records(fp) == -1) {
797155131Srwatson			errx(EXIT_FAILURE, "Couldn't select records %s",
798155131Srwatson			    fname);
799155131Srwatson		}
800155131Srwatson		fclose(fp);
801155131Srwatson	}
802155131Srwatson	exit(EXIT_SUCCESS);
803155131Srwatson}
804