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