praudit(1): return 0 on success
[freebsd.git] / contrib / openbsm / bin / praudit / praudit.c
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 }