diff options
Diffstat (limited to 'usr/src/cmd/auditreduce/proc.c')
| -rw-r--r-- | usr/src/cmd/auditreduce/proc.c | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/usr/src/cmd/auditreduce/proc.c b/usr/src/cmd/auditreduce/proc.c new file mode 100644 index 0000000000..5e235675a9 --- /dev/null +++ b/usr/src/cmd/auditreduce/proc.c @@ -0,0 +1,1050 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Main processor for auditreduce. + * Mproc() is the entry point for this module. It is the only visible + * function in this module. + */ + +#include <sys/types.h> +#include <locale.h> +#include <bsm/libbsm.h> +#include "auditr.h" + +extern int write_header(); +extern int token_processing(); + +static void asort(); +static audit_pcb_t *aget(); +static int get_file(); +static int write_recs(); +static int get_recs(); +static int check_rec(); +static void check_order(); +static int check_header(); +static int get_record(); + +static char empty_file_token[] = { +#ifdef _LP64 + AUT_OTHER_FILE64, /* token id */ + 0, 0, 0, 0, 0, 0, 0, 0, /* seconds of time */ + 0, 0, 0, 0, 0, 0, 0, 0, /* microseconds of time */ +#else + AUT_OTHER_FILE32, /* token id */ + 0, 0, 0, 0, /* seconds of time */ + 0, 0, 0, 0, /* microseconds of time */ +#endif + 0, 0, /* length of path name */ +}; + + +/* + * .func mproc - main processor. + * .desc Mproc controls a single process's actions. + * First one record is retreived from each pcb. As they are retreived + * they are placed into a linked list sorted with oldest first. Then + * the first one from the list is written out and another record + * read in to replace it. The new record is placed into the list. + * This continues until the list is empty. + * .call ret = mproc(pcbr). + * .arg pcbr - ptr to pcb for this process. + * .ret 0 - no errors in processing. + * .ret -1 - errors in processing (message already printed). + */ +int +mproc(pcbr) +register audit_pcb_t *pcbr; +{ + int i, ret, junk; + int nrecs = 0; /* number of records read from stream */ + int nprecs = 0; /* number of records put to stream */ + register audit_pcb_t *pcb; + audit_pcb_t *aget(); + void asort(); + +#if AUDIT_PROC_TRACE + (void) fprintf(stderr, "mproc: count %d lo %d hi %d\n", + pcbr->pcb_count, pcbr->pcb_lo, pcbr->pcb_hi); +#endif + + /* + * First load up a record from each input group. + */ + for (i = pcbr->pcb_lo; i <= pcbr->pcb_hi; i++) { + pcb = &(pcbr->pcb_below[i]); /* get next PCB */ + while (pcb->pcb_time < 0) { /* while no active record ... */ + if ((ret = get_file(pcb)) == -1) + break; /* no files - finished PCB */ + if (ret == -2) + return (-1); /* quit processing - failed */ + if (get_recs(pcb, &nrecs) == 0) + asort(pcb); /* got a rec - put in list */ + } + } + /* + * Now process all of the records. + */ + while ((pcb = aget()) != NULL) { /* get oldest record */ + if (write_recs(pcbr, pcb, &nprecs)) + return (-1); + while (pcb->pcb_time < 0) { /* while we don't have a rec */ + if (pcb->pcb_fpr == NULL) { /* no active file ... */ + if ((ret = get_file(pcb)) == -1) + break; /* no files - finished pcb */ + else if (ret == -2) + return (-1); /* quit - failed */ + } + if (get_recs(pcb, &nrecs) == 0) + asort(pcb); /* put record in list */ + } + } + /* + * For root: write outfile header if no records were encountered. + * For non-root: write trailer to pipe and close pipe. + */ + if (pcbr->pcb_flags & PF_ROOT) { + if (nprecs == 0) { + if (write_header()) /* write header if no records */ + return (-1); + } + } else { + pcb = &(pcbr->pcb_below[0]); /* any old PCB will do */ + pcb->pcb_rec = empty_file_token; + if (write_recs(pcbr, pcb, &junk)) + return (-1); + if (fclose(pcbr->pcb_fpw) == EOF) { + if (!f_quiet) + (void) fprintf(stderr, + gettext("%s couldn't close pipe.\n"), ar); + } + } + /* + * For root process tell how many records were written. + */ + if (f_verbose && (pcbr->pcb_flags & PF_ROOT)) { + (void) fprintf(stderr, + gettext("%s %d record(s) total were written out.\n"), + ar, nprecs); + } + return (0); +} + + +/* + * Head of linked-list of pcbs - sorted by time - oldest first. + */ +static audit_pcb_t *pcbls = NULL; + +/* + * .func asort - audit sort. + * .desc Place a pcb in the list sorted by time - oldest first. + * .call asort(pcb); + * .arg pcb - ptr to pcb to install in list. + * .ret void. + */ +static void +asort(pcb) +register audit_pcb_t *pcb; +{ + register audit_pcb_t *pcbc, *pcbp; + extern audit_pcb_t *pcbls; /* ptr to start of list */ + + pcb->pcb_next = NULL; + if (pcbls == NULL) { + pcbls = pcb; /* empty list */ + return; + } + pcbc = pcbls; /* current pcb */ + pcbp = pcbls; /* previous pcb */ + while (pcbc != NULL) { + if (pcb->pcb_time < pcbc->pcb_time) { + if (pcbp == pcbc) { + pcb->pcb_next = pcbls; /* new -> 1st in list */ + pcbls = pcb; + return; + } + pcbp->pcb_next = pcb; + pcb->pcb_next = pcbc; /* new in the inside */ + return; + } + pcbp = pcbc; + pcbc = pcbc->pcb_next; + } + pcbp->pcb_next = pcb; /* new -> last */ +} + + +/* + * .func aget - audit get. + * .desc Get the first pcb from the list. Pcb is removed from list, too. + * .call pcb = aget(). + * .arg none. + * .ret pcb - ptr to pcb that was the first. + */ +static audit_pcb_t * +aget() +{ + audit_pcb_t *pcbret; + extern audit_pcb_t *pcbls; /* ptr to start of list */ + + if (pcbls == NULL) + return (pcbls); /* empty list */ + pcbret = pcbls; + pcbls = pcbls->pcb_next; /* 2nd becomes 1st */ + return (pcbret); +} + + +/* + * .func get_file - get a new file. + * .desc Get the next file from the pcb's list. Check the header to see + * if the file really is an audit file. If there are no more then + * quit. If a file open (fopen) fails because the system file table + * is full or the process file table is full then quit processing + * altogether. + * .call ret = get_file(pcb). + * .arg pcb - pcb holding the fcb's (files). + * .ret 0 - new file opened for processing. + * .ret -1 - no more files - pcb finished. + * .ret -2 - fatal error - quit processing. + */ +static int +get_file(pcb) +register audit_pcb_t *pcb; +{ + FILE *fp; + audit_fcb_t *fcb; + + /* + * Process file list until a good one if found or empty. + */ + while (pcb->pcb_fpr == NULL) { + if ((fcb = pcb->pcb_first) == NULL) { + pcb->pcb_time = -1; + return (-1); /* pcb is all done */ + } else { + /* + * If we are reading from files then open the next one. + */ + if (!f_stdin) { + if ((fp = fopen(fcb->fcb_file, "r")) == NULL) { + if (!f_quiet) { + (void) sprintf(errbuf, gettext( + "%s couldn't open:\n %s"), + ar, fcb->fcb_file); + perror(errbuf); + } + /* + * See if file space is depleted. + * If it is then we quit. + */ + if (errno == ENFILE || errno == EMFILE) + { + return (-2); + } + pcb->pcb_first = fcb->fcb_next; + continue; /* try another file */ + } + } else { + /* + * Read from standard input. + */ + fp = stdin; + } + /* + * Check header of audit file. + */ + if (check_header(fp, fcb->fcb_name)) { + if (!f_quiet) { + (void) fprintf(stderr, + "%s %s:\n %s.\n", + ar, error_str, fcb->fcb_file); + } + if (fclose(fp) == EOF) { + if (!f_quiet) { + (void) fprintf(stderr, gettext( + "%s couldn't close %s.\n"), + ar, fcb->fcb_file); + } + } + pcb->pcb_first = fcb->fcb_next; + continue; /* try another file */ + } + /* + * Found a good audit file. + * Initalize pcb for processing. + */ + pcb->pcb_first = fcb->fcb_next; + pcb->pcb_cur = fcb; + pcb->pcb_fpr = fp; + pcb->pcb_nrecs = 0; + pcb->pcb_nprecs = 0; + pcb->pcb_otime = -1; + } + } + return (0); +} + + +/* + * .func write_recs - write records. + * .desc Write record from a buffer to output stream. Keep an eye out + * for the first and last records of the root's output stream. + * .call ret = write_recs(pcbr, pcb, nprecs). + * .arg pcbr - ptr to node pcb. + * .arg pcb - ptr to pcb holding the stream. + * .arg nprecs - ptr to the number of put records. Updated here. + * .ret 0 - no errors detected. + * .ret -1 - error in writing. Quit processing. + */ +static int +write_recs(pcbr, pcb, nprecs) +register audit_pcb_t *pcbr, *pcb; +int *nprecs; +{ + adr_t adr; + char id; + int32_t size; + + adrm_start(&adr, pcb->pcb_rec); + (void) adrm_char(&adr, &id, 1); + (void) adrm_int32(&adr, &size, 1); + + /* + * Scan for first record to be written to outfile. + * When we find it then write the header and + * save the time for the outfile name. + */ + if ((*nprecs)++ == 0) { + if (pcbr->pcb_flags & PF_ROOT) { + f_start = pcb->pcb_time; /* save start time */ + if (write_header()) + return (-1); + } + } + f_end = pcb->pcb_time; /* find last record's time */ + pcb->pcb_time = -1; /* disable just written rec */ + + if ((fwrite(pcb->pcb_rec, sizeof (char), size, pcbr->pcb_fpw)) != + size) { + if (pcbr->pcb_flags & PF_ROOT) { + (void) sprintf(errbuf, gettext( + "%s write failed to %s"), + ar, f_outfile ? f_outfile : gettext("stdout")); + perror(errbuf); + } else { + perror(gettext("auditreduce: write failed to pipe")); + } + return (-1); + } + free(pcb->pcb_rec); + return (0); +} + +/* + * .func get_recs - get records. + * .desc Get records from a stream until one passing the current selection + * criteria is found or the stream is emptied. + * .call ret = get_recs(pcb, nr). + * .arg pcb - ptr to pcb that holds this stream. + * .arg nr - ptr to number of records read. Updated by this routine. + * .ret 0 - got a record. + * .ret -1 - stream is finished. + */ +static int +get_recs(pcb, nr) +register audit_pcb_t *pcb; +int *nr; +{ + adr_t adr; + time_t secs; + int tmp; + int ret, ret2; + int nrecs = 0; /* count how many records read this call */ + int getrec = TRUE; + int alldone = FALSE; + char header_type; + short e; + char *str; +#if AUDIT_FILE + static void get_trace(); +#endif + + while (getrec) { + ret = get_record(pcb->pcb_fpr, &pcb->pcb_rec, + pcb->pcb_cur->fcb_name); + if (ret > 0) { + adrm_start(&adr, pcb->pcb_rec); + + /* get token id */ + (void) adrm_char(&adr, (char *)&header_type, 1); + /* skip over byte count */ + (void) adrm_int32(&adr, (int32_t *)&tmp, 1); + /* skip over version # */ + (void) adrm_char(&adr, (char *)&tmp, 1); + /* skip over event id */ + (void) adrm_short(&adr, (short *)&e, 1); + /* skip over event id modifier */ + (void) adrm_short(&adr, (short *)&tmp, 1); + + if (header_type == AUT_HEADER32) { + int32_t s, m; + + /* get seconds */ + (void) adrm_int32(&adr, (int32_t *)&s, 1); + /* get microseconds */ + (void) adrm_int32(&adr, (int32_t *)&m, 1); + secs = (time_t)s; + } else if (header_type == AUT_HEADER32_EX) { + int32_t s, m; + int32_t t, junk[4]; /* at_type + at_addr[4] */ + + /* skip type and ip address field */ + (void) adrm_int32(&adr, (int32_t *)&t, 1); + (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); + + /* get seconds */ + (void) adrm_int32(&adr, (int32_t *)&s, 1); + /* get microseconds */ + (void) adrm_int32(&adr, (int32_t *)&m, 1); + secs = (time_t)s; + } else if (header_type == AUT_HEADER64) { + int64_t s, m; + + /* get seconds */ + (void) adrm_int64(&adr, (int64_t *)&s, 1); + /* get microseconds */ + (void) adrm_int64(&adr, (int64_t *)&m, 1); +#if ((!defined(_LP64)) || defined(_SYSCALL32)) + if (s < (time_t)INT32_MIN || + s > (time_t)INT32_MAX) + secs = 0; + else + secs = (time_t)s; +#else + secs = (time_t)s; +#endif + } else if (header_type == AUT_HEADER64_EX) { + int64_t s, m; + int32_t t, junk[4]; + + /* skip type and ip address field */ + (void) adrm_int32(&adr, (int32_t *)&t, 1); + (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); + + /* get seconds */ + (void) adrm_int64(&adr, (int64_t *)&s, 1); + /* get microseconds */ + (void) adrm_int64(&adr, (int64_t *)&m, 1); +#if ((!defined(_LP64)) || defined(_SYSCALL32)) + if (s < (time_t)INT32_MIN || + s > (time_t)INT32_MAX) + secs = 0; + else + secs = (time_t)s; +#else + secs = (time_t)s; +#endif + } + } + +#if AUDIT_REC + (void) fprintf(stderr, "get_recs: %d ret %d recno %d\n", + pcb->pcb_procno, ret, pcb->pcb_nrecs + 1); +#endif + /* + * See if entire file is after the time window specified. + * Must be check here because the start time of the file name + * may be after the first record(s). + */ + if (pcb->pcb_nrecs == 0 && (pcb->pcb_flags & PF_FILE)) { + /* + * If the first record read failed then use the time + * that was in the filename to judge. + */ + if (ret > 0) + (pcb->pcb_cur)->fcb_start = secs; + if (!f_all && (m_before <= (pcb->pcb_cur)->fcb_start)) { + (void) fclose(pcb->pcb_fpr); /* ignore file */ + pcb->pcb_fpr = NULL; + pcb->pcb_time = -1; + return (-1); + } else { + /* Give belated announcement of file opening. */ + if (f_verbose) { + (void) fprintf(stderr, + gettext("%s opened:\n %s.\n"), + ar, (pcb->pcb_cur)->fcb_file); + } + } + } + /* Succesful acquisition of a record. */ + if (ret > 0) { + pcb->pcb_time = secs; /* time of record */ + pcb->pcb_nrecs++; /* # of read recs from stream */ + nrecs++; /* # of recs read this call */ + /* Only check record if at bottom of process tree. */ + if (pcb->pcb_flags & PF_FILE) { + check_order(pcb); /* check time sequence */ + if ((ret2 = check_rec(pcb)) == 0) { + pcb->pcb_nprecs++; + getrec = FALSE; + } else if (ret2 == -2) { + /* error */ + getrec = FALSE; /* get no more recs */ + alldone = TRUE; /* quit this file */ + free(pcb->pcb_rec); + } else { + /* -1: record not interesting */ + free(pcb->pcb_rec); + } + } else { + pcb->pcb_nprecs++; + getrec = FALSE; + } + } else { + /* Error with record read or all done with stream. */ + getrec = FALSE; + alldone = TRUE; + } + } + if (alldone == TRUE) { +#if AUDIT_FILE + get_trace(pcb); +#endif + /* Error in record read. Display messages. */ + if (ret < 0 || ret2 == -2) { + pcb->pcb_nrecs++; /* # of read records */ + if (!f_quiet) { + if (pcb->pcb_flags & PF_FILE) { + /* Ignore if this is not_terminated. */ + if (!strstr((pcb->pcb_cur)->fcb_file, + "not_terminated")) { +(void) fprintf(stderr, gettext("%s read error in %s at record %d.\n"), ar, + (pcb->pcb_cur)->fcb_file, pcb->pcb_nrecs); + } + } else { +(void) fprintf(stderr, gettext("%s read error in pipe at record %d.\n"), ar, + pcb->pcb_nrecs); + } + } + } else { + /* + * Only mark infile for deleting if we have succesfully + * processed all of it. + */ + if (pcb->pcb_flags & PF_FILE) + (pcb->pcb_cur)->fcb_flags |= FF_DELETE; + } + if (fclose(pcb->pcb_fpr) == EOF) { + if (!f_quiet) { + if (pcb->pcb_flags & PF_FILE) { + str = (pcb->pcb_cur)->fcb_file; + } else { + str = "pipe"; + } + (void) fprintf(stderr, + gettext("%s couldn't close %s.\n"), + ar, str); + } + } + pcb->pcb_fpr = NULL; + pcb->pcb_time = -1; + *nr += nrecs; + return (-1); + } + *nr += nrecs; + return (0); +} + + +#if AUDIT_FILE +/* + * .func get_trace - get trace. + * .desc If we are tracing file action (AUDIT_FILE is on) then print out + * a message when the file is closed regarding how many records + * were handled. + * .call get_trace(pcb). + * .arg pcb - ptr to pcb holding file/pipe. + * .ret void. + */ +static void +get_trace(pcb) +audit_pcb_t *pcb; +{ + /* + * For file give filename, too. + */ + if (pcb->pcb_flags & PF_FILE) { + (void) fprintf(stderr, "%s closed %s: %d records read recs: \ + %d record written.\n", ar, (pcb->pcb_cur)->fcb_file, + pcb->pcb_nrecs, pcb->pcb_nprecs); + } else { + (void) fprintf(stderr, "%s closed pipe: %d records read: \ + %d records written .\n", ar, pcb->pcb_nrecs, + pcb->pcb_nprecs); + } +} + +#endif + +/* + * .func check_rec - check a record. + * .desc Check a record against the user's selection criteria. + * .call ret = check_rec(pcb). + * .arg pcb - ptr to pcb holding the record. + * .ret 0 - record accepted. + * .ret -1 - record rejected - continue processing file. + * .ret -2 - record rejected - quit processing file. + */ +static int +check_rec(pcb) +register audit_pcb_t *pcb; +{ + adr_t adr; + struct timeval tv; + uint_t bytes; + ushort_t id_modifier; + char version; + ushort_t event_type; + char tokenid; + int rc; /* return code */ + + adrm_start(&adr, pcb->pcb_rec); + (void) adrm_char(&adr, &tokenid, 1); + + /* + * checkflags will be my data structure for determining if + * a record has met ALL the selection criteria. Once + * checkflags == flags, we have seen all we need to of the + * record, and can go to the next one. If when we finish + * processing the record we still have stuff to see, + * checkflags != flags, and thus we should return a -1 + * from this function meaning reject this record. + */ + + checkflags = 0; + + /* must be header token -- sanity check */ + if (tokenid != AUT_HEADER32 && tokenid != AUT_HEADER64 && + tokenid != AUT_HEADER32_EX && tokenid != AUT_HEADER64_EX) { +#if AUDIT_REC + (void) fprintf(stderr, + "check_rec: %d recno %d no header %d found\n", + pcb->pcb_procno, pcb->pcb_nrecs, tokenid); +#endif + return (-2); + } + + /* + * The header token is: + * attribute id: char + * byte count: int + * version #: char + * event ID: short + * ID modifier: short + * seconds (date): int + * time (microsecs): int + */ + (void) adrm_u_int32(&adr, (uint32_t *)&bytes, 1); + (void) adrm_char(&adr, &version, 1); + (void) adrm_u_short(&adr, &event_type, 1); + + /* + * Used by s5_IPC_token to set the ipc_type so + * s5_IPC_perm_token can test. + */ + ipc_type = (char)0; + + if (flags & M_TYPE) { + checkflags |= M_TYPE; + if (m_type != event_type) + return (-1); + } + if (flags & M_CLASS) { + au_event_ent_t *ev = NULL; + + checkflags |= M_CLASS; + if (cacheauevent(&ev, event_type) <= 0) { + (void) fprintf(stderr, gettext( + "Warning: invalid event no %d in audit trail."), + event_type); + return (-1); + } + global_class = ev->ae_class; + if (!(flags & M_SORF) && !(mask.am_success & global_class)) + return (-1); + } + + (void) adrm_u_short(&adr, &id_modifier, 1); + + /* + * Check record against time criteria. + * If the 'A' option was used then no time checking is done. + * The 'a' parameter is inclusive and the 'b' exclusive. + */ + if (tokenid == AUT_HEADER32) { + int32_t secs, msecs; + (void) adrm_int32(&adr, (int32_t *)&secs, 1); + (void) adrm_int32(&adr, (int32_t *)&msecs, 1); + tv.tv_sec = (time_t)secs; + tv.tv_usec = (suseconds_t)msecs; + } else if (tokenid == AUT_HEADER32_EX) { + int32_t secs, msecs; + int32_t t, junk[5]; /* at_type + at_addr[4] */ + /* skip type and ip address field */ + (void) adrm_int32(&adr, (int32_t *)&t, 1); + (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); + /* get time */ + (void) adrm_int32(&adr, (int32_t *)&secs, 1); + (void) adrm_int32(&adr, (int32_t *)&msecs, 1); + tv.tv_sec = (time_t)secs; + tv.tv_usec = (suseconds_t)msecs; + } else if (tokenid == AUT_HEADER64) { + int64_t secs, msecs; + (void) adrm_int64(&adr, (int64_t *)&secs, 1); + (void) adrm_int64(&adr, (int64_t *)&msecs, 1); +#if ((!defined(_LP64)) || defined(_SYSCALL32)) + if (secs < (time_t)INT32_MIN || + secs > (time_t)INT32_MAX) + tv.tv_sec = 0; + else + tv.tv_sec = (time_t)secs; + if (msecs < (suseconds_t)INT32_MIN || + msecs > (suseconds_t)INT32_MAX) + tv.tv_usec = 0; + else + tv.tv_usec = (suseconds_t)msecs; +#else + tv.tv_sec = (time_t)secs; + tv.tv_usec = (suseconds_t)msecs; +#endif + } else if (tokenid == AUT_HEADER64_EX) { + int64_t secs, msecs; + int32_t t, junk[4]; /* at_type + at_addr[4] */ + /* skip type and ip address field */ + (void) adrm_int32(&adr, (int32_t *)&t, 1); + (void) adrm_int32(&adr, (int32_t *)&junk[0], t/4); + /* get time */ + (void) adrm_int64(&adr, (int64_t *)&secs, 1); + (void) adrm_int64(&adr, (int64_t *)&msecs, 1); +#if ((!defined(_LP64)) || defined(_SYSCALL32)) + if (secs < (time_t)INT32_MIN || + secs > (time_t)INT32_MAX) + tv.tv_sec = 0; + else + tv.tv_sec = (time_t)secs; + if (msecs < (suseconds_t)INT32_MIN || + msecs > (suseconds_t)INT32_MAX) + tv.tv_usec = 0; + else + tv.tv_usec = (suseconds_t)msecs; +#else + tv.tv_sec = (time_t)secs; + tv.tv_usec = (suseconds_t)msecs; +#endif + } + pcb->pcb_otime = pcb->pcb_time; + if (!f_all) { + if (m_after > tv.tv_sec) + return (-1); + if (m_before <= tv.tv_sec) + return (-1); + } + + /* if no selection flags were passed, select everything */ + if (!flags) + return (0); + + /* + * If all information can be found in header, + * there is no need to continue processing the tokens. + */ + if (flags == checkflags) + return (0); + + /* + * Process tokens until we hit the end of the record + */ + while ((uint_t)(adr.adr_now - adr.adr_stream) < bytes) { + adrm_char(&adr, &tokenid, 1); + rc = token_processing(&adr, tokenid); + + /* Any Problems? */ + if (rc == -2) { + (void) fprintf(stderr, + gettext("auditreduce: bad token %u, terminating " + "file %s\n"), tokenid, (pcb->pcb_cur)->fcb_file); + return (-2); + } + + /* Are we finished? */ + if (flags == checkflags) + return (0); + } + + /* + * So, we haven't seen all that we need to see. Reject record. + */ + + return (-1); +} + + +/* + * .func check_order - Check temporal sequence. + * .call check_order(pcb). + * .arg pcb - ptr to audit_pcb_t. + * .desc Check to see if the records are out of temporal sequence, ie, + * a record has a time stamp older than its predecessor. + * Also check to see if the current record is within the bounds of + * the file itself. + * This routine prints a diagnostic message, unless the QUIET + * option was selected. + * .call check_order(pcb). + * .arg pcb - ptr to pcb holding the records. + * .ret void. + */ +static void +check_order(pcb) +register audit_pcb_t *pcb; +{ + char cptr1[28], cptr2[28]; /* for error reporting */ + + /* + * If the record-past is not the oldest then say so. + */ + if (pcb->pcb_otime > pcb->pcb_time) { + if (!f_quiet) { + (void) memcpy((void *)cptr1, + (void *)ctime(&pcb->pcb_otime), 26); + cptr1[24] = ' '; + (void) memcpy((void *)cptr2, + (void *)ctime(&pcb->pcb_time), 26); + cptr2[24] = ' '; + (void) fprintf(stderr, + gettext("%s %s had records out of order: %s was followed by %s.\n"), + ar, (pcb->pcb_cur)->fcb_file, cptr1, cptr2); + } + } +} + + +/* + * .func check_header. + * .desc Read in and check the header for an audit file. + * The header must read-in properly and have the magic #. + * .call err = check_header(fp). + * .arg fp - file stream. + * .ret 0 no problems. + * .ret -1 problems. + */ +static int +check_header(fp, fn) +FILE *fp; +char *fn; +{ + char id; + char *fname; + short pathlength; + adr_t adr; + adrf_t adrf; + + adrf_start(&adrf, &adr, fp); + + if (adrf_char(&adrf, &id, 1)) { + (void) sprintf(errbuf, gettext("%s is empty"), fn); + error_str = errbuf; + return (-1); + } + if (!(id == AUT_OTHER_FILE32 || id == AUT_OTHER_FILE64)) { + (void) sprintf(errbuf, gettext("%s not an audit file "), fn); + error_str = errbuf; + return (-1); + } + + if (id == AUT_OTHER_FILE32) { + int32_t secs, msecs; + (void) adrf_int32(&adrf, (int32_t *)&secs, 1); + (void) adrf_int32(&adrf, (int32_t *)&msecs, 1); + } else { + int64_t secs, msecs; + (void) adrf_int64(&adrf, (int64_t *)&secs, 1); + (void) adrf_int64(&adrf, (int64_t *)&msecs, 1); +#if ((!defined(_LP64)) || defined(_SYSCALL32)) + if (secs < (time_t)INT32_MIN || + secs > (time_t)INT32_MAX) { + error_str = gettext("bad time stamp in file header"); + return (-1); + } + if (msecs < (suseconds_t)INT32_MIN || + msecs > (suseconds_t)INT32_MAX) { + error_str = gettext("bad time stamp in file header"); + return (-1); + } +#endif + } + + if (adrf_short(&adrf, &pathlength, 1)) { + error_str = gettext("incomplete file header"); + return (-1); + } + + if (pathlength != 0) { + fname = (char *)a_calloc(1, (size_t)pathlength); + if ((fread(fname, sizeof (char), pathlength, fp)) != + pathlength) { + (void) sprintf(errbuf, + gettext("error in header/filename read in %s"), + fn); + error_str = errbuf; + return (-1); + } + free(fname); + } + return (0); +} + + +/* + * .func get_record - get a single record. + * .desc Read a single record from stream fp. If the record to be read + * is larger than the buffer given to hold it (as determined by + * cur_size) then free that buffer and allocate a new and bigger + * one, making sure to store its size. + * .call ret = get_record(fp, buf, cur_size, flags). + * .arg fp - stream to read from. + * .arg buf - ptr to ptr to buffer to place record in. + * .arg cur_size- ptr to the size of the buffer that *buf points to. + * .arg flags - flags from fcb (to get FF_NOTTERM). + * .ret +number - number of chars in the record. + * .ret 0 - trailer seen - file done. + * .ret -1 - read error (error_str know what type). + */ +static int +get_record(fp, buf, fn) +FILE *fp; +char **buf; +char *fn; +{ + adr_t adr; + adrf_t adrf; + int leadin; + char id; + int lsize; + short ssize; + + /* + * Get the token type. It will be either a header or a file + * token. + */ + (void) adrf_start(&adrf, &adr, fp); + if (adrf_char(&adrf, &id, 1)) { + (void) sprintf(errbuf, gettext( + "record expected but not found in %s"), + fn); + error_str = errbuf; + return (-1); + } + switch (id) { + case AUT_HEADER32: + case AUT_HEADER32_EX: + case AUT_HEADER64: + case AUT_HEADER64_EX: + /* + * The header token is: + * attribute id: char + * byte count: int + * version #: char + * event ID: short + * ID modifier: short + * IP address type int (_EX only) + * IP address 1/4*int (_EX only) + * seconds (date): long + * time (microsecs): long + */ + leadin = sizeof (int32_t) + sizeof (char); + (void) adrf_int32(&adrf, &lsize, 1); + *buf = (char *)a_calloc(1, (size_t)(lsize + leadin)); + adr_start(&adr, *buf); + adr_char(&adr, &id, 1); + adr_int32(&adr, (int32_t *)&lsize, 1); + if (fread(*buf + leadin, sizeof (char), lsize - leadin, fp) != + lsize - leadin) { + (void) sprintf(errbuf, + gettext("header token read failure in %s"), fn); + error_str = errbuf; + return (-1); + } + return (lsize + leadin); + case AUT_OTHER_FILE32: { + int32_t secs, msecs; + leadin = 2 * sizeof (int32_t) + + sizeof (short) + sizeof (char); + (void) adrf_int32(&adrf, (int32_t *)&secs, 1); + (void) adrf_int32(&adrf, (int32_t *)&msecs, 1); + (void) adrf_short(&adrf, &ssize, 1); + *buf = (char *)a_calloc(1, (size_t)(ssize + leadin)); + adr_start(&adr, *buf); + adr_char(&adr, &id, 1); + adr_int32(&adr, (int32_t *)&secs, 1); + adr_int32(&adr, (int32_t *)&msecs, 1); + adr_short(&adr, &ssize, 1); + if (fread(*buf + leadin, sizeof (char), ssize, fp) != ssize) { + error_str = gettext("file token read failure"); + return (-1); + } + return (0); /* done! */ + } + case AUT_OTHER_FILE64: { + int64_t secs, msecs; + leadin = 2 * sizeof (int64_t) + + sizeof (short) + sizeof (char); + (void) adrf_int64(&adrf, (int64_t *)&secs, 1); + (void) adrf_int64(&adrf, (int64_t *)&msecs, 1); + (void) adrf_short(&adrf, &ssize, 1); + *buf = (char *)a_calloc(1, (size_t)(ssize + leadin)); + adr_start(&adr, *buf); + adr_char(&adr, &id, 1); + adr_int64(&adr, (int64_t *)&secs, 1); + adr_int64(&adr, (int64_t *)&msecs, 1); + adr_short(&adr, &ssize, 1); + if (fread(*buf + leadin, sizeof (char), ssize, fp) != ssize) { + error_str = gettext("file token read failure"); + return (-1); + } + return (0); /* done! */ + } + default: + break; + } + error_str = gettext("record begins without proper token"); + return (-1); +} |
