1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Main processor for auditreduce. 28 * Mproc() is the entry point for this module. It is the only visible 29 * function in this module. 30 */ 31 32 #include <sys/types.h> 33 #include <locale.h> 34 #include <bsm/libbsm.h> 35 #include <bsm/audit.h> 36 #include "auditr.h" 37 38 extern int write_header(); 39 extern int token_processing(); 40 41 static void asort(); 42 static audit_pcb_t *aget(); 43 static int get_file(); 44 static int write_recs(); 45 static int get_recs(); 46 static int check_rec(); 47 static void check_order(); 48 static int check_header(); 49 static int get_record(); 50 51 static char empty_file_token[] = { 52 #ifdef _LP64 53 AUT_OTHER_FILE64, /* token id */ 54 0, 0, 0, 0, 0, 0, 0, 0, /* seconds of time */ 55 0, 0, 0, 0, 0, 0, 0, 0, /* microseconds of time */ 56 #else 57 AUT_OTHER_FILE32, /* token id */ 58 0, 0, 0, 0, /* seconds of time */ 59 0, 0, 0, 0, /* microseconds of time */ 60 #endif 61 0, 0, /* length of path name */ 62 }; 63 64 65 /* 66 * .func mproc - main processor. 67 * .desc Mproc controls a single process's actions. 68 * First one record is retreived from each pcb. As they are retreived 69 * they are placed into a linked list sorted with oldest first. Then 70 * the first one from the list is written out and another record 71 * read in to replace it. The new record is placed into the list. 72 * This continues until the list is empty. 73 * .call ret = mproc(pcbr). 74 * .arg pcbr - ptr to pcb for this process. 75 * .ret 0 - no errors in processing. 76 * .ret -1 - errors in processing (message already printed). 77 */ 78 int 79 mproc(pcbr) 80 register audit_pcb_t *pcbr; 81 { 82 int i, ret, junk; 83 int nrecs = 0; /* number of records read from stream */ 84 int nprecs = 0; /* number of records put to stream */ 85 register audit_pcb_t *pcb; 86 audit_pcb_t *aget(); 87 void asort(); 88 89 #if AUDIT_PROC_TRACE 90 (void) fprintf(stderr, "mproc: count %d lo %d hi %d\n", 91 pcbr->pcb_count, pcbr->pcb_lo, pcbr->pcb_hi); 92 #endif 93 94 /* 95 * First load up a record from each input group. 96 */ 97 for (i = pcbr->pcb_lo; i <= pcbr->pcb_hi; i++) { 98 pcb = &(pcbr->pcb_below[i]); /* get next PCB */ 99 while (pcb->pcb_time < 0) { /* while no active record ... */ 100 if ((ret = get_file(pcb)) == -1) 101 break; /* no files - finished PCB */ 102 if (ret == -2) 103 return (-1); /* quit processing - failed */ 104 if (get_recs(pcb, &nrecs) == 0) 105 asort(pcb); /* got a rec - put in list */ 106 } 107 } 108 /* 109 * Now process all of the records. 110 */ 111 while ((pcb = aget()) != NULL) { /* get oldest record */ 112 if (write_recs(pcbr, pcb, &nprecs)) 113 return (-1); 114 while (pcb->pcb_time < 0) { /* while we don't have a rec */ 115 if (pcb->pcb_fpr == NULL) { /* no active file ... */ 116 if ((ret = get_file(pcb)) == -1) 117 break; /* no files - finished pcb */ 118 else if (ret == -2) 119 return (-1); /* quit - failed */ 120 } 121 if (get_recs(pcb, &nrecs) == 0) 122 asort(pcb); /* put record in list */ 123 } 124 } 125 /* 126 * For root: write outfile header if no records were encountered. 127 * For non-root: write trailer to pipe and close pipe. 128 */ 129 if (pcbr->pcb_flags & PF_ROOT) { 130 if (nprecs == 0) { 131 if (write_header()) /* write header if no records */ 132 return (-1); 133 } 134 } else { 135 pcb = &(pcbr->pcb_below[0]); /* any old PCB will do */ 136 pcb->pcb_rec = empty_file_token; 137 if (write_recs(pcbr, pcb, &junk)) 138 return (-1); 139 if (fclose(pcbr->pcb_fpw) == EOF) { 140 if (!f_quiet) 141 (void) fprintf(stderr, 142 gettext("%s couldn't close pipe.\n"), ar); 143 } 144 } 145 /* 146 * For root process tell how many records were written. 147 */ 148 if (f_verbose && (pcbr->pcb_flags & PF_ROOT)) { 149 (void) fprintf(stderr, 150 gettext("%s %d record(s) total were written out.\n"), 151 ar, nprecs); 152 } 153 return (0); 154 } 155 156 157 /* 158 * Head of linked-list of pcbs - sorted by time - oldest first. 159 */ 160 static audit_pcb_t *pcbls = NULL; 161 162 /* 163 * .func asort - audit sort. 164 * .desc Place a pcb in the list sorted by time - oldest first. 165 * .call asort(pcb); 166 * .arg pcb - ptr to pcb to install in list. 167 * .ret void. 168 */ 169 static void 170 asort(pcb) 171 register audit_pcb_t *pcb; 172 { 173 register audit_pcb_t *pcbc, *pcbp; 174 extern audit_pcb_t *pcbls; /* ptr to start of list */ 175 176 pcb->pcb_next = NULL; 177 if (pcbls == NULL) { 178 pcbls = pcb; /* empty list */ 179 return; 180 } 181 pcbc = pcbls; /* current pcb */ 182 pcbp = pcbls; /* previous pcb */ 183 while (pcbc != NULL) { 184 if (pcb->pcb_time < pcbc->pcb_time) { 185 if (pcbp == pcbc) { 186 pcb->pcb_next = pcbls; /* new -> 1st in list */ 187 pcbls = pcb; 188 return; 189 } 190 pcbp->pcb_next = pcb; 191 pcb->pcb_next = pcbc; /* new in the inside */ 192 return; 193 } 194 pcbp = pcbc; 195 pcbc = pcbc->pcb_next; 196 } 197 pcbp->pcb_next = pcb; /* new -> last */ 198 } 199 200 201 /* 202 * .func aget - audit get. 203 * .desc Get the first pcb from the list. Pcb is removed from list, too. 204 * .call pcb = aget(). 205 * .arg none. 206 * .ret pcb - ptr to pcb that was the first. 207 */ 208 static audit_pcb_t * 209 aget() 210 { 211 audit_pcb_t *pcbret; 212 extern audit_pcb_t *pcbls; /* ptr to start of list */ 213 214 if (pcbls == NULL) 215 return (pcbls); /* empty list */ 216 pcbret = pcbls; 217 pcbls = pcbls->pcb_next; /* 2nd becomes 1st */ 218 return (pcbret); 219 } 220 221 222 /* 223 * .func get_file - get a new file. 224 * .desc Get the next file from the pcb's list. Check the header to see 225 * if the file really is an audit file. If there are no more then 226 * quit. If a file open (fopen) fails because the system file table 227 * is full or the process file table is full then quit processing 228 * altogether. 229 * .call ret = get_file(pcb). 230 * .arg pcb - pcb holding the fcb's (files). 231 * .ret 0 - new file opened for processing. 232 * .ret -1 - no more files - pcb finished. 233 * .ret -2 - fatal error - quit processing. 234 */ 235 static int 236 get_file(pcb) 237 register audit_pcb_t *pcb; 238 { 239 FILE *fp; 240 audit_fcb_t *fcb; 241 242 /* 243 * Process file list until a good one if found or empty. 244 */ 245 while (pcb->pcb_fpr == NULL) { 246 if ((fcb = pcb->pcb_first) == NULL) { 247 pcb->pcb_time = -1; 248 return (-1); /* pcb is all done */ 249 } else { 250 /* 251 * If we are reading from files then open the next one. 252 */ 253 if (!f_stdin) { 254 if ((fp = fopen(fcb->fcb_file, "r")) == NULL) { 255 if (!f_quiet) { 256 (void) sprintf(errbuf, gettext( 257 "%s couldn't open:\n %s"), 258 ar, fcb->fcb_file); 259 perror(errbuf); 260 } 261 /* 262 * See if file space is depleted. 263 * If it is then we quit. 264 */ 265 if (errno == ENFILE || errno == EMFILE) 266 { 267 return (-2); 268 } 269 pcb->pcb_first = fcb->fcb_next; 270 continue; /* try another file */ 271 } 272 } else { 273 /* 274 * Read from standard input. 275 */ 276 fp = stdin; 277 } 278 /* 279 * Check header of audit file. 280 */ 281 if (check_header(fp, fcb->fcb_name)) { 282 if (!f_quiet) { 283 (void) fprintf(stderr, 284 "%s %s:\n %s.\n", 285 ar, error_str, fcb->fcb_file); 286 } 287 if (fclose(fp) == EOF) { 288 if (!f_quiet) { 289 (void) fprintf(stderr, gettext( 290 "%s couldn't close %s.\n"), 291 ar, fcb->fcb_file); 292 } 293 } 294 pcb->pcb_first = fcb->fcb_next; 295 continue; /* try another file */ 296 } 297 /* 298 * Found a good audit file. 299 * Initalize pcb for processing. 300 */ 301 pcb->pcb_first = fcb->fcb_next; 302 pcb->pcb_cur = fcb; 303 pcb->pcb_fpr = fp; 304 pcb->pcb_nrecs = 0; 305 pcb->pcb_nprecs = 0; 306 pcb->pcb_otime = -1; 307 } 308 } 309 return (0); 310 } 311 312 313 /* 314 * .func write_recs - write records. 315 * .desc Write record from a buffer to output stream. Keep an eye out 316 * for the first and last records of the root's output stream. 317 * .call ret = write_recs(pcbr, pcb, nprecs). 318 * .arg pcbr - ptr to node pcb. 319 * .arg pcb - ptr to pcb holding the stream. 320 * .arg nprecs - ptr to the number of put records. Updated here. 321 * .ret 0 - no errors detected. 322 * .ret -1 - error in writing. Quit processing. 323 */ 324 static int 325 write_recs(pcbr, pcb, nprecs) 326 register audit_pcb_t *pcbr, *pcb; 327 int *nprecs; 328 { 329 adr_t adr; 330 char id; 331 int32_t size; 332 333 adrm_start(&adr, pcb->pcb_rec); 334 (void) adrm_char(&adr, &id, 1); 335 (void) adrm_int32(&adr, &size, 1); 336 337 /* 338 * Scan for first record to be written to outfile. 339 * When we find it then write the header and 340 * save the time for the outfile name. 341 */ 342 if ((*nprecs)++ == 0) { 343 if (pcbr->pcb_flags & PF_ROOT) { 344 f_start = pcb->pcb_time; /* save start time */ 345 if (write_header()) 346 return (-1); 347 } 348 } 349 f_end = pcb->pcb_time; /* find last record's time */ 350 pcb->pcb_time = -1; /* disable just written rec */ 351 352 if ((fwrite(pcb->pcb_rec, sizeof (char), size, pcbr->pcb_fpw)) != 353 size) { 354 if (pcbr->pcb_flags & PF_ROOT) { 355 (void) sprintf(errbuf, gettext( 356 "%s write failed to %s"), 357 ar, f_outfile ? f_outfile : gettext("stdout")); 358 perror(errbuf); 359 } else { 360 perror(gettext("auditreduce: write failed to pipe")); 361 } 362 return (-1); 363 } 364 free(pcb->pcb_rec); 365 return (0); 366 } 367 368 /* 369 * .func get_recs - get records. 370 * .desc Get records from a stream until one passing the current selection 371 * criteria is found or the stream is emptied. 372 * .call ret = get_recs(pcb, nr). 373 * .arg pcb - ptr to pcb that holds this stream. 374 * .arg nr - ptr to number of records read. Updated by this routine. 375 * .ret 0 - got a record. 376 * .ret -1 - stream is finished. 377 */ 378 static int 379 get_recs(pcb, nr) 380 register audit_pcb_t *pcb; 381 int *nr; 382 { 383 adr_t adr; 384 time_t secs; 385 int tmp; 386 int ret, ret2; 387 int nrecs = 0; /* count how many records read this call */ 388 int getrec = TRUE; 389 int alldone = FALSE; 390 char header_type; 391 short e; 392 char *str; 393 #if AUDIT_FILE 394 static void get_trace(); 395 #endif 396 397 while (getrec) { 398 ret = get_record(pcb->pcb_fpr, &pcb->pcb_rec, 399 pcb->pcb_cur->fcb_name); 400 if (ret > 0) { 401 adrm_start(&adr, pcb->pcb_rec); 402 403 /* get token id */ 404 (void) adrm_char(&adr, (char *)&header_type, 1); 405 /* skip over byte count */ 406 (void) adrm_int32(&adr, (int32_t *)&tmp, 1); 407 /* skip over version # */ 408 (void) adrm_char(&adr, (char *)&tmp, 1); 409 /* skip over event id */ 410 (void) adrm_short(&adr, (short *)&e, 1); 411 /* skip over event id modifier */ 412 (void) adrm_short(&adr, (short *)&tmp, 1); 413 414 if (header_type == AUT_HEADER32) { 415 int32_t s, m; 416 417 /* get seconds */ 418 (void) adrm_int32(&adr, (int32_t *)&s, 1); 419 /* get microseconds */ 420 (void) adrm_int32(&adr, (int32_t *)&m, 1); 421 secs = (time_t)s; 422 } else if (header_type == AUT_HEADER32_EX) { 423 int32_t s, m; 424 int32_t t, junk[4]; /* at_type + at_addr[4] */ 425 426 /* skip type and ip address field */ 427 (void) adrm_int32(&adr, (int32_t *)&t, 1); 428 (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); 429 430 /* get seconds */ 431 (void) adrm_int32(&adr, (int32_t *)&s, 1); 432 /* get microseconds */ 433 (void) adrm_int32(&adr, (int32_t *)&m, 1); 434 secs = (time_t)s; 435 } else if (header_type == AUT_HEADER64) { 436 int64_t s, m; 437 438 /* get seconds */ 439 (void) adrm_int64(&adr, (int64_t *)&s, 1); 440 /* get microseconds */ 441 (void) adrm_int64(&adr, (int64_t *)&m, 1); 442 #if ((!defined(_LP64)) || defined(_SYSCALL32)) 443 if (s < (time_t)INT32_MIN || 444 s > (time_t)INT32_MAX) 445 secs = 0; 446 else 447 secs = (time_t)s; 448 #else 449 secs = (time_t)s; 450 #endif 451 } else if (header_type == AUT_HEADER64_EX) { 452 int64_t s, m; 453 int32_t t, junk[4]; 454 455 /* skip type and ip address field */ 456 (void) adrm_int32(&adr, (int32_t *)&t, 1); 457 (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); 458 459 /* get seconds */ 460 (void) adrm_int64(&adr, (int64_t *)&s, 1); 461 /* get microseconds */ 462 (void) adrm_int64(&adr, (int64_t *)&m, 1); 463 #if ((!defined(_LP64)) || defined(_SYSCALL32)) 464 if (s < (time_t)INT32_MIN || 465 s > (time_t)INT32_MAX) 466 secs = 0; 467 else 468 secs = (time_t)s; 469 #else 470 secs = (time_t)s; 471 #endif 472 } 473 } 474 475 #if AUDIT_REC 476 (void) fprintf(stderr, "get_recs: %d ret %d recno %d\n", 477 pcb->pcb_procno, ret, pcb->pcb_nrecs + 1); 478 #endif 479 /* 480 * See if entire file is after the time window specified. 481 * Must be check here because the start time of the file name 482 * may be after the first record(s). 483 */ 484 if (pcb->pcb_nrecs == 0 && (pcb->pcb_flags & PF_USEFILE)) { 485 /* 486 * If the first record read failed then use the time 487 * that was in the filename to judge. 488 */ 489 if (ret > 0) 490 (pcb->pcb_cur)->fcb_start = secs; 491 if (!f_all && (m_before <= (pcb->pcb_cur)->fcb_start)) { 492 (void) fclose(pcb->pcb_fpr); /* ignore file */ 493 pcb->pcb_fpr = NULL; 494 pcb->pcb_time = -1; 495 return (-1); 496 } else { 497 /* Give belated announcement of file opening. */ 498 if (f_verbose) { 499 (void) fprintf(stderr, 500 gettext("%s opened:\n %s.\n"), 501 ar, (pcb->pcb_cur)->fcb_file); 502 } 503 } 504 } 505 /* Succesful acquisition of a record. */ 506 if (ret > 0) { 507 pcb->pcb_time = secs; /* time of record */ 508 pcb->pcb_nrecs++; /* # of read recs from stream */ 509 nrecs++; /* # of recs read this call */ 510 /* Only check record if at bottom of process tree. */ 511 if (pcb->pcb_flags & PF_USEFILE) { 512 check_order(pcb); /* check time sequence */ 513 if ((ret2 = check_rec(pcb)) == 0) { 514 pcb->pcb_nprecs++; 515 getrec = FALSE; 516 } else if (ret2 == -2) { 517 /* error */ 518 getrec = FALSE; /* get no more recs */ 519 alldone = TRUE; /* quit this file */ 520 free(pcb->pcb_rec); 521 } else { 522 /* -1: record not interesting */ 523 free(pcb->pcb_rec); 524 } 525 } else { 526 pcb->pcb_nprecs++; 527 getrec = FALSE; 528 } 529 } else { 530 /* Error with record read or all done with stream. */ 531 getrec = FALSE; 532 alldone = TRUE; 533 } 534 } 535 if (alldone == TRUE) { 536 #if AUDIT_FILE 537 get_trace(pcb); 538 #endif 539 /* Error in record read. Display messages. */ 540 if (ret < 0 || ret2 == -2) { 541 pcb->pcb_nrecs++; /* # of read records */ 542 if (!f_quiet) { 543 if (pcb->pcb_flags & PF_USEFILE) { 544 /* Ignore if this is not_terminated. */ 545 if (!strstr((pcb->pcb_cur)->fcb_file, 546 "not_terminated")) { 547 (void) fprintf(stderr, gettext("%s read error in %s at record %d.\n"), ar, 548 (pcb->pcb_cur)->fcb_file, pcb->pcb_nrecs); 549 } 550 } else { 551 (void) fprintf(stderr, gettext("%s read error in pipe at record %d.\n"), ar, 552 pcb->pcb_nrecs); 553 } 554 } 555 } else { 556 /* 557 * Only mark infile for deleting if we have succesfully 558 * processed all of it. 559 */ 560 if (pcb->pcb_flags & PF_USEFILE) 561 (pcb->pcb_cur)->fcb_flags |= FF_DELETE; 562 } 563 if (fclose(pcb->pcb_fpr) == EOF) { 564 if (!f_quiet) { 565 if (pcb->pcb_flags & PF_USEFILE) { 566 str = (pcb->pcb_cur)->fcb_file; 567 } else { 568 str = "pipe"; 569 } 570 (void) fprintf(stderr, 571 gettext("%s couldn't close %s.\n"), 572 ar, str); 573 } 574 } 575 pcb->pcb_fpr = NULL; 576 pcb->pcb_time = -1; 577 *nr += nrecs; 578 return (-1); 579 } 580 *nr += nrecs; 581 return (0); 582 } 583 584 585 #if AUDIT_FILE 586 /* 587 * .func get_trace - get trace. 588 * .desc If we are tracing file action (AUDIT_FILE is on) then print out 589 * a message when the file is closed regarding how many records 590 * were handled. 591 * .call get_trace(pcb). 592 * .arg pcb - ptr to pcb holding file/pipe. 593 * .ret void. 594 */ 595 static void 596 get_trace(pcb) 597 audit_pcb_t *pcb; 598 { 599 /* 600 * For file give filename, too. 601 */ 602 if (pcb->pcb_flags & PF_USEFILE) { 603 (void) fprintf(stderr, "%s closed %s: %d records read recs: \ 604 %d record written.\n", ar, (pcb->pcb_cur)->fcb_file, 605 pcb->pcb_nrecs, pcb->pcb_nprecs); 606 } else { 607 (void) fprintf(stderr, "%s closed pipe: %d records read: \ 608 %d records written .\n", ar, pcb->pcb_nrecs, 609 pcb->pcb_nprecs); 610 } 611 } 612 613 #endif 614 615 /* 616 * .func check_rec - check a record. 617 * .desc Check a record against the user's selection criteria. 618 * .call ret = check_rec(pcb). 619 * .arg pcb - ptr to pcb holding the record. 620 * .ret 0 - record accepted. 621 * .ret -1 - record rejected - continue processing file. 622 * .ret -2 - record rejected - quit processing file. 623 */ 624 static int 625 check_rec(pcb) 626 register audit_pcb_t *pcb; 627 { 628 adr_t adr; 629 struct timeval tv; 630 uint_t bytes; 631 au_emod_t id_modifier; 632 char version; 633 au_event_t event_type; 634 char tokenid; 635 int rc; /* return code */ 636 637 adrm_start(&adr, pcb->pcb_rec); 638 (void) adrm_char(&adr, &tokenid, 1); 639 640 /* 641 * checkflags will be my data structure for determining if 642 * a record has met ALL the selection criteria. Once 643 * checkflags == flags, we have seen all we need to of the 644 * record, and can go to the next one. If when we finish 645 * processing the record we still have stuff to see, 646 * checkflags != flags, and thus we should return a -1 647 * from this function meaning reject this record. 648 */ 649 650 checkflags = 0; 651 652 /* must be header token -- sanity check */ 653 if (tokenid != AUT_HEADER32 && tokenid != AUT_HEADER64 && 654 tokenid != AUT_HEADER32_EX && tokenid != AUT_HEADER64_EX) { 655 #if AUDIT_REC 656 (void) fprintf(stderr, 657 "check_rec: %d recno %d no header %d found\n", 658 pcb->pcb_procno, pcb->pcb_nrecs, tokenid); 659 #endif 660 return (-2); 661 } 662 663 /* 664 * The header token is: 665 * attribute id: char 666 * byte count: int 667 * version #: char 668 * event ID: short 669 * ID modifier: short 670 * seconds (date): int 671 * time (microsecs): int 672 */ 673 (void) adrm_u_int32(&adr, (uint32_t *)&bytes, 1); 674 (void) adrm_char(&adr, &version, 1); 675 (void) adrm_u_short(&adr, &event_type, 1); 676 677 /* 678 * Used by s5_IPC_token to set the ipc_type so 679 * s5_IPC_perm_token can test. 680 */ 681 ipc_type = (char)0; 682 683 if (flags & M_TYPE) { 684 checkflags |= M_TYPE; 685 if (m_type != event_type) 686 return (-1); 687 } 688 if (flags & M_CLASS) { 689 au_event_ent_t *ev = NULL; 690 691 checkflags |= M_CLASS; 692 if (cacheauevent(&ev, event_type) <= 0) { 693 (void) fprintf(stderr, gettext( 694 "Warning: invalid event no %d in audit trail."), 695 event_type); 696 return (-1); 697 } 698 global_class = ev->ae_class; 699 if (!(flags & M_SORF) && !(mask.am_success & global_class)) 700 return (-1); 701 } 702 703 (void) adrm_u_short(&adr, &id_modifier, 1); 704 705 /* 706 * Check record against time criteria. 707 * If the 'A' option was used then no time checking is done. 708 * The 'a' parameter is inclusive and the 'b' exclusive. 709 */ 710 if (tokenid == AUT_HEADER32) { 711 int32_t secs, msecs; 712 (void) adrm_int32(&adr, (int32_t *)&secs, 1); 713 (void) adrm_int32(&adr, (int32_t *)&msecs, 1); 714 tv.tv_sec = (time_t)secs; 715 tv.tv_usec = (suseconds_t)msecs; 716 } else if (tokenid == AUT_HEADER32_EX) { 717 int32_t secs, msecs; 718 int32_t t, junk[5]; /* at_type + at_addr[4] */ 719 /* skip type and ip address field */ 720 (void) adrm_int32(&adr, (int32_t *)&t, 1); 721 (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); 722 /* get time */ 723 (void) adrm_int32(&adr, (int32_t *)&secs, 1); 724 (void) adrm_int32(&adr, (int32_t *)&msecs, 1); 725 tv.tv_sec = (time_t)secs; 726 tv.tv_usec = (suseconds_t)msecs; 727 } else if (tokenid == AUT_HEADER64) { 728 int64_t secs, msecs; 729 (void) adrm_int64(&adr, (int64_t *)&secs, 1); 730 (void) adrm_int64(&adr, (int64_t *)&msecs, 1); 731 #if ((!defined(_LP64)) || defined(_SYSCALL32)) 732 if (secs < (time_t)INT32_MIN || 733 secs > (time_t)INT32_MAX) 734 tv.tv_sec = 0; 735 else 736 tv.tv_sec = (time_t)secs; 737 if (msecs < (suseconds_t)INT32_MIN || 738 msecs > (suseconds_t)INT32_MAX) 739 tv.tv_usec = 0; 740 else 741 tv.tv_usec = (suseconds_t)msecs; 742 #else 743 tv.tv_sec = (time_t)secs; 744 tv.tv_usec = (suseconds_t)msecs; 745 #endif 746 } else if (tokenid == AUT_HEADER64_EX) { 747 int64_t secs, msecs; 748 int32_t t, junk[4]; /* at_type + at_addr[4] */ 749 /* skip type and ip address field */ 750 (void) adrm_int32(&adr, (int32_t *)&t, 1); 751 (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); 752 /* get time */ 753 (void) adrm_int64(&adr, (int64_t *)&secs, 1); 754 (void) adrm_int64(&adr, (int64_t *)&msecs, 1); 755 #if ((!defined(_LP64)) || defined(_SYSCALL32)) 756 if (secs < (time_t)INT32_MIN || 757 secs > (time_t)INT32_MAX) 758 tv.tv_sec = 0; 759 else 760 tv.tv_sec = (time_t)secs; 761 if (msecs < (suseconds_t)INT32_MIN || 762 msecs > (suseconds_t)INT32_MAX) 763 tv.tv_usec = 0; 764 else 765 tv.tv_usec = (suseconds_t)msecs; 766 #else 767 tv.tv_sec = (time_t)secs; 768 tv.tv_usec = (suseconds_t)msecs; 769 #endif 770 } 771 pcb->pcb_otime = pcb->pcb_time; 772 if (!f_all) { 773 if (m_after > tv.tv_sec) 774 return (-1); 775 if (m_before <= tv.tv_sec) 776 return (-1); 777 } 778 779 /* if no selection flags were passed, select everything */ 780 if (!flags) 781 return (0); 782 783 /* 784 * If all information can be found in header, 785 * there is no need to continue processing the tokens. 786 */ 787 if (flags == checkflags) 788 return (0); 789 790 /* 791 * Process tokens until we hit the end of the record 792 */ 793 while ((uint_t)(adr.adr_now - adr.adr_stream) < bytes) { 794 adrm_char(&adr, &tokenid, 1); 795 rc = token_processing(&adr, tokenid); 796 797 /* Any Problems? */ 798 if (rc == -2) { 799 (void) fprintf(stderr, 800 gettext("auditreduce: bad token %u, terminating " 801 "file %s\n"), tokenid, (pcb->pcb_cur)->fcb_file); 802 return (-2); 803 } 804 805 /* Are we finished? */ 806 if (flags == checkflags) 807 return (0); 808 } 809 810 /* 811 * So, we haven't seen all that we need to see. Reject record. 812 */ 813 814 return (-1); 815 } 816 817 818 /* 819 * .func check_order - Check temporal sequence. 820 * .call check_order(pcb). 821 * .arg pcb - ptr to audit_pcb_t. 822 * .desc Check to see if the records are out of temporal sequence, ie, 823 * a record has a time stamp older than its predecessor. 824 * Also check to see if the current record is within the bounds of 825 * the file itself. 826 * This routine prints a diagnostic message, unless the QUIET 827 * option was selected. 828 * .call check_order(pcb). 829 * .arg pcb - ptr to pcb holding the records. 830 * .ret void. 831 */ 832 static void 833 check_order(pcb) 834 register audit_pcb_t *pcb; 835 { 836 char cptr1[28], cptr2[28]; /* for error reporting */ 837 838 /* 839 * If the record-past is not the oldest then say so. 840 */ 841 if (pcb->pcb_otime > pcb->pcb_time) { 842 if (!f_quiet) { 843 (void) memcpy((void *)cptr1, 844 (void *)ctime(&pcb->pcb_otime), 26); 845 cptr1[24] = ' '; 846 (void) memcpy((void *)cptr2, 847 (void *)ctime(&pcb->pcb_time), 26); 848 cptr2[24] = ' '; 849 (void) fprintf(stderr, 850 gettext("%s %s had records out of order: %s was followed by %s.\n"), 851 ar, (pcb->pcb_cur)->fcb_file, cptr1, cptr2); 852 } 853 } 854 } 855 856 857 /* 858 * .func check_header. 859 * .desc Read in and check the header for an audit file. 860 * The header must read-in properly and have the magic #. 861 * .call err = check_header(fp). 862 * .arg fp - file stream. 863 * .ret 0 no problems. 864 * .ret -1 problems. 865 */ 866 static int 867 check_header(fp, fn) 868 FILE *fp; 869 char *fn; 870 { 871 char id; 872 char *fname; 873 short pathlength; 874 adr_t adr; 875 adrf_t adrf; 876 877 adrf_start(&adrf, &adr, fp); 878 879 if (adrf_char(&adrf, &id, 1)) { 880 (void) sprintf(errbuf, gettext("%s is empty"), fn); 881 error_str = errbuf; 882 return (-1); 883 } 884 if (!(id == AUT_OTHER_FILE32 || id == AUT_OTHER_FILE64)) { 885 (void) sprintf(errbuf, gettext("%s not an audit file "), fn); 886 error_str = errbuf; 887 return (-1); 888 } 889 890 if (id == AUT_OTHER_FILE32) { 891 int32_t secs, msecs; 892 (void) adrf_int32(&adrf, (int32_t *)&secs, 1); 893 (void) adrf_int32(&adrf, (int32_t *)&msecs, 1); 894 } else { 895 int64_t secs, msecs; 896 (void) adrf_int64(&adrf, (int64_t *)&secs, 1); 897 (void) adrf_int64(&adrf, (int64_t *)&msecs, 1); 898 #if ((!defined(_LP64)) || defined(_SYSCALL32)) 899 if (secs < (time_t)INT32_MIN || 900 secs > (time_t)INT32_MAX) { 901 error_str = gettext("bad time stamp in file header"); 902 return (-1); 903 } 904 if (msecs < (suseconds_t)INT32_MIN || 905 msecs > (suseconds_t)INT32_MAX) { 906 error_str = gettext("bad time stamp in file header"); 907 return (-1); 908 } 909 #endif 910 } 911 912 if (adrf_short(&adrf, &pathlength, 1)) { 913 error_str = gettext("incomplete file header"); 914 return (-1); 915 } 916 917 if (pathlength != 0) { 918 fname = (char *)a_calloc(1, (size_t)pathlength); 919 if ((fread(fname, sizeof (char), pathlength, fp)) != 920 pathlength) { 921 (void) sprintf(errbuf, 922 gettext("error in header/filename read in %s"), 923 fn); 924 error_str = errbuf; 925 return (-1); 926 } 927 free(fname); 928 } 929 return (0); 930 } 931 932 933 /* 934 * .func get_record - get a single record. 935 * .desc Read a single record from stream fp. If the record to be read 936 * is larger than the buffer given to hold it (as determined by 937 * cur_size) then free that buffer and allocate a new and bigger 938 * one, making sure to store its size. 939 * .call ret = get_record(fp, buf, cur_size, flags). 940 * .arg fp - stream to read from. 941 * .arg buf - ptr to ptr to buffer to place record in. 942 * .arg cur_size- ptr to the size of the buffer that *buf points to. 943 * .arg flags - flags from fcb (to get FF_NOTTERM). 944 * .ret +number - number of chars in the record. 945 * .ret 0 - trailer seen - file done. 946 * .ret -1 - read error (error_str know what type). 947 */ 948 static int 949 get_record(fp, buf, fn) 950 FILE *fp; 951 char **buf; 952 char *fn; 953 { 954 adr_t adr; 955 adrf_t adrf; 956 int leadin; 957 char id; 958 int lsize; 959 short ssize; 960 961 /* 962 * Get the token type. It will be either a header or a file 963 * token. 964 */ 965 (void) adrf_start(&adrf, &adr, fp); 966 if (adrf_char(&adrf, &id, 1)) { 967 (void) sprintf(errbuf, gettext( 968 "record expected but not found in %s"), 969 fn); 970 error_str = errbuf; 971 return (-1); 972 } 973 switch (id) { 974 case AUT_HEADER32: 975 case AUT_HEADER32_EX: 976 case AUT_HEADER64: 977 case AUT_HEADER64_EX: 978 /* 979 * The header token is: 980 * attribute id: char 981 * byte count: int 982 * version #: char 983 * event ID: short 984 * ID modifier: short 985 * IP address type int (_EX only) 986 * IP address 1/4*int (_EX only) 987 * seconds (date): long 988 * time (microsecs): long 989 */ 990 leadin = sizeof (int32_t) + sizeof (char); 991 (void) adrf_int32(&adrf, &lsize, 1); 992 *buf = (char *)a_calloc(1, (size_t)(lsize + leadin)); 993 adr_start(&adr, *buf); 994 adr_char(&adr, &id, 1); 995 adr_int32(&adr, (int32_t *)&lsize, 1); 996 if (fread(*buf + leadin, sizeof (char), lsize - leadin, fp) != 997 lsize - leadin) { 998 (void) sprintf(errbuf, 999 gettext("header token read failure in %s"), fn); 1000 error_str = errbuf; 1001 return (-1); 1002 } 1003 return (lsize + leadin); 1004 case AUT_OTHER_FILE32: { 1005 int32_t secs, msecs; 1006 leadin = 2 * sizeof (int32_t) + 1007 sizeof (short) + sizeof (char); 1008 (void) adrf_int32(&adrf, (int32_t *)&secs, 1); 1009 (void) adrf_int32(&adrf, (int32_t *)&msecs, 1); 1010 (void) adrf_short(&adrf, &ssize, 1); 1011 *buf = (char *)a_calloc(1, (size_t)(ssize + leadin)); 1012 adr_start(&adr, *buf); 1013 adr_char(&adr, &id, 1); 1014 adr_int32(&adr, (int32_t *)&secs, 1); 1015 adr_int32(&adr, (int32_t *)&msecs, 1); 1016 adr_short(&adr, &ssize, 1); 1017 if (fread(*buf + leadin, sizeof (char), ssize, fp) != ssize) { 1018 error_str = gettext("file token read failure"); 1019 return (-1); 1020 } 1021 return (0); /* done! */ 1022 } 1023 case AUT_OTHER_FILE64: { 1024 int64_t secs, msecs; 1025 leadin = 2 * sizeof (int64_t) + 1026 sizeof (short) + sizeof (char); 1027 (void) adrf_int64(&adrf, (int64_t *)&secs, 1); 1028 (void) adrf_int64(&adrf, (int64_t *)&msecs, 1); 1029 (void) adrf_short(&adrf, &ssize, 1); 1030 *buf = (char *)a_calloc(1, (size_t)(ssize + leadin)); 1031 adr_start(&adr, *buf); 1032 adr_char(&adr, &id, 1); 1033 adr_int64(&adr, (int64_t *)&secs, 1); 1034 adr_int64(&adr, (int64_t *)&msecs, 1); 1035 adr_short(&adr, &ssize, 1); 1036 if (fread(*buf + leadin, sizeof (char), ssize, fp) != ssize) { 1037 error_str = gettext("file token read failure"); 1038 return (-1); 1039 } 1040 return (0); /* done! */ 1041 } 1042 default: 1043 break; 1044 } 1045 error_str = gettext("record begins without proper token"); 1046 return (-1); 1047 } 1048