xref: /titanic_52/usr/src/cmd/auditreduce/proc.c (revision c2580b931007758eab8cb5ae8726ebe1588e259b)
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