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