1 /*- 2 * Copyright (c) 2004-2008 Apple Inc. 3 * Copyright (c) 2016 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Portions of this software were developed by BAE Systems, the University of 7 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 8 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 9 * Computing (TC) research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 20 * its contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* 37 * Tool used to merge and select audit records from audit trail files 38 */ 39 40 /* 41 * XXX Currently we do not support merging of records from multiple 42 * XXX audit trail files 43 * XXX We assume that records are sorted chronologically - both wrt to 44 * XXX the records present within the file and between the files themselves 45 */ 46 47 #include <config/config.h> 48 49 #define _GNU_SOURCE /* Required for strptime() on glibc2. */ 50 51 #ifdef HAVE_FULL_QUEUE_H 52 #include <sys/queue.h> 53 #else 54 #include <compat/queue.h> 55 #endif 56 57 #ifdef HAVE_CAP_ENTER 58 #include <sys/capsicum.h> 59 #include <sys/wait.h> 60 #endif 61 62 #include <bsm/libbsm.h> 63 64 #include <err.h> 65 #include <fnmatch.h> 66 #include <grp.h> 67 #include <pwd.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <sysexits.h> 71 #include <string.h> 72 #include <time.h> 73 #include <unistd.h> 74 #include <regex.h> 75 #include <errno.h> 76 77 #ifndef HAVE_STRLCPY 78 #include <compat/strlcpy.h> 79 #endif 80 81 #include "auditreduce.h" 82 83 static TAILQ_HEAD(tailhead, re_entry) re_head = 84 TAILQ_HEAD_INITIALIZER(re_head); 85 86 extern char *optarg; 87 extern int optind, optopt, opterr,optreset; 88 89 static au_mask_t maskp; /* Class. */ 90 static time_t p_atime; /* Created after this time. */ 91 static time_t p_btime; /* Created before this time. */ 92 static int p_auid; /* Audit id. */ 93 static int p_euid; /* Effective user id. */ 94 static int p_egid; /* Effective group id. */ 95 static int p_rgid; /* Real group id. */ 96 static int p_ruid; /* Real user id. */ 97 static int p_subid; /* Subject id. */ 98 static const char *p_zone; /* Zone. */ 99 100 /* 101 * Maintain a dynamically sized array of events for -m 102 */ 103 static uint16_t *p_evec; /* Event type list */ 104 static int p_evec_used; /* Number of events used */ 105 static int p_evec_alloc; /* Number of events allocated */ 106 107 /* 108 * Following are the objects (-o option) that we can select upon. 109 */ 110 static char *p_fileobj = NULL; 111 static char *p_msgqobj = NULL; 112 static char *p_pidobj = NULL; 113 static char *p_semobj = NULL; 114 static char *p_shmobj = NULL; 115 static char *p_sockobj = NULL; 116 117 static uint32_t opttochk = 0; 118 119 static int select_zone(const char *zone, uint32_t *optchkd); 120 121 static void 122 parse_regexp(char *re_string) 123 { 124 char *orig, *copy, re_error[64]; 125 struct re_entry *rep; 126 int error, nstrs, i, len; 127 128 copy = strdup(re_string); 129 orig = copy; 130 len = strlen(copy); 131 for (nstrs = 0, i = 0; i < len; i++) { 132 if (copy[i] == ',' && i > 0) { 133 if (copy[i - 1] == '\\') 134 strlcpy(©[i - 1], ©[i], len); 135 else { 136 nstrs++; 137 copy[i] = '\0'; 138 } 139 } 140 } 141 TAILQ_INIT(&re_head); 142 for (i = 0; i < nstrs + 1; i++) { 143 rep = calloc(1, sizeof(*rep)); 144 if (rep == NULL) { 145 (void) fprintf(stderr, "calloc: %s\n", 146 strerror(errno)); 147 exit(1); 148 } 149 if (*copy == '~') { 150 copy++; 151 rep->re_negate = 1; 152 } 153 rep->re_pattern = strdup(copy); 154 error = regcomp(&rep->re_regexp, rep->re_pattern, 155 REG_EXTENDED | REG_NOSUB); 156 if (error != 0) { 157 regerror(error, &rep->re_regexp, re_error, 64); 158 (void) fprintf(stderr, "regcomp: %s\n", re_error); 159 exit(1); 160 } 161 TAILQ_INSERT_TAIL(&re_head, rep, re_glue); 162 len = strlen(copy); 163 copy += len + 1; 164 } 165 free(orig); 166 } 167 168 static void 169 usage(const char *msg) 170 { 171 fprintf(stderr, "%s\n", msg); 172 fprintf(stderr, "Usage: auditreduce [options] [file ...]\n"); 173 fprintf(stderr, "\tOptions are : \n"); 174 fprintf(stderr, "\t-A : all records\n"); 175 fprintf(stderr, "\t-a YYYYMMDD[HH[[MM[SS]]] : after date\n"); 176 fprintf(stderr, "\t-b YYYYMMDD[HH[[MM[SS]]] : before date\n"); 177 fprintf(stderr, "\t-c <flags> : matching class\n"); 178 fprintf(stderr, "\t-d YYYYMMDD : on date\n"); 179 fprintf(stderr, "\t-e <uid|name> : effective user\n"); 180 fprintf(stderr, "\t-f <gid|group> : effective group\n"); 181 fprintf(stderr, "\t-g <gid|group> : real group\n"); 182 fprintf(stderr, "\t-j <pid> : subject id \n"); 183 fprintf(stderr, "\t-m <evno|evname> : matching event\n"); 184 fprintf(stderr, "\t-o objecttype=objectvalue\n"); 185 fprintf(stderr, "\t\t file=<pathname>\n"); 186 fprintf(stderr, "\t\t msgqid=<ID>\n"); 187 fprintf(stderr, "\t\t pid=<ID>\n"); 188 fprintf(stderr, "\t\t semid=<ID>\n"); 189 fprintf(stderr, "\t\t shmid=<ID>\n"); 190 fprintf(stderr, "\t-r <uid|name> : real user\n"); 191 fprintf(stderr, "\t-u <uid|name> : audit user\n"); 192 fprintf(stderr, "\t-v : select non-matching records\n"); 193 fprintf(stderr, "\t-z <zone> : zone name\n"); 194 exit(EX_USAGE); 195 } 196 197 /* 198 * Check if the given auid matches the selection criteria. 199 */ 200 static int 201 select_auid(int au) 202 { 203 204 /* Check if we want to select on auid. */ 205 if (ISOPTSET(opttochk, OPT_u)) { 206 if (au != p_auid) 207 return (0); 208 } 209 return (1); 210 } 211 212 /* 213 * Check if the given euid matches the selection criteria. 214 */ 215 static int 216 select_euid(int euser) 217 { 218 219 /* Check if we want to select on euid. */ 220 if (ISOPTSET(opttochk, OPT_e)) { 221 if (euser != p_euid) 222 return (0); 223 } 224 return (1); 225 } 226 227 /* 228 * Check if the given egid matches the selection criteria. 229 */ 230 static int 231 select_egid(int egrp) 232 { 233 234 /* Check if we want to select on egid. */ 235 if (ISOPTSET(opttochk, OPT_f)) { 236 if (egrp != p_egid) 237 return (0); 238 } 239 return (1); 240 } 241 242 /* 243 * Check if the given rgid matches the selection criteria. 244 */ 245 static int 246 select_rgid(int grp) 247 { 248 249 /* Check if we want to select on rgid. */ 250 if (ISOPTSET(opttochk, OPT_g)) { 251 if (grp != p_rgid) 252 return (0); 253 } 254 return (1); 255 } 256 257 /* 258 * Check if the given ruid matches the selection criteria. 259 */ 260 static int 261 select_ruid(int user) 262 { 263 264 /* Check if we want to select on rgid. */ 265 if (ISOPTSET(opttochk, OPT_r)) { 266 if (user != p_ruid) 267 return (0); 268 } 269 return (1); 270 } 271 272 /* 273 * Check if the given subject id (pid) matches the selection criteria. 274 */ 275 static int 276 select_subid(int subid) 277 { 278 279 /* Check if we want to select on subject uid. */ 280 if (ISOPTSET(opttochk, OPT_j)) { 281 if (subid != p_subid) 282 return (0); 283 } 284 return (1); 285 } 286 287 288 /* 289 * Check if object's pid maches the given pid. 290 */ 291 static int 292 select_pidobj(uint32_t pid) 293 { 294 295 if (ISOPTSET(opttochk, OPT_op)) { 296 if (pid != (uint32_t)strtol(p_pidobj, (char **)NULL, 10)) 297 return (0); 298 } 299 return (1); 300 } 301 302 /* 303 * Check if the given ipc object with the given type matches the selection 304 * criteria. 305 */ 306 static int 307 select_ipcobj(u_char type, uint32_t id, uint32_t *optchkd) 308 { 309 310 if (type == AT_IPC_MSG) { 311 SETOPT((*optchkd), OPT_om); 312 if (ISOPTSET(opttochk, OPT_om)) { 313 if (id != (uint32_t)strtol(p_msgqobj, (char **)NULL, 314 10)) 315 return (0); 316 } 317 return (1); 318 } else if (type == AT_IPC_SEM) { 319 SETOPT((*optchkd), OPT_ose); 320 if (ISOPTSET(opttochk, OPT_ose)) { 321 if (id != (uint32_t)strtol(p_semobj, (char **)NULL, 10)) 322 return (0); 323 } 324 return (1); 325 } else if (type == AT_IPC_SHM) { 326 SETOPT((*optchkd), OPT_osh); 327 if (ISOPTSET(opttochk, OPT_osh)) { 328 if (id != (uint32_t)strtol(p_shmobj, (char **)NULL, 10)) 329 return (0); 330 } 331 return (1); 332 } 333 334 /* Unknown type -- filter if *any* ipc filtering is required. */ 335 if (ISOPTSET(opttochk, OPT_om) || ISOPTSET(opttochk, OPT_ose) 336 || ISOPTSET(opttochk, OPT_osh)) 337 return (0); 338 339 return (1); 340 } 341 342 343 /* 344 * Check if the file name matches selection criteria. 345 */ 346 static int 347 select_filepath(char *path, uint32_t *optchkd) 348 { 349 struct re_entry *rep; 350 int match; 351 352 SETOPT((*optchkd), OPT_of); 353 match = 1; 354 if (ISOPTSET(opttochk, OPT_of)) { 355 match = 0; 356 TAILQ_FOREACH(rep, &re_head, re_glue) { 357 if (regexec(&rep->re_regexp, path, 0, NULL, 358 0) != REG_NOMATCH) 359 return (!rep->re_negate); 360 } 361 } 362 return (match); 363 } 364 365 /* 366 * Returns 1 if the following pass the selection rules: 367 * 368 * before-time, 369 * after time, 370 * date, 371 * class, 372 * event 373 */ 374 static int 375 select_hdr32(tokenstr_t tok, uint32_t *optchkd) 376 { 377 uint16_t *ev; 378 int match; 379 380 SETOPT((*optchkd), (OPT_A | OPT_a | OPT_b | OPT_c | OPT_m | OPT_v)); 381 382 /* The A option overrides a, b and d. */ 383 if (!ISOPTSET(opttochk, OPT_A)) { 384 if (ISOPTSET(opttochk, OPT_a)) { 385 if (difftime((time_t)tok.tt.hdr32.s, p_atime) < 0) { 386 /* Record was created before p_atime. */ 387 return (0); 388 } 389 } 390 391 if (ISOPTSET(opttochk, OPT_b)) { 392 if (difftime(p_btime, (time_t)tok.tt.hdr32.s) < 0) { 393 /* Record was created after p_btime. */ 394 return (0); 395 } 396 } 397 } 398 399 if (ISOPTSET(opttochk, OPT_c)) { 400 /* 401 * Check if the classes represented by the event matches 402 * given class. 403 */ 404 if (au_preselect(tok.tt.hdr32.e_type, &maskp, AU_PRS_BOTH, 405 AU_PRS_USECACHE) != 1) 406 return (0); 407 } 408 409 /* Check if event matches. */ 410 if (ISOPTSET(opttochk, OPT_m)) { 411 match = 0; 412 for (ev = p_evec; ev < &p_evec[p_evec_used]; ev++) 413 if (tok.tt.hdr32.e_type == *ev) 414 match = 1; 415 if (match == 0) 416 return (0); 417 } 418 419 return (1); 420 } 421 422 static int 423 select_return32(tokenstr_t tok_ret32, tokenstr_t tok_hdr32, uint32_t *optchkd) 424 { 425 int sorf; 426 427 SETOPT((*optchkd), (OPT_c)); 428 if (tok_ret32.tt.ret32.status == 0) 429 sorf = AU_PRS_SUCCESS; 430 else 431 sorf = AU_PRS_FAILURE; 432 if (ISOPTSET(opttochk, OPT_c)) { 433 if (au_preselect(tok_hdr32.tt.hdr32.e_type, &maskp, sorf, 434 AU_PRS_USECACHE) != 1) 435 return (0); 436 } 437 return (1); 438 } 439 440 /* 441 * Return 1 if checks for the the following succeed 442 * auid, 443 * euid, 444 * egid, 445 * rgid, 446 * ruid, 447 * process id 448 */ 449 static int 450 select_proc32(tokenstr_t tok, uint32_t *optchkd) 451 { 452 453 SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_op)); 454 455 if (!select_auid(tok.tt.proc32.auid)) 456 return (0); 457 if (!select_euid(tok.tt.proc32.euid)) 458 return (0); 459 if (!select_egid(tok.tt.proc32.egid)) 460 return (0); 461 if (!select_rgid(tok.tt.proc32.rgid)) 462 return (0); 463 if (!select_ruid(tok.tt.proc32.ruid)) 464 return (0); 465 if (!select_pidobj(tok.tt.proc32.pid)) 466 return (0); 467 return (1); 468 } 469 470 /* 471 * Return 1 if checks for the the following succeed 472 * auid, 473 * euid, 474 * egid, 475 * rgid, 476 * ruid, 477 * subject id 478 */ 479 static int 480 select_subj32(tokenstr_t tok, uint32_t *optchkd) 481 { 482 483 SETOPT((*optchkd), (OPT_u | OPT_e | OPT_f | OPT_g | OPT_r | OPT_j)); 484 485 if (!select_auid(tok.tt.subj32.auid)) 486 return (0); 487 if (!select_euid(tok.tt.subj32.euid)) 488 return (0); 489 if (!select_egid(tok.tt.subj32.egid)) 490 return (0); 491 if (!select_rgid(tok.tt.subj32.rgid)) 492 return (0); 493 if (!select_ruid(tok.tt.subj32.ruid)) 494 return (0); 495 if (!select_subid(tok.tt.subj32.pid)) 496 return (0); 497 return (1); 498 } 499 500 /* 501 * Check if the given zone matches the selection criteria. 502 */ 503 static int 504 select_zone(const char *zone, uint32_t *optchkd) 505 { 506 507 SETOPT((*optchkd), OPT_z); 508 if (ISOPTSET(opttochk, OPT_z) && p_zone != NULL) { 509 if (fnmatch(p_zone, zone, FNM_PATHNAME) != 0) 510 return (0); 511 } 512 return (1); 513 } 514 515 /* 516 * Read each record from the audit trail. Check if it is selected after 517 * passing through each of the options 518 */ 519 static int 520 select_records(FILE *fp) 521 { 522 tokenstr_t tok_hdr32_copy; 523 u_char *buf; 524 tokenstr_t tok; 525 int reclen; 526 int bytesread; 527 int selected; 528 uint32_t optchkd; 529 int print; 530 531 int err = 0; 532 while ((reclen = au_read_rec(fp, &buf)) != -1) { 533 optchkd = 0; 534 bytesread = 0; 535 selected = 1; 536 while ((selected == 1) && (bytesread < reclen)) { 537 if (-1 == au_fetch_tok(&tok, buf + bytesread, 538 reclen - bytesread)) { 539 /* Is this an incomplete record? */ 540 err = 1; 541 break; 542 } 543 544 /* 545 * For each token type we have have different 546 * selection criteria. 547 */ 548 switch(tok.id) { 549 case AUT_HEADER32: 550 selected = select_hdr32(tok, 551 &optchkd); 552 bcopy(&tok, &tok_hdr32_copy, 553 sizeof(tok)); 554 break; 555 556 case AUT_PROCESS32: 557 selected = select_proc32(tok, 558 &optchkd); 559 break; 560 561 case AUT_SUBJECT32: 562 selected = select_subj32(tok, 563 &optchkd); 564 break; 565 566 case AUT_IPC: 567 selected = select_ipcobj( 568 tok.tt.ipc.type, tok.tt.ipc.id, 569 &optchkd); 570 break; 571 572 case AUT_PATH: 573 selected = select_filepath( 574 tok.tt.path.path, &optchkd); 575 break; 576 577 case AUT_RETURN32: 578 selected = select_return32(tok, 579 tok_hdr32_copy, &optchkd); 580 break; 581 582 case AUT_ZONENAME: 583 selected = select_zone(tok.tt.zonename.zonename, &optchkd); 584 break; 585 586 default: 587 break; 588 } 589 bytesread += tok.len; 590 } 591 /* Check if all the options were matched. */ 592 print = ((selected == 1) && (!err) && (!(opttochk & ~optchkd))); 593 if (ISOPTSET(opttochk, OPT_v)) 594 print = !print; 595 if (print) 596 (void) fwrite(buf, 1, reclen, stdout); 597 free(buf); 598 } 599 return (0); 600 } 601 602 /* 603 * The -o option has the form object_type=object_value. Identify the object 604 * components. 605 */ 606 static void 607 parse_object_type(char *name, char *val) 608 { 609 if (val == NULL) 610 return; 611 612 if (!strcmp(name, FILEOBJ)) { 613 p_fileobj = val; 614 parse_regexp(val); 615 SETOPT(opttochk, OPT_of); 616 } else if (!strcmp(name, MSGQIDOBJ)) { 617 p_msgqobj = val; 618 SETOPT(opttochk, OPT_om); 619 } else if (!strcmp(name, PIDOBJ)) { 620 p_pidobj = val; 621 SETOPT(opttochk, OPT_op); 622 } else if (!strcmp(name, SEMIDOBJ)) { 623 p_semobj = val; 624 SETOPT(opttochk, OPT_ose); 625 } else if (!strcmp(name, SHMIDOBJ)) { 626 p_shmobj = val; 627 SETOPT(opttochk, OPT_osh); 628 } else if (!strcmp(name, SOCKOBJ)) { 629 p_sockobj = val; 630 SETOPT(opttochk, OPT_oso); 631 } else 632 usage("unknown value for -o"); 633 } 634 635 int 636 main(int argc, char **argv) 637 { 638 struct group *grp; 639 struct passwd *pw; 640 struct tm tm; 641 au_event_t *n; 642 FILE *fp; 643 int i; 644 char *objval, *converr; 645 int ch; 646 char timestr[128]; 647 char *fname; 648 uint16_t *etp; 649 #ifdef HAVE_CAP_ENTER 650 int retval, status; 651 pid_t childpid, pid; 652 #endif 653 654 converr = NULL; 655 656 while ((ch = getopt(argc, argv, "Aa:b:c:d:e:f:g:j:m:o:r:u:vz:")) != -1) { 657 switch(ch) { 658 case 'A': 659 SETOPT(opttochk, OPT_A); 660 break; 661 662 case 'a': 663 if (ISOPTSET(opttochk, OPT_a)) { 664 usage("d is exclusive with a and b"); 665 } 666 SETOPT(opttochk, OPT_a); 667 bzero(&tm, sizeof(tm)); 668 strptime(optarg, "%Y%m%d%H%M%S", &tm); 669 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", 670 &tm); 671 /* fprintf(stderr, "Time converted = %s\n", timestr); */ 672 p_atime = mktime(&tm); 673 break; 674 675 case 'b': 676 if (ISOPTSET(opttochk, OPT_b)) { 677 usage("d is exclusive with a and b"); 678 } 679 SETOPT(opttochk, OPT_b); 680 bzero(&tm, sizeof(tm)); 681 strptime(optarg, "%Y%m%d%H%M%S", &tm); 682 strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", 683 &tm); 684 /* fprintf(stderr, "Time converted = %s\n", timestr); */ 685 p_btime = mktime(&tm); 686 break; 687 688 case 'c': 689 if (0 != getauditflagsbin(optarg, &maskp)) { 690 /* Incorrect class */ 691 usage("Incorrect class"); 692 } 693 SETOPT(opttochk, OPT_c); 694 break; 695 696 case 'd': 697 if (ISOPTSET(opttochk, OPT_b) || ISOPTSET(opttochk, 698 OPT_a)) 699 usage("'d' is exclusive with 'a' and 'b'"); 700 SETOPT(opttochk, OPT_d); 701 bzero(&tm, sizeof(tm)); 702 strptime(optarg, "%Y%m%d", &tm); 703 strftime(timestr, sizeof(timestr), "%Y%m%d", &tm); 704 /* fprintf(stderr, "Time converted = %s\n", timestr); */ 705 p_atime = mktime(&tm); 706 tm.tm_hour = 23; 707 tm.tm_min = 59; 708 tm.tm_sec = 59; 709 strftime(timestr, sizeof(timestr), "%Y%m%d", &tm); 710 /* fprintf(stderr, "Time converted = %s\n", timestr); */ 711 p_btime = mktime(&tm); 712 break; 713 714 case 'e': 715 p_euid = strtol(optarg, &converr, 10); 716 if (*converr != '\0') { 717 /* Try the actual name */ 718 if ((pw = getpwnam(optarg)) == NULL) 719 break; 720 p_euid = pw->pw_uid; 721 } 722 SETOPT(opttochk, OPT_e); 723 break; 724 725 case 'f': 726 p_egid = strtol(optarg, &converr, 10); 727 if (*converr != '\0') { 728 /* Try actual group name. */ 729 if ((grp = getgrnam(optarg)) == NULL) 730 break; 731 p_egid = grp->gr_gid; 732 } 733 SETOPT(opttochk, OPT_f); 734 break; 735 736 case 'g': 737 p_rgid = strtol(optarg, &converr, 10); 738 if (*converr != '\0') { 739 /* Try actual group name. */ 740 if ((grp = getgrnam(optarg)) == NULL) 741 break; 742 p_rgid = grp->gr_gid; 743 } 744 SETOPT(opttochk, OPT_g); 745 break; 746 747 case 'j': 748 p_subid = strtol(optarg, (char **)NULL, 10); 749 SETOPT(opttochk, OPT_j); 750 break; 751 752 case 'm': 753 if (p_evec == NULL) { 754 p_evec_alloc = 32; 755 p_evec = malloc(sizeof(*etp) * p_evec_alloc); 756 if (p_evec == NULL) 757 err(1, "malloc"); 758 } else if (p_evec_alloc == p_evec_used) { 759 p_evec_alloc <<= 1; 760 p_evec = realloc(p_evec, 761 sizeof(*p_evec) * p_evec_alloc); 762 if (p_evec == NULL) 763 err(1, "realloc"); 764 } 765 etp = &p_evec[p_evec_used++]; 766 *etp = strtol(optarg, (char **)NULL, 10); 767 if (*etp == 0) { 768 /* Could be the string representation. */ 769 n = getauevnonam(optarg); 770 if (n == NULL) 771 usage("Incorrect event name"); 772 *etp = *n; 773 } 774 SETOPT(opttochk, OPT_m); 775 break; 776 777 case 'o': 778 objval = strchr(optarg, '='); 779 if (objval != NULL) { 780 *objval = '\0'; 781 objval += 1; 782 parse_object_type(optarg, objval); 783 } 784 break; 785 786 case 'r': 787 p_ruid = strtol(optarg, &converr, 10); 788 if (*converr != '\0') { 789 if ((pw = getpwnam(optarg)) == NULL) 790 break; 791 p_ruid = pw->pw_uid; 792 } 793 SETOPT(opttochk, OPT_r); 794 break; 795 796 case 'u': 797 p_auid = strtol(optarg, &converr, 10); 798 if (*converr != '\0') { 799 if ((pw = getpwnam(optarg)) == NULL) 800 break; 801 p_auid = pw->pw_uid; 802 } 803 SETOPT(opttochk, OPT_u); 804 break; 805 806 case 'v': 807 SETOPT(opttochk, OPT_v); 808 break; 809 810 case 'z': 811 p_zone = optarg; 812 SETOPT(opttochk, OPT_z); 813 break; 814 815 case '?': 816 default: 817 usage("Unknown option"); 818 } 819 } 820 argv += optind; 821 argc -= optind; 822 823 if (argc == 0) { 824 #ifdef HAVE_CAP_ENTER 825 retval = cap_enter(); 826 if (retval != 0 && errno != ENOSYS) 827 err(EXIT_FAILURE, "cap_enter"); 828 #endif 829 if (select_records(stdin) == -1) 830 errx(EXIT_FAILURE, 831 "Couldn't select records from stdin"); 832 exit(EXIT_SUCCESS); 833 } 834 835 /* 836 * XXX: We should actually be merging records here. 837 */ 838 for (i = 0; i < argc; i++) { 839 fname = argv[i]; 840 fp = fopen(fname, "r"); 841 if (fp == NULL) 842 errx(EXIT_FAILURE, "Couldn't open %s", fname); 843 844 /* 845 * If operating with sandboxing, create a sandbox process for 846 * each trail file we operate on. This avoids the need to do 847 * fancy things with file descriptors, etc, when iterating on 848 * a list of arguments. 849 * 850 * NB: Unlike praudit(1), auditreduce(1) terminates if it hits 851 * any errors. Propagate the error from the child to the 852 * parent if any problems arise. 853 */ 854 #ifdef HAVE_CAP_ENTER 855 childpid = fork(); 856 if (childpid == 0) { 857 /* Child. */ 858 retval = cap_enter(); 859 if (retval != 0 && errno != ENOSYS) 860 errx(EXIT_FAILURE, "cap_enter"); 861 if (select_records(fp) == -1) 862 errx(EXIT_FAILURE, 863 "Couldn't select records %s", fname); 864 exit(0); 865 } 866 867 /* Parent. Await child termination, check exit value. */ 868 while ((pid = waitpid(childpid, &status, 0)) != childpid); 869 if (WEXITSTATUS(status) != 0) 870 exit(EXIT_FAILURE); 871 #else 872 if (select_records(fp) == -1) 873 errx(EXIT_FAILURE, "Couldn't select records %s", 874 fname); 875 #endif 876 fclose(fp); 877 } 878 exit(EXIT_SUCCESS); 879 } 880