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
usage(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
print_tokens(FILE * fp)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
main(int argc,char ** argv)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