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