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