xref: /freebsd/contrib/openbsm/bin/praudit/praudit.c (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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 
62 extern char	*optarg;
63 extern int	 optind, optopt, opterr,optreset;
64 
65 static char	*del = ",";	/* Default delimiter. */
66 static int	 oneline = 0;
67 static int	 partial = 0;
68 static int	 oflags = AU_OFLAG_NONE;
69 
70 static void
71 usage(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  */
82 static int
83 print_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 
123 int
124 main(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