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