/* * 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 #include #include #include #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); }