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