1/*-
2 * Copyright (c) 2004-2009 Apple Inc.
3 * Copyright (c) 2006 Martin Voros
4 * Copyright (c) 2016 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * Portions of this software were developed by BAE Systems, the University of
8 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
9 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
10 * Computing (TC) research program.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1.  Redistributions of source code must retain the above copyright
16 *     notice, this list of conditions and the following disclaimer.
17 * 2.  Redistributions in binary form must reproduce the above copyright
18 *     notice, this list of conditions and the following disclaimer in the
19 *     documentation and/or other materials provided with the distribution.
20 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
21 *     its contributors may be used to endorse or promote products derived
22 *     from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37/*
38 * Tool used to parse audit records conforming to the BSM structure.
39 */
40
41/*
42 * praudit [-lnpx] [-r | -s] [-d del] [file ...]
43 */
44
45#include <config/config.h>
46
47#include <bsm/libbsm.h>
48
49#ifdef HAVE_CAP_ENTER
50#include <sys/capsicum.h>
51#include <sys/wait.h>
52#include <err.h>
53#include <errno.h>
54#endif
55
56#include <grp.h>
57#include <pwd.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <unistd.h>
61
62extern char	*optarg;
63extern int	 optind, optopt, opterr,optreset;
64
65static char	*del = ",";	/* Default delimiter. */
66static int	 oneline = 0;
67static int	 partial = 0;
68static int	 oflags = AU_OFLAG_NONE;
69
70static void
71usage(void)
72{
73
74	fprintf(stderr, "usage: praudit [-lnpx] [-r | -s] [-d del] "
75	    "[file ...]\n");
76	exit(1);
77}
78
79/*
80 * Token printing for each token type .
81 */
82static int
83print_tokens(FILE *fp)
84{
85	u_char *buf;
86	tokenstr_t tok;
87	int reclen;
88	int bytesread;
89
90	/* Allow tail -f | praudit to work. */
91	if (partial) {
92		u_char type = 0;
93		/* Record must begin with a header token. */
94		do {
95			type = fgetc(fp);
96		} while(type != AUT_HEADER32);
97		ungetc(type, fp);
98	}
99
100	while ((reclen = au_read_rec(fp, &buf)) != -1) {
101		bytesread = 0;
102		while (bytesread < reclen) {
103			/* Is this an incomplete record? */
104			if (-1 == au_fetch_tok(&tok, buf + bytesread,
105			    reclen - bytesread))
106				break;
107			au_print_flags_tok(stdout, &tok, del, oflags);
108			bytesread += tok.len;
109			if (oneline) {
110				if (!(oflags & AU_OFLAG_XML))
111					printf("%s", del);
112			} else
113				printf("\n");
114		}
115		free(buf);
116		if (oneline)
117			printf("\n");
118		fflush(stdout);
119	}
120	return (0);
121}
122
123int
124main(int argc, char **argv)
125{
126	int ch;
127	int i;
128#ifdef HAVE_CAP_ENTER
129	int retval;
130	pid_t childpid, pid;
131#endif
132	FILE *fp;
133
134	while ((ch = getopt(argc, argv, "d:lnprsx")) != -1) {
135		switch(ch) {
136		case 'd':
137			del = optarg;
138			break;
139
140		case 'l':
141			oneline = 1;
142			break;
143
144		case 'n':
145			oflags |= AU_OFLAG_NORESOLVE;
146			break;
147
148		case 'p':
149			partial = 1;
150			break;
151
152		case 'r':
153			if (oflags & AU_OFLAG_SHORT)
154				usage();	/* Exclusive from shortfrm. */
155			oflags |= AU_OFLAG_RAW;
156			break;
157
158		case 's':
159			if (oflags & AU_OFLAG_RAW)
160				usage();	/* Exclusive from raw. */
161			oflags |= AU_OFLAG_SHORT;
162			break;
163
164		case 'x':
165			oflags |= AU_OFLAG_XML;
166			break;
167
168		case '?':
169		default:
170			usage();
171		}
172	}
173
174#ifdef HAVE_CAP_ENTER
175	/*
176	 * Prime group, password, and audit-event files to be opened before we
177	 * enter capability mode.
178	 */
179	(void)getgrgid(0);
180	(void)setgroupent(1);
181	(void)getpwuid(0);
182	(void)setpassent(1);
183	(void)getauevent();
184#endif
185
186	if (oflags & AU_OFLAG_XML)
187		au_print_xml_header(stdout);
188
189	/* For each of the files passed as arguments dump the contents. */
190	if (optind == argc) {
191#ifdef HAVE_CAP_ENTER
192		retval = cap_enter();
193		if (retval != 0 && errno != ENOSYS)
194			err(EXIT_FAILURE, "cap_enter");
195#endif
196		print_tokens(stdin);
197		return (1);
198	}
199	for (i = optind; i < argc; i++) {
200		fp = fopen(argv[i], "r");
201		if (fp == NULL) {
202			perror(argv[i]);
203			continue;
204		}
205
206		/*
207		 * If operating with sandboxing, create a sandbox process for
208		 * each trail file we operate on.  This avoids the need to do
209		 * fancy things with file descriptors, etc, when iterating on
210		 * a list of arguments.
211		 */
212#ifdef HAVE_CAP_ENTER
213		childpid = fork();
214		if (childpid == 0) {
215			/* Child. */
216			retval = cap_enter();
217			if (retval != 0 && errno != ENOSYS)
218				err(EXIT_FAILURE, "cap_enter");
219			if (print_tokens(fp) == -1)
220				perror(argv[i]);
221			exit(0);
222		}
223
224		/* Parent.  Await child termination. */
225		while ((pid = waitpid(childpid, NULL, 0)) != childpid);
226#else
227		if (print_tokens(fp) == -1)
228			perror(argv[i]);
229#endif
230		fclose(fp);
231	}
232
233	if (oflags & AU_OFLAG_XML)
234		au_print_xml_footer(stdout);
235
236	return (0);
237}
238