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 }