| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| /* |
| * 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 <bsm/audit.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_USEFILE)) { |
| /* |
| * 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_USEFILE) { |
| 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_USEFILE) { |
| /* 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_USEFILE) |
| (pcb->pcb_cur)->fcb_flags |= FF_DELETE; |
| } |
| if (fclose(pcb->pcb_fpr) == EOF) { |
| if (!f_quiet) { |
| if (pcb->pcb_flags & PF_USEFILE) { |
| 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_USEFILE) { |
| (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; |
| au_emod_t id_modifier; |
| char version; |
| au_event_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); |
| } |