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