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