#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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
#else
AUT_OTHER_FILE32,
0, 0, 0, 0,
0, 0, 0, 0,
#endif
0, 0,
};
int
mproc(pcbr)
register audit_pcb_t *pcbr;
{
int i, ret, junk;
int nrecs = 0;
int nprecs = 0;
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
for (i = pcbr->pcb_lo; i <= pcbr->pcb_hi; i++) {
pcb = &(pcbr->pcb_below[i]);
while (pcb->pcb_time < 0) {
if ((ret = get_file(pcb)) == -1)
break;
if (ret == -2)
return (-1);
if (get_recs(pcb, &nrecs) == 0)
asort(pcb);
}
}
while ((pcb = aget()) != NULL) {
if (write_recs(pcbr, pcb, &nprecs))
return (-1);
while (pcb->pcb_time < 0) {
if (pcb->pcb_fpr == NULL) {
if ((ret = get_file(pcb)) == -1)
break;
else if (ret == -2)
return (-1);
}
if (get_recs(pcb, &nrecs) == 0)
asort(pcb);
}
}
if (pcbr->pcb_flags & PF_ROOT) {
if (nprecs == 0) {
if (write_header())
return (-1);
}
} else {
pcb = &(pcbr->pcb_below[0]);
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);
}
}
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);
}
static audit_pcb_t *pcbls = NULL;
static void
asort(pcb)
register audit_pcb_t *pcb;
{
register audit_pcb_t *pcbc, *pcbp;
extern audit_pcb_t *pcbls;
pcb->pcb_next = NULL;
if (pcbls == NULL) {
pcbls = pcb;
return;
}
pcbc = pcbls;
pcbp = pcbls;
while (pcbc != NULL) {
if (pcb->pcb_time < pcbc->pcb_time) {
if (pcbp == pcbc) {
pcb->pcb_next = pcbls;
pcbls = pcb;
return;
}
pcbp->pcb_next = pcb;
pcb->pcb_next = pcbc;
return;
}
pcbp = pcbc;
pcbc = pcbc->pcb_next;
}
pcbp->pcb_next = pcb;
}
static audit_pcb_t *
aget()
{
audit_pcb_t *pcbret;
extern audit_pcb_t *pcbls;
if (pcbls == NULL)
return (pcbls);
pcbret = pcbls;
pcbls = pcbls->pcb_next;
return (pcbret);
}
static int
get_file(pcb)
register audit_pcb_t *pcb;
{
FILE *fp;
audit_fcb_t *fcb;
while (pcb->pcb_fpr == NULL) {
if ((fcb = pcb->pcb_first) == NULL) {
pcb->pcb_time = -1;
return (-1);
} else {
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);
}
if (errno == ENFILE || errno == EMFILE)
{
return (-2);
}
pcb->pcb_first = fcb->fcb_next;
continue;
}
} else {
fp = stdin;
}
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;
}
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);
}
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);
if ((*nprecs)++ == 0) {
if (pcbr->pcb_flags & PF_ROOT) {
f_start = pcb->pcb_time;
if (write_header())
return (-1);
}
}
f_end = pcb->pcb_time;
pcb->pcb_time = -1;
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);
}
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;
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);
(void) adrm_char(&adr, (char *)&header_type, 1);
(void) adrm_int32(&adr, (int32_t *)&tmp, 1);
(void) adrm_char(&adr, (char *)&tmp, 1);
(void) adrm_short(&adr, (short *)&e, 1);
(void) adrm_short(&adr, (short *)&tmp, 1);
if (header_type == AUT_HEADER32) {
int32_t s, m;
(void) adrm_int32(&adr, (int32_t *)&s, 1);
(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];
(void) adrm_int32(&adr, (int32_t *)&t, 1);
(void) adrm_int32(&adr, (int32_t *)&junk[0], t/4);
(void) adrm_int32(&adr, (int32_t *)&s, 1);
(void) adrm_int32(&adr, (int32_t *)&m, 1);
secs = (time_t)s;
} else if (header_type == AUT_HEADER64) {
int64_t s, m;
(void) adrm_int64(&adr, (int64_t *)&s, 1);
(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];
(void) adrm_int32(&adr, (int32_t *)&t, 1);
(void) adrm_int32(&adr, (int32_t *)&junk[0], t/4);
(void) adrm_int64(&adr, (int64_t *)&s, 1);
(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
if (pcb->pcb_nrecs == 0 && (pcb->pcb_flags & PF_USEFILE)) {
if (ret > 0)
(pcb->pcb_cur)->fcb_start = secs;
if (!f_all && (m_before <= (pcb->pcb_cur)->fcb_start)) {
(void) fclose(pcb->pcb_fpr);
pcb->pcb_fpr = NULL;
pcb->pcb_time = -1;
return (-1);
} else {
if (f_verbose) {
(void) fprintf(stderr,
gettext("%s opened:\n %s.\n"),
ar, (pcb->pcb_cur)->fcb_file);
}
}
}
if (ret > 0) {
pcb->pcb_time = secs;
pcb->pcb_nrecs++;
nrecs++;
if (pcb->pcb_flags & PF_USEFILE) {
check_order(pcb);
if ((ret2 = check_rec(pcb)) == 0) {
pcb->pcb_nprecs++;
getrec = FALSE;
} else if (ret2 == -2) {
getrec = FALSE;
alldone = TRUE;
free(pcb->pcb_rec);
} else {
free(pcb->pcb_rec);
}
} else {
pcb->pcb_nprecs++;
getrec = FALSE;
}
} else {
getrec = FALSE;
alldone = TRUE;
}
}
if (alldone == TRUE) {
#if AUDIT_FILE
get_trace(pcb);
#endif
if (ret < 0 || ret2 == -2) {
pcb->pcb_nrecs++;
if (!f_quiet) {
if (pcb->pcb_flags & PF_USEFILE) {
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 {
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
static void
get_trace(pcb)
audit_pcb_t *pcb;
{
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
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;
adrm_start(&adr, pcb->pcb_rec);
(void) adrm_char(&adr, &tokenid, 1);
checkflags = 0;
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);
}
(void) adrm_u_int32(&adr, (uint32_t *)&bytes, 1);
(void) adrm_char(&adr, &version, 1);
(void) adrm_u_short(&adr, &event_type, 1);
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);
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];
(void) adrm_int32(&adr, (int32_t *)&t, 1);
(void) adrm_int32(&adr, (int32_t *)&junk[0], t/4);
(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];
(void) adrm_int32(&adr, (int32_t *)&t, 1);
(void) adrm_int32(&adr, (int32_t *)&junk[0], t/4);
(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 (!flags)
return (0);
if (flags == checkflags)
return (0);
while ((uint_t)(adr.adr_now - adr.adr_stream) < bytes) {
adrm_char(&adr, &tokenid, 1);
rc = token_processing(&adr, tokenid);
if (rc == -2) {
(void) fprintf(stderr,
gettext("auditreduce: bad token %u, terminating "
"file %s\n"), tokenid, (pcb->pcb_cur)->fcb_file);
return (-2);
}
if (flags == checkflags)
return (0);
}
return (-1);
}
static void
check_order(pcb)
register audit_pcb_t *pcb;
{
char cptr1[28], cptr2[28];
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);
}
}
}
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);
}
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;
(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:
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);
}
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);
}
default:
break;
}
error_str = gettext("record begins without proper token");
return (-1);
}