proc.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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 <locale.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
register audit_pcb_t *pcbr;
{
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
#endif
/*
* First load up a record from each input group.
*/
break; /* no files - finished PCB */
if (ret == -2)
return (-1); /* quit processing - failed */
}
}
/*
* Now process all of the records.
*/
return (-1);
break; /* no files - finished pcb */
else if (ret == -2)
return (-1); /* quit - failed */
}
}
}
/*
* For root: write outfile header if no records were encountered.
* For non-root: write trailer to pipe and close pipe.
*/
if (nprecs == 0) {
if (write_header()) /* write header if no records */
return (-1);
}
} else {
return (-1);
if (!f_quiet)
}
}
/*
* For root process tell how many records were written.
*/
gettext("%s %d record(s) total were written out.\n"),
}
return (0);
}
/*
* Head of linked-list of pcbs - sorted by time - oldest first.
*/
/*
* .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
register audit_pcb_t *pcb;
{
return;
}
return;
}
return;
}
}
}
/*
* .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()
{
return (pcbls); /* empty list */
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
register audit_pcb_t *pcb;
{
/*
* Process file list until a good one if found or empty.
*/
return (-1); /* pcb is all done */
} else {
/*
* If we are reading from files then open the next one.
*/
if (!f_stdin) {
if (!f_quiet) {
"%s couldn't open:\n %s"),
}
/*
* See if file space is depleted.
* If it is then we quit.
*/
{
return (-2);
}
continue; /* try another file */
}
} else {
/*
* Read from standard input.
*/
}
/*
* Check header of audit file.
*/
if (!f_quiet) {
"%s %s:\n %s.\n",
}
if (!f_quiet) {
"%s couldn't close %s.\n"),
}
}
continue; /* try another file */
}
/*
* Found a good audit file.
* Initalize pcb for processing.
*/
pcb->pcb_nprecs = 0;
}
}
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
int *nprecs;
{
char id;
/*
* 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 (write_header())
return (-1);
}
}
size) {
"%s write failed to %s"),
} else {
}
return (-1);
}
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
register audit_pcb_t *pcb;
int *nr;
{
int tmp;
int nrecs = 0; /* count how many records read this call */
char header_type;
short e;
char *str;
#if AUDIT_FILE
static void get_trace();
#endif
while (getrec) {
if (ret > 0) {
/* get token id */
/* skip over byte count */
/* skip over version # */
/* skip over event id */
/* skip over event id modifier */
if (header_type == AUT_HEADER32) {
int32_t s, m;
/* get seconds */
/* get microseconds */
} else if (header_type == AUT_HEADER32_EX) {
int32_t s, m;
/* skip type and ip address field */
/* get seconds */
/* get microseconds */
} else if (header_type == AUT_HEADER64) {
int64_t s, m;
/* get seconds */
/* get microseconds */
#if ((!defined(_LP64)) || defined(_SYSCALL32))
secs = 0;
else
#else
#endif
} else if (header_type == AUT_HEADER64_EX) {
int64_t s, m;
/* skip type and ip address field */
/* get seconds */
/* get microseconds */
#if ((!defined(_LP64)) || defined(_SYSCALL32))
secs = 0;
else
#else
#endif
}
}
#if AUDIT_REC
#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 the first record read failed then use the time
* that was in the filename to judge.
*/
if (ret > 0)
return (-1);
} else {
/* Give belated announcement of file opening. */
if (f_verbose) {
gettext("%s opened:\n %s.\n"),
}
}
}
/* Succesful acquisition of a record. */
if (ret > 0) {
nrecs++; /* # of recs read this call */
/* Only check record if at bottom of process tree. */
pcb->pcb_nprecs++;
} else if (ret2 == -2) {
/* error */
} else {
/* -1: record not interesting */
}
} else {
pcb->pcb_nprecs++;
}
} else {
/* Error with record read or all done with stream. */
}
}
#if AUDIT_FILE
#endif
/* Error in record read. Display messages. */
if (!f_quiet) {
/* Ignore if this is not_terminated. */
"not_terminated")) {
}
} else {
}
}
} else {
/*
* Only mark infile for deleting if we have succesfully
* processed all of it.
*/
}
if (!f_quiet) {
} else {
str = "pipe";
}
gettext("%s couldn't close %s.\n"),
}
}
return (-1);
}
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).
* .ret void.
*/
static void
{
/*
* For file give filename, too.
*/
} else {
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
register audit_pcb_t *pcb;
{
char version;
char tokenid;
int rc; /* return code */
/*
* 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 AUDIT_REC
"check_rec: %d recno %d no header %d found\n",
#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
*/
/*
* Used by s5_IPC_token to set the ipc_type so
* s5_IPC_perm_token can test.
*/
ipc_type = (char)0;
checkflags |= M_TYPE;
if (m_type != event_type)
return (-1);
}
checkflags |= M_CLASS;
"Warning: invalid event no %d in audit trail."),
return (-1);
}
return (-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) {
} else if (tokenid == AUT_HEADER32_EX) {
/* skip type and ip address field */
/* get time */
} else if (tokenid == AUT_HEADER64) {
#if ((!defined(_LP64)) || defined(_SYSCALL32))
else
else
#else
#endif
} else if (tokenid == AUT_HEADER64_EX) {
/* skip type and ip address field */
/* get time */
#if ((!defined(_LP64)) || defined(_SYSCALL32))
else
else
#else
#endif
}
if (!f_all) {
return (-1);
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
*/
/* Any Problems? */
if (rc == -2) {
gettext("auditreduce: bad token %u, terminating "
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
register audit_pcb_t *pcb;
{
/*
* If the record-past is not the oldest then say so.
*/
if (!f_quiet) {
gettext("%s %s had records out of order: %s was followed by %s.\n"),
}
}
}
/*
* .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
char *fn;
{
char id;
char *fname;
short pathlength;
return (-1);
}
return (-1);
}
if (id == AUT_OTHER_FILE32) {
} else {
#if ((!defined(_LP64)) || defined(_SYSCALL32))
return (-1);
}
return (-1);
}
#endif
}
return (-1);
}
if (pathlength != 0) {
pathlength) {
fn);
return (-1);
}
}
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
char **buf;
char *fn;
{
int leadin;
char id;
int lsize;
short ssize;
/*
* Get the token type. It will be either a header or a file
* token.
*/
"record expected but not found in %s"),
fn);
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
*/
return (-1);
}
case AUT_OTHER_FILE32: {
sizeof (short) + sizeof (char);
return (-1);
}
return (0); /* done! */
}
case AUT_OTHER_FILE64: {
sizeof (short) + sizeof (char);
return (-1);
}
return (0); /* done! */
}
default:
break;
}
return (-1);
}