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 */
29155131Srwatson
30155131Srwatson/*
31155131Srwatson * Tool used to merge and select audit records from audit trail files
32155131Srwatson */
33155131Srwatson
34155131Srwatson/*
35155131Srwatson * XXX Currently we do not support merging of records from multiple
36155131Srwatson * XXX audit trail files
37155131Srwatson * XXX We assume that records are sorted chronologically - both wrt to
38155131Srwatson * XXX the records present within the file and between the files themselves
39155131Srwatson */
40155131Srwatson
41162621Srwatson#include <config/config.h>
42187214Srwatson
43187214Srwatson#define	_GNU_SOURCE		/* Required for strptime() on glibc2. */
44187214Srwatson
45162621Srwatson#ifdef HAVE_FULL_QUEUE_H
46162621Srwatson#include <sys/queue.h>
47162621Srwatson#else
48162621Srwatson#include <compat/queue.h>
49162621Srwatson#endif
50162621Srwatson
51155131Srwatson#include <bsm/libbsm.h>
52155131Srwatson
53159248Srwatson#include <err.h>
54159248Srwatson#include <grp.h>
55159248Srwatson#include <pwd.h>
56155131Srwatson#include <stdio.h>
57155131Srwatson#include <stdlib.h>
58155131Srwatson#include <sysexits.h>
59155131Srwatson#include <string.h>
60155131Srwatson#include <time.h>
61155131Srwatson#include <unistd.h>
62162621Srwatson#include <regex.h>
63162621Srwatson#include <errno.h>
64155131Srwatson
65185573Srwatson#ifndef HAVE_STRLCPY
66185573Srwatson#include <compat/strlcpy.h>
67185573Srwatson#endif
68185573Srwatson
69155131Srwatson#include "auditreduce.h"
70155131Srwatson
71162621Srwatsonstatic TAILQ_HEAD(tailhead, re_entry) re_head =
72162621Srwatson    TAILQ_HEAD_INITIALIZER(re_head);
73162621Srwatson
74155131Srwatsonextern char		*optarg;
75155131Srwatsonextern int		 optind, optopt, opterr,optreset;
76155131Srwatson
77155131Srwatsonstatic au_mask_t	 maskp;		/* Class. */
78155131Srwatsonstatic time_t		 p_atime;	/* Created after this time. */
79155131Srwatsonstatic time_t		 p_btime;	/* Created before this time. */
80155131Srwatsonstatic int		 p_auid;	/* Audit id. */
81155131Srwatsonstatic int		 p_euid;	/* Effective user id. */
82155131Srwatsonstatic int		 p_egid;	/* Effective group id. */
83155131Srwatsonstatic int		 p_rgid;	/* Real group id. */
84155131Srwatsonstatic int		 p_ruid;	/* Real user id. */
85155131Srwatsonstatic int		 p_subid;	/* Subject id. */
86155131Srwatson
87155131Srwatson/*
88185573Srwatson * Maintain a dynamically sized array of events for -m
89185573Srwatson */
90185573Srwatsonstatic uint16_t		*p_evec;	/* Event type list */
91185573Srwatsonstatic int		 p_evec_used;	/* Number of events used */
92185573Srwatsonstatic int		 p_evec_alloc;	/* Number of events allocated */
93185573Srwatson
94185573Srwatson/*
95155131Srwatson * Following are the objects (-o option) that we can select upon.
96155131Srwatson */
97155131Srwatsonstatic char	*p_fileobj = NULL;
98155131Srwatsonstatic char	*p_msgqobj = NULL;
99155131Srwatsonstatic char	*p_pidobj = NULL;
100155131Srwatsonstatic char	*p_semobj = NULL;
101155131Srwatsonstatic char	*p_shmobj = NULL;
102155131Srwatsonstatic char	*p_sockobj = NULL;
103155131Srwatson
104155131Srwatsonstatic uint32_t opttochk = 0;
105155131Srwatson
106155131Srwatsonstatic void
107162621Srwatsonparse_regexp(char *re_string)
108162621Srwatson{
109162621Srwatson	char *orig, *copy, re_error[64];
110162621Srwatson	struct re_entry *rep;
111162621Srwatson	int error, nstrs, i, len;
112162621Srwatson
113162621Srwatson	copy = strdup(re_string);
114162621Srwatson	orig = copy;
115162621Srwatson	len = strlen(copy);
116162621Srwatson	for (nstrs = 0, i = 0; i < len; i++) {
117162621Srwatson		if (copy[i] == ',' && i > 0) {
118162621Srwatson			if (copy[i - 1] == '\\')
119185573Srwatson				strlcpy(&copy[i - 1], &copy[i], len);
120162621Srwatson			else {
121162621Srwatson				nstrs++;
122162621Srwatson				copy[i] = '\0';
123162621Srwatson			}
124162621Srwatson		}
125162621Srwatson	}
126162621Srwatson	TAILQ_INIT(&re_head);
127162621Srwatson	for (i = 0; i < nstrs + 1; i++) {
128162621Srwatson		rep = calloc(1, sizeof(*rep));
129162621Srwatson		if (rep == NULL) {
130162621Srwatson			(void) fprintf(stderr, "calloc: %s\n",
131162621Srwatson			    strerror(errno));
132162621Srwatson			exit(1);
133162621Srwatson		}
134162621Srwatson		if (*copy == '~') {
135162621Srwatson			copy++;
136162621Srwatson			rep->re_negate = 1;
137162621Srwatson		}
138162621Srwatson		rep->re_pattern = strdup(copy);
139162621Srwatson		error = regcomp(&rep->re_regexp, rep->re_pattern,
140162621Srwatson		    REG_EXTENDED | REG_NOSUB);
141162621Srwatson		if (error != 0) {
142162621Srwatson			regerror(error, &rep->re_regexp, re_error, 64);
143162621Srwatson			(void) fprintf(stderr, "regcomp: %s\n", re_error);
144162621Srwatson			exit(1);
145162621Srwatson		}
146162621Srwatson		TAILQ_INSERT_TAIL(&re_head, rep, re_glue);
147162621Srwatson		len = strlen(copy);
148162621Srwatson		copy += len + 1;
149162621Srwatson	}
150162621Srwatson	free(orig);
151162621Srwatson}
152162621Srwatson
153162621Srwatsonstatic void
154155131Srwatsonusage(const char *msg)
155155131Srwatson{
156155131Srwatson	fprintf(stderr, "%s\n", msg);
157162621Srwatson	fprintf(stderr, "Usage: auditreduce [options] [file ...]\n");
158155131Srwatson	fprintf(stderr, "\tOptions are : \n");
159155131Srwatson	fprintf(stderr, "\t-A : all records\n");
160155131Srwatson	fprintf(stderr, "\t-a YYYYMMDD[HH[[MM[SS]]] : after date\n");
161155131Srwatson	fprintf(stderr, "\t-b YYYYMMDD[HH[[MM[SS]]] : before date\n");
162155131Srwatson	fprintf(stderr, "\t-c <flags> : matching class\n");
163155131Srwatson	fprintf(stderr, "\t-d YYYYMMDD : on date\n");
164155131Srwatson	fprintf(stderr, "\t-e <uid|name>  : effective user\n");
165155131Srwatson	fprintf(stderr, "\t-f <gid|group> : effective group\n");
166155131Srwatson	fprintf(stderr, "\t-g <gid|group> : real group\n");
167155131Srwatson	fprintf(stderr, "\t-j <pid> : subject id \n");
168155131Srwatson	fprintf(stderr, "\t-m <evno|evname> : matching event\n");
169155131Srwatson	fprintf(stderr, "\t-o objecttype=objectvalue\n");
170155131Srwatson	fprintf(stderr, "\t\t file=<pathname>\n");
171155131Srwatson	fprintf(stderr, "\t\t msgqid=<ID>\n");
172155131Srwatson	fprintf(stderr, "\t\t pid=<ID>\n");
173155131Srwatson	fprintf(stderr, "\t\t semid=<ID>\n");
174155131Srwatson	fprintf(stderr, "\t\t shmid=<ID>\n");
175155131Srwatson	fprintf(stderr, "\t-r <uid|name> : real user\n");
176155131Srwatson	fprintf(stderr, "\t-u <uid|name> : audit user\n");
177185573Srwatson	fprintf(stderr, "\t-v : select non-matching records\n");
178155131Srwatson	exit(EX_USAGE);
179155131Srwatson}
180155131Srwatson
181155131Srwatson/*
182155131Srwatson * Check if the given auid matches the selection criteria.
183155131Srwatson */
184155131Srwatsonstatic int
185155131Srwatsonselect_auid(int au)
186155131Srwatson{
187155131Srwatson
188155131Srwatson	/* Check if we want to select on auid. */
189155131Srwatson	if (ISOPTSET(opttochk, OPT_u)) {
190155131Srwatson		if (au != p_auid)
191155131Srwatson			return (0);
192155131Srwatson	}
193155131Srwatson	return (1);
194155131Srwatson}
195155131Srwatson
196155131Srwatson/*
197155131Srwatson * Check if the given euid matches the selection criteria.
198155131Srwatson */
199155131Srwatsonstatic int
200155131Srwatsonselect_euid(int euser)
201155131Srwatson{
202155131Srwatson
203155131Srwatson	/* Check if we want to select on euid. */
204155131Srwatson	if (ISOPTSET(opttochk, OPT_e)) {
205155131Srwatson		if (euser != p_euid)
206155131Srwatson			return (0);
207155131Srwatson	}
208155131Srwatson	return (1);
209155131Srwatson}
210155131Srwatson
211155131Srwatson/*
212155131Srwatson * Check if the given egid matches the selection criteria.
213155131Srwatson */
214155131Srwatsonstatic int
215155131Srwatsonselect_egid(int egrp)
216155131Srwatson{
217155131Srwatson
218155131Srwatson	/* Check if we want to select on egid. */
219155131Srwatson	if (ISOPTSET(opttochk, OPT_f)) {
220155131Srwatson		if (egrp != p_egid)
221155131Srwatson			return (0);
222155131Srwatson	}
223155131Srwatson	return (1);
224155131Srwatson}
225155131Srwatson
226155131Srwatson/*
227155131Srwatson * Check if the given rgid matches the selection criteria.
228155131Srwatson */
229155131Srwatsonstatic int
230155131Srwatsonselect_rgid(int grp)
231155131Srwatson{
232155131Srwatson
233155131Srwatson	/* Check if we want to select on rgid. */
234155131Srwatson	if (ISOPTSET(opttochk, OPT_g)) {
235155131Srwatson		if (grp != p_rgid)
236155131Srwatson			return (0);
237155131Srwatson	}
238155131Srwatson	return (1);
239155131Srwatson}
240155131Srwatson
241155131Srwatson/*
242155131Srwatson * Check if the given ruid matches the selection criteria.
243155131Srwatson */
244155131Srwatsonstatic int
245155131Srwatsonselect_ruid(int user)
246155131Srwatson{
247155131Srwatson
248155131Srwatson	/* Check if we want to select on rgid. */
249155131Srwatson	if (ISOPTSET(opttochk, OPT_r)) {
250155131Srwatson		if (user != p_ruid)
251155131Srwatson			return (0);
252155131Srwatson	}
253155131Srwatson	return (1);
254155131Srwatson}
255155131Srwatson
256155131Srwatson/*
257155131Srwatson * Check if the given subject id (pid) matches the selection criteria.
258155131Srwatson */
259155131Srwatsonstatic int
260155131Srwatsonselect_subid(int subid)
261155131Srwatson{
262155131Srwatson
263155131Srwatson	/* Check if we want to select on subject uid. */
264155131Srwatson	if (ISOPTSET(opttochk, OPT_j)) {
265155131Srwatson		if (subid != p_subid)
266155131Srwatson			return (0);
267155131Srwatson	}
268155131Srwatson	return (1);
269155131Srwatson}
270155131Srwatson
271155131Srwatson
272155131Srwatson/*
273155131Srwatson * Check if object's pid maches the given pid.
274155131Srwatson */
275155131Srwatsonstatic int
276155131Srwatsonselect_pidobj(uint32_t pid)
277155131Srwatson{
278155131Srwatson
279155131Srwatson	if (ISOPTSET(opttochk, OPT_op)) {
280185573Srwatson		if (pid != (uint32_t)strtol(p_pidobj, (char **)NULL, 10))
281155131Srwatson			return (0);
282155131Srwatson	}
283155131Srwatson	return (1);
284155131Srwatson}
285155131Srwatson
286155131Srwatson/*
287155131Srwatson * Check if the given ipc object with the given type matches the selection
288155131Srwatson * criteria.
289155131Srwatson */
290155131Srwatsonstatic int
291155131Srwatsonselect_ipcobj(u_char type, uint32_t id, uint32_t *optchkd)
292155131Srwatson{
293155131Srwatson
294155131Srwatson	if (type == AT_IPC_MSG) {
295155131Srwatson		SETOPT((*optchkd), OPT_om);
296155131Srwatson		if (ISOPTSET(opttochk, OPT_om)) {
297185573Srwatson			if (id != (uint32_t)strtol(p_msgqobj, (char **)NULL,
298185573Srwatson			    10))
299155131Srwatson				return (0);
300155131Srwatson		}
301155131Srwatson		return (1);
302155131Srwatson	} else if (type == AT_IPC_SEM) {
303155131Srwatson		SETOPT((*optchkd), OPT_ose);
304155131Srwatson		if (ISOPTSET(opttochk, OPT_ose)) {
305185573Srwatson			if (id != (uint32_t)strtol(p_semobj, (char **)NULL, 10))
306155131Srwatson				return (0);
307155131Srwatson		}
308155131Srwatson		return (1);
309155131Srwatson	} else if (type == AT_IPC_SHM) {
310155131Srwatson		SETOPT((*optchkd), OPT_osh);
311155131Srwatson		if (ISOPTSET(opttochk, OPT_osh)) {
312185573Srwatson			if (id != (uint32_t)strtol(p_shmobj, (char **)NULL, 10))
313155131Srwatson				return (0);
314155131Srwatson		}
315155131Srwatson		return (1);
316155131Srwatson	}
317155131Srwatson
318155131Srwatson	/* Unknown type -- filter if *any* ipc filtering is required. */
319155131Srwatson	if (ISOPTSET(opttochk, OPT_om) || ISOPTSET(opttochk, OPT_ose)
320155131Srwatson	    || ISOPTSET(opttochk, OPT_osh))
321155131Srwatson		return (0);
322155131Srwatson
323155131Srwatson	return (1);
324155131Srwatson}
325155131Srwatson
326155131Srwatson
327155131Srwatson/*
328155131Srwatson * Check if the file name matches selection criteria.
329155131Srwatson */
330155131Srwatsonstatic int
331155131Srwatsonselect_filepath(char *path, uint32_t *optchkd)
332155131Srwatson{
333162621Srwatson	struct re_entry *rep;
334162621Srwatson	int match;
335155131Srwatson
336155131Srwatson	SETOPT((*optchkd), OPT_of);
337162621Srwatson	match = 1;
338155131Srwatson	if (ISOPTSET(opttochk, OPT_of)) {
339162621Srwatson		match = 0;
340162621Srwatson		TAILQ_FOREACH(rep, &re_head, re_glue) {
341162621Srwatson			if (regexec(&rep->re_regexp, path, 0, NULL,
342162621Srwatson			    0) != REG_NOMATCH)
343162621Srwatson				return (!rep->re_negate);
344155131Srwatson		}
345155131Srwatson	}
346162621Srwatson	return (match);
347155131Srwatson}
348155131Srwatson
349155131Srwatson/*
350155131Srwatson * Returns 1 if the following pass the selection rules:
351155131Srwatson *
352155131Srwatson * before-time,
353155131Srwatson * after time,
354155131Srwatson * date,
355155131Srwatson * class,
356155131Srwatson * event
357155131Srwatson */
358155131Srwatsonstatic int
359155131Srwatsonselect_hdr32(tokenstr_t tok, uint32_t *optchkd)
360155131Srwatson{
361185573Srwatson	uint16_t *ev;
362185573Srwatson	int match;
363155131Srwatson
364185573Srwatson	SETOPT((*optchkd), (OPT_A | OPT_a | OPT_b | OPT_c | OPT_m | OPT_v));
365155131Srwatson
366155131Srwatson	/* The A option overrides a, b and d. */
367155131Srwatson	if (!ISOPTSET(opttochk, OPT_A)) {
368155131Srwatson		if (ISOPTSET(opttochk, OPT_a)) {
369155131Srwatson			if (difftime((time_t)tok.tt.hdr32.s, p_atime) < 0) {
370155131Srwatson				/* Record was created before p_atime. */
371155131Srwatson				return (0);
372155131Srwatson			}
373155131Srwatson		}
374155131Srwatson
375155131Srwatson		if (ISOPTSET(opttochk, OPT_b)) {
376155131Srwatson			if (difftime(p_btime, (time_t)tok.tt.hdr32.s) < 0) {
377155131Srwatson				/* Record was created after p_btime. */
378155131Srwatson				return (0);
379155131Srwatson			}
380155131Srwatson		}
381155131Srwatson	}
382155131Srwatson
383155131Srwatson	if (ISOPTSET(opttochk, OPT_c)) {
384155131Srwatson		/*
385155131Srwatson		 * Check if the classes represented by the event matches
386155131Srwatson		 * given class.
387155131Srwatson		 */
388155131Srwatson		if (au_preselect(tok.tt.hdr32.e_type, &maskp, AU_PRS_BOTH,
389155131Srwatson		    AU_PRS_USECACHE) != 1)
390155131Srwatson			return (0);
391155131Srwatson	}
392155131Srwatson
393155131Srwatson	/* Check if event matches. */
394155131Srwatson	if (ISOPTSET(opttochk, OPT_m)) {
395185573Srwatson		match = 0;
396185573Srwatson		for (ev = p_evec; ev < &p_evec[p_evec_used]; ev++)
397185573Srwatson			if (tok.tt.hdr32.e_type == *ev)
398185573Srwatson				match = 1;
399185573Srwatson		if (match == 0)
400155131Srwatson			return (0);
401155131Srwatson	}
402155131Srwatson
403155131Srwatson	return (1);
404155131Srwatson}
405155131Srwatson
406162621Srwatsonstatic int
407162621Srwatsonselect_return32(tokenstr_t tok_ret32, tokenstr_t tok_hdr32, uint32_t *optchkd)
408162621Srwatson{
409162621Srwatson	int sorf;
410162621Srwatson
411162621Srwatson	SETOPT((*optchkd), (OPT_c));
412162621Srwatson	if (tok_ret32.tt.ret32.status == 0)
413162621Srwatson		sorf = AU_PRS_SUCCESS;
414162621Srwatson	else
415162621Srwatson		sorf = AU_PRS_FAILURE;
416162621Srwatson	if (ISOPTSET(opttochk, OPT_c)) {
417162621Srwatson		if (au_preselect(tok_hdr32.tt.hdr32.e_type, &maskp, sorf,
418162621Srwatson		    AU_PRS_USECACHE) != 1)
419162621Srwatson			return (0);
420162621Srwatson	}
421162621Srwatson	return (1);
422162621Srwatson}
423162621Srwatson
424155131Srwatson/*
425155131Srwatson * Return 1 if checks for the the following succeed
426155131Srwatson * auid,
427155131Srwatson * euid,
428155131Srwatson * egid,
429155131Srwatson * rgid,
430155131Srwatson * ruid,
431155131Srwatson * process id
432155131Srwatson */
433155131Srwatsonstatic int
434155131Srwatsonselect_proc32(tokenstr_t tok, uint32_t *optchkd)
435155131Srwatson{
436155131Srwatson
437155131Srwatson	SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_op));
438155131Srwatson
439155131Srwatson	if (!select_auid(tok.tt.proc32.auid))
440155131Srwatson		return (0);
441155131Srwatson	if (!select_euid(tok.tt.proc32.euid))
442155131Srwatson		return (0);
443155131Srwatson	if (!select_egid(tok.tt.proc32.egid))
444155131Srwatson		return (0);
445155131Srwatson	if (!select_rgid(tok.tt.proc32.rgid))
446155131Srwatson		return (0);
447155131Srwatson	if (!select_ruid(tok.tt.proc32.ruid))
448155131Srwatson		return (0);
449155131Srwatson	if (!select_pidobj(tok.tt.proc32.pid))
450155131Srwatson		return (0);
451155131Srwatson	return (1);
452155131Srwatson}
453155131Srwatson
454155131Srwatson/*
455155131Srwatson * Return 1 if checks for the the following succeed
456155131Srwatson * auid,
457155131Srwatson * euid,
458155131Srwatson * egid,
459155131Srwatson * rgid,
460155131Srwatson * ruid,
461155131Srwatson * subject id
462155131Srwatson */
463155131Srwatsonstatic int
464155131Srwatsonselect_subj32(tokenstr_t tok, uint32_t *optchkd)
465155131Srwatson{
466155131Srwatson
467155131Srwatson	SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_j));
468155131Srwatson
469155131Srwatson	if (!select_auid(tok.tt.subj32.auid))
470155131Srwatson		return (0);
471155131Srwatson	if (!select_euid(tok.tt.subj32.euid))
472155131Srwatson		return (0);
473155131Srwatson	if (!select_egid(tok.tt.subj32.egid))
474155131Srwatson		return (0);
475155131Srwatson	if (!select_rgid(tok.tt.subj32.rgid))
476155131Srwatson		return (0);
477155131Srwatson	if (!select_ruid(tok.tt.subj32.ruid))
478155131Srwatson		return (0);
479155131Srwatson	if (!select_subid(tok.tt.subj32.pid))
480155131Srwatson		return (0);
481155131Srwatson	return (1);
482155131Srwatson}
483155131Srwatson
484155131Srwatson/*
485155131Srwatson * Read each record from the audit trail.  Check if it is selected after
486155131Srwatson * passing through each of the options
487155131Srwatson */
488155131Srwatsonstatic int
489155131Srwatsonselect_records(FILE *fp)
490155131Srwatson{
491162621Srwatson	tokenstr_t tok_hdr32_copy;
492155131Srwatson	u_char *buf;
493155131Srwatson	tokenstr_t tok;
494155131Srwatson	int reclen;
495155131Srwatson	int bytesread;
496155131Srwatson	int selected;
497155131Srwatson	uint32_t optchkd;
498185573Srwatson	int print;
499155131Srwatson
500155131Srwatson	int err = 0;
501155131Srwatson	while ((reclen = au_read_rec(fp, &buf)) != -1) {
502155131Srwatson		optchkd = 0;
503155131Srwatson		bytesread = 0;
504155131Srwatson		selected = 1;
505155131Srwatson		while ((selected == 1) && (bytesread < reclen)) {
506155131Srwatson			if (-1 == au_fetch_tok(&tok, buf + bytesread,
507155131Srwatson			    reclen - bytesread)) {
508155131Srwatson				/* Is this an incomplete record? */
509155131Srwatson				err = 1;
510155131Srwatson				break;
511155131Srwatson			}
512155131Srwatson
513155131Srwatson			/*
514155131Srwatson			 * For each token type we have have different
515155131Srwatson			 * selection criteria.
516155131Srwatson			 */
517155131Srwatson			switch(tok.id) {
518185573Srwatson			case AUT_HEADER32:
519155131Srwatson					selected = select_hdr32(tok,
520155131Srwatson					    &optchkd);
521162621Srwatson					bcopy(&tok, &tok_hdr32_copy,
522162621Srwatson					    sizeof(tok));
523155131Srwatson					break;
524155131Srwatson
525185573Srwatson			case AUT_PROCESS32:
526155131Srwatson					selected = select_proc32(tok,
527155131Srwatson					    &optchkd);
528155131Srwatson					break;
529155131Srwatson
530185573Srwatson			case AUT_SUBJECT32:
531155131Srwatson					selected = select_subj32(tok,
532155131Srwatson					    &optchkd);
533155131Srwatson					break;
534155131Srwatson
535185573Srwatson			case AUT_IPC:
536155131Srwatson					selected = select_ipcobj(
537155131Srwatson					    tok.tt.ipc.type, tok.tt.ipc.id,
538155131Srwatson					    &optchkd);
539155131Srwatson					break;
540155131Srwatson
541185573Srwatson			case AUT_PATH:
542155131Srwatson					selected = select_filepath(
543155131Srwatson					    tok.tt.path.path, &optchkd);
544155131Srwatson					break;
545155131Srwatson
546185573Srwatson			case AUT_RETURN32:
547162621Srwatson				selected = select_return32(tok,
548162621Srwatson				    tok_hdr32_copy, &optchkd);
549162621Srwatson				break;
550162621Srwatson
551155131Srwatson			default:
552155131Srwatson				break;
553155131Srwatson			}
554155131Srwatson			bytesread += tok.len;
555155131Srwatson		}
556185573Srwatson		/* Check if all the options were matched. */
557185573Srwatson		print = ((selected == 1) && (!err) && (!(opttochk & ~optchkd)));
558185573Srwatson		if (ISOPTSET(opttochk, OPT_v))
559185573Srwatson			print = !print;
560185573Srwatson		if (print)
561185573Srwatson			(void) fwrite(buf, 1, reclen, stdout);
562155131Srwatson		free(buf);
563155131Srwatson	}
564155131Srwatson	return (0);
565155131Srwatson}
566155131Srwatson
567155131Srwatson/*
568155131Srwatson * The -o option has the form object_type=object_value.  Identify the object
569155131Srwatson * components.
570155131Srwatson */
571186647Srwatsonstatic void
572155131Srwatsonparse_object_type(char *name, char *val)
573155131Srwatson{
574155131Srwatson	if (val == NULL)
575155131Srwatson		return;
576155131Srwatson
577155131Srwatson	if (!strcmp(name, FILEOBJ)) {
578155131Srwatson		p_fileobj = val;
579162621Srwatson		parse_regexp(val);
580155131Srwatson		SETOPT(opttochk, OPT_of);
581155131Srwatson	} else if (!strcmp(name, MSGQIDOBJ)) {
582155131Srwatson		p_msgqobj = val;
583155131Srwatson		SETOPT(opttochk, OPT_om);
584155131Srwatson	} else if (!strcmp(name, PIDOBJ)) {
585155131Srwatson		p_pidobj = val;
586155131Srwatson		SETOPT(opttochk, OPT_op);
587155131Srwatson	} else if (!strcmp(name, SEMIDOBJ)) {
588155131Srwatson		p_semobj = val;
589155131Srwatson		SETOPT(opttochk, OPT_ose);
590155131Srwatson	} else if (!strcmp(name, SHMIDOBJ)) {
591155131Srwatson		p_shmobj = val;
592155131Srwatson		SETOPT(opttochk, OPT_osh);
593155131Srwatson	} else if (!strcmp(name, SOCKOBJ)) {
594155131Srwatson		p_sockobj = val;
595155131Srwatson		SETOPT(opttochk, OPT_oso);
596155131Srwatson	} else
597155131Srwatson		usage("unknown value for -o");
598155131Srwatson}
599155131Srwatson
600155131Srwatsonint
601155131Srwatsonmain(int argc, char **argv)
602155131Srwatson{
603155131Srwatson	struct group *grp;
604155131Srwatson	struct passwd *pw;
605155131Srwatson	struct tm tm;
606155131Srwatson	au_event_t *n;
607155131Srwatson	FILE *fp;
608155131Srwatson	int i;
609155131Srwatson	char *objval, *converr;
610155364Srwatson	int ch;
611155131Srwatson	char timestr[128];
612155131Srwatson	char *fname;
613185573Srwatson	uint16_t *etp;
614155131Srwatson
615155131Srwatson	converr = NULL;
616155131Srwatson
617185573Srwatson	while ((ch = getopt(argc, argv, "Aa:b:c:d:e:f:g:j:m:o:r:u:v")) != -1) {
618155131Srwatson		switch(ch) {
619155131Srwatson		case 'A':
620155131Srwatson			SETOPT(opttochk, OPT_A);
621155131Srwatson			break;
622155131Srwatson
623155131Srwatson		case 'a':
624155131Srwatson			if (ISOPTSET(opttochk, OPT_a)) {
625155131Srwatson				usage("d is exclusive with a and b");
626155131Srwatson			}
627155131Srwatson			SETOPT(opttochk, OPT_a);
628171537Srwatson			bzero(&tm, sizeof(tm));
629155131Srwatson			strptime(optarg, "%Y%m%d%H%M%S", &tm);
630155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
631155131Srwatson			    &tm);
632155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
633155131Srwatson			p_atime = mktime(&tm);
634155131Srwatson			break;
635155131Srwatson
636155131Srwatson		case 'b':
637155131Srwatson			if (ISOPTSET(opttochk, OPT_b)) {
638155131Srwatson				usage("d is exclusive with a and b");
639155131Srwatson			}
640155131Srwatson			SETOPT(opttochk, OPT_b);
641171537Srwatson			bzero(&tm, sizeof(tm));
642155131Srwatson			strptime(optarg, "%Y%m%d%H%M%S", &tm);
643155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S",
644155131Srwatson			    &tm);
645155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
646155131Srwatson			p_btime = mktime(&tm);
647155131Srwatson			break;
648155131Srwatson
649155131Srwatson		case 'c':
650155131Srwatson			if (0 != getauditflagsbin(optarg, &maskp)) {
651155131Srwatson				/* Incorrect class */
652155131Srwatson				usage("Incorrect class");
653155131Srwatson			}
654155131Srwatson			SETOPT(opttochk, OPT_c);
655155131Srwatson			break;
656155131Srwatson
657155131Srwatson		case 'd':
658155131Srwatson			if (ISOPTSET(opttochk, OPT_b) || ISOPTSET(opttochk,
659155131Srwatson			    OPT_a))
660155131Srwatson				usage("'d' is exclusive with 'a' and 'b'");
661155131Srwatson			SETOPT(opttochk, OPT_d);
662171537Srwatson			bzero(&tm, sizeof(tm));
663155131Srwatson			strptime(optarg, "%Y%m%d", &tm);
664155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
665155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
666155131Srwatson			p_atime = mktime(&tm);
667155131Srwatson			tm.tm_hour = 23;
668155131Srwatson			tm.tm_min = 59;
669155131Srwatson			tm.tm_sec = 59;
670155131Srwatson			strftime(timestr, sizeof(timestr), "%Y%m%d", &tm);
671155131Srwatson			/* fprintf(stderr, "Time converted = %s\n", timestr); */
672155131Srwatson			p_btime = mktime(&tm);
673155131Srwatson			break;
674155131Srwatson
675155131Srwatson		case 'e':
676155131Srwatson			p_euid = strtol(optarg, &converr, 10);
677155131Srwatson			if (*converr != '\0') {
678155131Srwatson				/* Try the actual name */
679155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
680155131Srwatson					break;
681155131Srwatson				p_euid = pw->pw_uid;
682155131Srwatson			}
683155131Srwatson			SETOPT(opttochk, OPT_e);
684155131Srwatson			break;
685155131Srwatson
686155131Srwatson		case 'f':
687155131Srwatson			p_egid = strtol(optarg, &converr, 10);
688155131Srwatson			if (*converr != '\0') {
689155131Srwatson				/* Try actual group name. */
690155131Srwatson				if ((grp = getgrnam(optarg)) == NULL)
691155131Srwatson					break;
692155131Srwatson				p_egid = grp->gr_gid;
693155131Srwatson			}
694155131Srwatson			SETOPT(opttochk, OPT_f);
695155131Srwatson			break;
696155131Srwatson
697155131Srwatson		case 'g':
698155131Srwatson			p_rgid = strtol(optarg, &converr, 10);
699155131Srwatson			if (*converr != '\0') {
700155131Srwatson				/* Try actual group name. */
701155131Srwatson				if ((grp = getgrnam(optarg)) == NULL)
702155131Srwatson					break;
703155131Srwatson				p_rgid = grp->gr_gid;
704155131Srwatson			}
705155131Srwatson			SETOPT(opttochk, OPT_g);
706155131Srwatson			break;
707155131Srwatson
708155131Srwatson		case 'j':
709155131Srwatson			p_subid = strtol(optarg, (char **)NULL, 10);
710155131Srwatson			SETOPT(opttochk, OPT_j);
711155131Srwatson			break;
712155131Srwatson
713155131Srwatson		case 'm':
714185573Srwatson			if (p_evec == NULL) {
715185573Srwatson				p_evec_alloc = 32;
716185573Srwatson				p_evec = malloc(sizeof(*etp) * p_evec_alloc);
717185573Srwatson				if (p_evec == NULL)
718185573Srwatson					err(1, "malloc");
719185573Srwatson			} else if (p_evec_alloc == p_evec_used) {
720185573Srwatson				p_evec_alloc <<= 1;
721185573Srwatson				p_evec = realloc(p_evec,
722185573Srwatson				    sizeof(*p_evec) * p_evec_alloc);
723185573Srwatson				if (p_evec == NULL)
724185573Srwatson					err(1, "realloc");
725185573Srwatson			}
726185573Srwatson			etp = &p_evec[p_evec_used++];
727185573Srwatson			*etp = strtol(optarg, (char **)NULL, 10);
728185573Srwatson			if (*etp == 0) {
729155131Srwatson				/* Could be the string representation. */
730155131Srwatson				n = getauevnonam(optarg);
731155131Srwatson				if (n == NULL)
732155131Srwatson					usage("Incorrect event name");
733185573Srwatson				*etp = *n;
734155131Srwatson			}
735155131Srwatson			SETOPT(opttochk, OPT_m);
736155131Srwatson			break;
737155131Srwatson
738155131Srwatson		case 'o':
739155131Srwatson			objval = strchr(optarg, '=');
740155131Srwatson			if (objval != NULL) {
741155131Srwatson				*objval = '\0';
742155131Srwatson				objval += 1;
743155131Srwatson				parse_object_type(optarg, objval);
744155131Srwatson			}
745155131Srwatson			break;
746155131Srwatson
747155131Srwatson		case 'r':
748155131Srwatson			p_ruid = strtol(optarg, &converr, 10);
749155131Srwatson			if (*converr != '\0') {
750155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
751155131Srwatson					break;
752155131Srwatson				p_ruid = pw->pw_uid;
753155131Srwatson			}
754155131Srwatson			SETOPT(opttochk, OPT_r);
755155131Srwatson			break;
756155131Srwatson
757155131Srwatson		case 'u':
758155131Srwatson			p_auid = strtol(optarg, &converr, 10);
759155131Srwatson			if (*converr != '\0') {
760155131Srwatson				if ((pw = getpwnam(optarg)) == NULL)
761155131Srwatson					break;
762155131Srwatson				p_auid = pw->pw_uid;
763155131Srwatson			}
764155131Srwatson			SETOPT(opttochk, OPT_u);
765155131Srwatson			break;
766155131Srwatson
767185573Srwatson		case 'v':
768185573Srwatson			SETOPT(opttochk, OPT_v);
769185573Srwatson			break;
770185573Srwatson
771155131Srwatson		case '?':
772155131Srwatson		default:
773155131Srwatson			usage("Unknown option");
774155131Srwatson		}
775155131Srwatson	}
776155131Srwatson	argv += optind;
777155131Srwatson	argc -= optind;
778155131Srwatson
779162621Srwatson	if (argc == 0) {
780162621Srwatson		if (select_records(stdin) == -1)
781162621Srwatson			errx(EXIT_FAILURE,
782162621Srwatson			    "Couldn't select records from stdin");
783162621Srwatson		exit(EXIT_SUCCESS);
784162621Srwatson	}
785155131Srwatson
786155131Srwatson	/*
787155131Srwatson	 * XXX: We should actually be merging records here.
788155131Srwatson	 */
789155131Srwatson	for (i = 0; i < argc; i++) {
790155131Srwatson		fname = argv[i];
791155131Srwatson		fp = fopen(fname, "r");
792155131Srwatson		if (fp == NULL)
793155131Srwatson			errx(EXIT_FAILURE, "Couldn't open %s", fname);
794155131Srwatson		if (select_records(fp) == -1) {
795155131Srwatson			errx(EXIT_FAILURE, "Couldn't select records %s",
796155131Srwatson			    fname);
797155131Srwatson		}
798155131Srwatson		fclose(fp);
799155131Srwatson	}
800155131Srwatson	exit(EXIT_SUCCESS);
801155131Srwatson}
802