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 (1); 237 } 238