diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/auditreduce | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/auditreduce')
| -rw-r--r-- | usr/src/cmd/auditreduce/Makefile | 66 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/auditr.h | 117 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/auditrd.h | 122 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/auditrt.h | 253 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/main.c | 1078 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/option.c | 1226 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/proc.c | 1050 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/regex2.c | 143 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/time.c | 496 | ||||
| -rw-r--r-- | usr/src/cmd/auditreduce/token.c | 1966 |
10 files changed, 6517 insertions, 0 deletions
diff --git a/usr/src/cmd/auditreduce/Makefile b/usr/src/cmd/auditreduce/Makefile new file mode 100644 index 0000000000..48d3b6d72b --- /dev/null +++ b/usr/src/cmd/auditreduce/Makefile @@ -0,0 +1,66 @@ +# +# 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 1991-2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +TABLEDIR = ../praudit + +PROG= auditreduce +SRCS= main.c option.c proc.c time.c token.c regex2.c $(TABLEDIR)/toktable.c +OBJS= main.o option.o proc.o time.o token.o regex2.o toktable.o + +include ../Makefile.cmd + +TEXT_DOMAIN=SUNW_OST_OSCMD +POFILE=auditreduce.po +POFILES=main.po option.po proc.po time.po token.po + +CPPFLAGS += -I$(TABLEDIR) +LDLIBS += -lnsl -lbsm + +.KEEP_STATE: + +all: $(PROG) + +install: all $(ROOTUSRSBINPROG) + +$(PROG): $(OBJS) + $(CC) -o $(PROG) $(OBJS) $(LDFLAGS) $(LDLIBS) + $(POST_PROCESS) + +toktable.o: $(TABLEDIR)/toktable.c + $(COMPILE.c) $(TABLEDIR)/toktable.c + +$(POFILE): $(POFILES) + $(RM) -f $@ + $(CAT) $(POFILES) > $@ + +lint: lint_SRCS + +clean: + $(RM) -f $(OBJS) $(PROG) $(POFILES) $(POFILE) + +include ../Makefile.targ diff --git a/usr/src/cmd/auditreduce/auditr.h b/usr/src/cmd/auditreduce/auditr.h new file mode 100644 index 0000000000..61462030e6 --- /dev/null +++ b/usr/src/cmd/auditreduce/auditr.h @@ -0,0 +1,117 @@ +/* + * 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 (c) 1987 - 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _AUDITR_H +#define _AUDITR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <stdio.h> +#include <sys/types.h> + +#include <grp.h> +#include <pwd.h> +#include <signal.h> +#include <string.h> +#include <values.h> + +#include <dirent.h> +#include <sys/errno.h> +#include <sys/file.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <tzfile.h> +#include <sys/resource.h> +#include <netdb.h> +#include <unistd.h> +#include <libgen.h> +#include <stdlib.h> + +#include <bsm/audit.h> +#include <bsm/audit_record.h> +#include <bsm/libbsm.h> + +#include "auditrt.h" + +/* + * Flags for on/off code. + * The release setting would be 0 0 0 1. + */ +#define AUDIT_PROC_TRACE 0 /* process trace code */ +#define AUDIT_FILE 0 /* file trace code (use -V also) */ +#define AUDIT_REC 0 /* record trace code (very verbose) */ +#define AUDIT_RENAME 1 /* rename output file w/time stamps */ + +#define TRUE 1 +#define FALSE 0 + +#define FM_ALLDIR 1 /* f_mode in o.c - all dirs in this dir */ +#define FM_ALLFILE 0 /* f_mode in o.c - all audit files in dir */ + +#define MAXFILELEN (MAXPATHLEN+MAXNAMLEN+1) + +/* + * Initial size of a record buffer. + * Never smaller than (2 * sizeof (short)). + * If a buffer is too small for the record being read then the + * current buffer is freed and a large-enough one is allocated. + */ +#define AUDITBUFSIZE 512 /* size of default record buffer */ + +/* + * Controls size of audit_pcbs[] array. + * INITSIZE is the initial allocation for the array. + * INC is the growth jump when the array becomes too small. + */ +#define PCB_INITSIZE 100 +#define PCB_INC 50 + + +/* + * Memory allocation functions. + * audit calloc that checks for NULL return + */ +extern void *a_calloc(int, size_t); + +/* + * Statistical reporting for error conditions. + */ +extern void audit_stats(void); +extern int errno; + +#ifdef __cplusplus +} +#endif + +#endif /* _AUDITR_H */ diff --git a/usr/src/cmd/auditreduce/auditrd.h b/usr/src/cmd/auditreduce/auditrd.h new file mode 100644 index 0000000000..4e4fec866f --- /dev/null +++ b/usr/src/cmd/auditreduce/auditrd.h @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#ifndef _AUDITRD_H +#define _AUDITRD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Global data for auditreduce + */ + +/* + * Message selection options + */ +unsigned short m_type; /* 'm' message type */ +gid_t m_groupr; /* 'g' group-id */ +gid_t m_groupe; /* 'f' effective group-id */ +uid_t m_usera; /* 'u' user id */ +uid_t m_usere; /* 'e' effective user-id */ +uid_t m_userr; /* 'r' real user-id */ +time_t m_after; /* 'a' after a time */ +time_t m_before; /* 'b' before a time */ +audit_state_t mask; /* used with m_class */ +char *zonename; /* 'z' zonename */ +#ifdef TSOL +brange_t m_slabel; /* 's' sensitivity label range */ +#endif /* TSOL */ +int flags; +int checkflags; +int socket_flag; +int ip_type; +int ip_ipv6[4]; /* ipv6 type object */ +int obj_flag; /* 'o' object type */ +int obj_id; /* object identifier */ +gid_t obj_group; /* object group */ +uid_t obj_owner; /* object owner */ +int subj_id; /* subject identifier */ +char ipc_type; /* 'o' object type - tell what type of IPC */ + +/* + * File selection options + */ +char *f_machine; /* 'M' machine (suffix) type */ +char *f_root; /* 'R' audit root */ +char *f_server; /* 'S' server */ +char *f_outfile; /* 'W' output file */ +static char *f_outtemp; /* 'W' temporary file name */ +int f_all; /* 'A' all records from a file */ +int f_complete; /* 'C' only completed files */ +int f_delete; /* 'D' delete when done */ +int f_quiet; /* 'Q' sshhhh! */ +int f_verbose; /* 'V' verbose */ +int f_stdin; /* '-' read from stdin */ +int f_cmdline; /* files specified on the command line */ +int new_mode; /* 'N' new object selection mode */ + +/* + * Global error reporting + */ +char *error_str; /* current error message */ +char errbuf[256]; /* for creating error messages with sprintf */ +char *ar = "auditreduce:"; +static int root_pid; /* remember original process's pid */ + +/* + * Global control blocks + */ +audit_pcb_t *audit_pcbs; /* ptr to array of pcbs that hold files (fcbs) */ + +int pcbsize; /* size of audit_pcb[] */ +int pcbnum; /* number of pcbs in audit_pcb[] that are active */ + +/* + * Time values + */ +time_t f_start; /* time of first record written */ +time_t f_end; /* time of last record written */ +time_t time_now; /* time the program began */ + +/* + * Global counting vars + */ +int filenum; /* number of files to process */ + +/* + * Global variable, class of current record being processed. + */ +int global_class; + +#ifdef __cplusplus +} +#endif + +#endif /* _AUDITRD_H */ diff --git a/usr/src/cmd/auditreduce/auditrt.h b/usr/src/cmd/auditreduce/auditrt.h new file mode 100644 index 0000000000..a52e17c413 --- /dev/null +++ b/usr/src/cmd/auditreduce/auditrt.h @@ -0,0 +1,253 @@ +/* + * 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. + */ + +#ifndef _AUDITRT_H +#define _AUDITRT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Auditreduce data structures. + */ + +/* + * File Control Block + * Controls a single file. + * These are held by the pcb's in audit_pcbs[] in a linked list. + * There is one fcb for each file controlled by the pcb, + * and all of the files in a list have the same suffix in their names. + */ +struct audit_fcb { + struct audit_fcb *fcb_next; /* ptr to next fcb in list */ + int fcb_flags; /* flags - see below */ + time_t fcb_start; /* start time from filename */ + time_t fcb_end; /* end time from filename */ + char *fcb_suffix; /* ptr to suffix in fcb_file */ + char *fcb_name; /* ptr to name in fcb_file */ + char fcb_file[1]; /* full path and name string */ +}; + +typedef struct audit_fcb audit_fcb_t; + +/* + * Flags for fcb_flags. + */ +#define FF_NOTTERM 0x01 /* file is "not_terminated" */ +#define FF_DELETE 0x02 /* we may delete this file if requested */ + +/* + * Process Control Block + * A pcb comes in two types: + * It controls either: + * + * 1. A single group of pcbs (processes that are lower on the process tree). + * These are the pcb's that the process tree is built from. + * These are allocated as needed while the process tree is being built. + * + * 2. A single group of files (fcbs). + * All of the files in one pcb have the same suffix in their filename. + * They are controlled by the leaf nodes of the process tree. + * They are found in audit_pcbs[]. + * They are initially setup by process_fileopt() when the files to be + * processes are gathered together. Then they are parsed out to + * the leaf nodes by mfork(). + * A particular leaf node's range of audit_pcbs[] is determined + * in the call to mfork() by the lo and hi paramters. + */ +struct audit_pcb { + struct audit_pcb *pcb_below; /* ptr to group of pcb's */ + struct audit_pcb *pcb_next; /* ptr to next - for list in mproc() */ + int pcb_procno; /* subprocess # */ + int pcb_nrecs; /* how many records read (current pcb/file) */ + int pcb_nprecs; /* how many records put (current pcb/file) */ + int pcb_flags; /* flags - see below */ + int pcb_count; /* count of active pcb's */ + int pcb_lo; /* low index for pcb's */ + int pcb_hi; /* hi index for pcb's */ + int pcb_size; /* size of current record buffer */ + time_t pcb_time; /* time of current record */ + time_t pcb_otime; /* time of previous record */ + char *pcb_rec; /* ptr to current record buffer */ + char *pcb_suffix; /* ptr to suffix name (string) */ + audit_fcb_t *pcb_first; /* ptr to first fcb_ */ + audit_fcb_t *pcb_last; /* ptr to last fcb_ */ + audit_fcb_t *pcb_cur; /* ptr to current fcb_ */ + audit_fcb_t *pcb_dfirst; /* ptr to first fcb_ for deleting */ + audit_fcb_t *pcb_dlast; /* ptr to last fcb_ for deleting */ + FILE *pcb_fpr; /* read stream */ + FILE *pcb_fpw; /* write stream */ +}; + +typedef struct audit_pcb audit_pcb_t; + +/* + * Flags for pcb_flags + */ +#define PF_ROOT 0x01 /* current pcb is the root of process tree */ +#define PF_LEAF 0x02 /* current pcb is a leaf of process tree */ +#define PF_FILE 0x04 /* current pcb uses files as input, not pipes */ + +/* + * Message selection options + */ +#define M_AFTER 0x0001 /* 'a' after a time */ +#define M_BEFORE 0x0002 /* 'b' before a time */ +#define M_CLASS 0x0004 /* 'c' event class */ +#define M_GROUPE 0x0008 /* 'f' effective group-id */ +#define M_GROUPR 0x0010 /* 'g' real group-id */ +#define M_OBJECT 0x0020 /* 'o' object */ +#define M_SUBJECT 0x0040 /* 'j' subject */ +#define M_TYPE 0x0080 /* 'm' event type */ +#define M_USERA 0x0100 /* 'u' audit user */ +#define M_USERE 0x0200 /* 'e' effective user */ +#define M_USERR 0x0400 /* 'r' real user */ +#define M_SLABEL 0x0800 /* 's' sensitivity label range */ +#define M_ZONENAME 0x1000 /* 'z' zone name */ +#define M_SORF 0x4000 /* success or failure of event */ +/* + * object types + */ + +/* XXX Why is this a bit map? There can be only one M_OBJECT. */ + +#define OBJ_LP 0x00001 /* 'o' lp object */ +#define OBJ_MSG 0x00002 /* 'o' msgq object */ +#define OBJ_PATH 0x00004 /* 'o' file system object */ +#define OBJ_PROC 0x00008 /* 'o' process object */ +#define OBJ_SEM 0x00010 /* 'o' semaphore object */ +#define OBJ_SHM 0x00020 /* 'o' shared memory object */ +#define OBJ_SOCK 0x00040 /* 'o' socket object */ +#define OBJ_FGROUP 0x00080 /* 'o' file group */ +#define OBJ_FOWNER 0x00100 /* 'o' file owner */ +#define OBJ_MSGGROUP 0x00200 /* 'o' msgq [c]group */ +#define OBJ_MSGOWNER 0x00400 /* 'o' msgq [c]owner */ +#define OBJ_PGROUP 0x00800 /* 'o' process [e]group */ +#define OBJ_POWNER 0x01000 /* 'o' process [e]owner */ +#define OBJ_SEMGROUP 0x02000 /* 'o' semaphore [c]group */ +#define OBJ_SEMOWNER 0x04000 /* 'o' semaphore [c]owner */ +#define OBJ_SHMGROUP 0x08000 /* 'o' shared memory [c]group */ +#define OBJ_SHMOWNER 0x10000 /* 'o' shared memory [c]owner */ + +#define SOCKFLG_MACHINE 0 /* search socket token by machine name */ +#define SOCKFLG_PORT 1 /* search socket token by port number */ + +/* + * Global variables + */ +extern unsigned short m_type; /* 'm' message type */ +extern gid_t m_groupr; /* 'g' real group-id */ +extern gid_t m_groupe; /* 'f' effective group-id */ +extern uid_t m_usera; /* 'u' audit user */ +extern uid_t m_userr; /* 'r' real user */ +extern uid_t m_usere; /* 'f' effective user */ +extern time_t m_after; /* 'a' after a time */ +extern time_t m_before; /* 'b' before a time */ +extern audit_state_t mask; /* used with m_class */ +extern char *zonename; /* 'z' zonename */ + +#ifdef TSOL +extern brange_t m_slabel; /* 's' sensitivity label range */ +#endif /* TSOL */ +extern int flags; +extern int checkflags; +extern int socket_flag; +extern int ip_type; +extern int ip_ipv6[4]; /* ip ipv6 object identifier */ +extern int obj_flag; /* 'o' object type */ +extern int obj_id; /* object identifier */ +extern gid_t obj_group; /* object group */ +extern uid_t obj_owner; /* object owner */ +extern int subj_id; /* subject identifier */ +extern char ipc_type; /* 'o' object type - tell what type of IPC */ + +/* + * File selection options + */ +extern char *f_machine; /* 'M' machine (suffix) type */ +extern char *f_root; /* 'R' audit root */ +extern char *f_server; /* 'S' server */ +extern char *f_outfile; /* 'W' output file */ +extern int f_all; /* 'A' all records from a file */ +extern int f_complete; /* 'C' only completed files */ +extern int f_delete; /* 'D' delete when done */ +extern int f_quiet; /* 'Q' sshhhh! */ +extern int f_verbose; /* 'V' verbose */ +extern int f_stdin; /* '-' read from stdin */ +extern int f_cmdline; /* files specified on the command line */ +extern int new_mode; /* 'N' new object selection mode */ + +/* + * Error reporting + * Error_str is set whenever an error occurs to point to a string describing + * the error. When the error message is printed error_str is also + * printed to describe exactly what went wrong. + * Errbuf is used to build messages with variables in them. + */ +extern char *error_str; /* current error message */ +extern char errbuf[]; /* buffer for building error message */ +extern char *ar; /* => "auditreduce:" */ + +/* + * Control blocks + * Audit_pcbs[] is an array of pcbs that control files directly. + * In the program's initialization phase it will gather all of the input + * files it needs to process. Each file will have one fcb allocated for it, + * and each fcb will belong to one pcb from audit_pcbs[]. All of the files + * in a single pcb will have the same suffix in their filenames. If the + * number of active pcbs in audit_pcbs[] is greater that the number of open + * files a single process can have then the program will need to fork + * subprocesses to handle all of the files. + */ +extern audit_pcb_t *audit_pcbs; /* file-holding pcb's */ +extern int pcbsize; /* current size of audit_pcbs[] */ +extern int pcbnum; /* total # of active pcbs in audit_pcbs[] */ + +/* + * Time values + */ +extern time_t f_start; /* time of start rec for outfile */ +extern time_t f_end; /* time of end rec for outfile */ +extern time_t time_now; /* time program began */ + +/* + * Counting vars + */ +extern int filenum; /* number of files total */ + +/* + * Global variable, class of current record being processed. + */ +extern int global_class; + +#ifdef __cplusplus +} +#endif + +#endif /* _AUDITRT_H */ diff --git a/usr/src/cmd/auditreduce/main.c b/usr/src/cmd/auditreduce/main.c new file mode 100644 index 0000000000..8fc0239de2 --- /dev/null +++ b/usr/src/cmd/auditreduce/main.c @@ -0,0 +1,1078 @@ +/* + * 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 1987-2000, 2002 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The Secure SunOS audit reduction tool - auditreduce. + * Document SM0071 is the primary source of information on auditreduce. + * + * Composed of 4 source modules: + * main.c - main driver. + * option.c - command line option processing. + * process.c - record/file/process functions. + * time.c - date/time handling. + * + * Main(), write_header(), audit_stats(), and a_calloc() + * are the only functions visible outside this module. + */ + +#include <siginfo.h> +#include <locale.h> +#include <libintl.h> +#include "auditr.h" +#include "auditrd.h" + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SUNW_OST_OSCMD" +#endif + +extern void derive_str(time_t, char *); +extern int process_options(int, char **); +extern int mproc(audit_pcb_t *); +extern void init_tokens(void); /* shared with praudit */ + +static int a_pow(int, int); +static void calc_procs(void); +static void chld_handler(int); +static int close_outfile(void); +static void c_close(audit_pcb_t *, int); +static void delete_infiles(void); +static void gather_pcb(audit_pcb_t *, int, int); +static void init_options(void); +static int init_sig(void); +static void int_handler(int); +static int mfork(audit_pcb_t *, int, int, int); +static void mcount(int, int); +static int open_outfile(void); +static void p_close(audit_pcb_t *); +static int rename_outfile(void); +static void rm_mem(audit_pcb_t *); +static void rm_outfile(void); +static void trim_mem(audit_pcb_t *); +static int write_file_token(time_t); +static int write_trailer(void); + +/* + * File globals. + */ +static int max_sproc; /* maximum number of subprocesses per process */ +static int total_procs; /* number of processes in the process tree */ +static int total_layers; /* number of layers in the process tree */ + +/* + * .func main - main. + * .desc The beginning. Main() calls each of the initialization routines + * and then allocates the root pcb. Then it calls mfork() to get + * the work done. + * .call main(argc, argv). + * .arg argc - number of arguments. + * .arg argv - array of pointers to arguments. + * .ret 0 - via exit() - no errors detected. + * .ret 1 - via exit() - errors detected (messages printed). + */ +int +main(int argc, char **argv) +{ + int ret; + audit_pcb_t *pcb; + + /* Internationalization */ + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + + root_pid = getpid(); /* know who is root process for error */ + init_options(); /* initialize options */ + init_tokens(); /* initialize token processing table */ + if (init_sig()) /* initialize signals */ + exit(1); + if (process_options(argc, argv)) + exit(1); /* process command line options */ + if (open_outfile()) /* setup root process output stream */ + exit(1); + calc_procs(); /* see how many subprocesses we need */ + /* + * Allocate the root pcb and set it up. + */ + pcb = (audit_pcb_t *)a_calloc(1, sizeof (audit_pcb_t)); + pcb->pcb_procno = root_pid; + pcb->pcb_flags |= PF_ROOT; + pcb->pcb_fpw = stdout; + pcb->pcb_time = -1; + /* + * Now start the whole thing rolling. + */ + if (mfork(pcb, pcbnum, 0, pcbnum - 1)) { + /* + * Error in processing somewhere. A message is already printed. + * Display usage statistics and remove the outfile. + */ + if (getpid() == root_pid) { + audit_stats(); + (void) close_outfile(); + rm_outfile(); + } + exit(1); + } + /* + * Clean up afterwards. + * Only do outfile cleanup if we are root process. + */ + if (getpid() == root_pid) { + if ((ret = write_trailer()) == 0) { /* write trailer to file */ + + ret = close_outfile(); /* close the outfile */ + } + /* + * If there was an error in cleanup then remove outfile. + */ + if (ret) { + rm_outfile(); + exit(1); + } + /* + * And lastly delete the infiles if the user so wishes. + */ + if (f_delete) + delete_infiles(); + } + return (0); +/*NOTREACHED*/ +} + + +/* + * .func mfork - main fork routine. + * .desc Create a (sub-)tree of processses if needed, or just do the work + * if we have few enough groups to process. This is a recursive routine + * which stops recursing when the number of files to process is small + * enough. Each call to mfork() is responsible for a range of pcbs + * from audit_pcbs[]. This range is designated by the lo and hi + * arguments (inclusive). If the number of pcbs is small enough + * then we have hit a leaf of the tree and mproc() is called to + * do the processing. Otherwise we fork some processes and break + * the range of pcbs up amongst them. + * .call ret = mfork(pcb, nsp, lo, hi). + * .arg pcb - ptr to pcb that is root node of the to-be-created tree. + * .arg nsp - number of sub-processes this tree must process. + * .arg lo - lower-limit of process number range. Index into audit_pcbs. + * .arg hi - higher limit of pcb range. Index into audit_pcbs. + * .ret 0 - succesful completion. + * .ret -1 - error encountered in processing - message already printed. + */ +static int +mfork(audit_pcb_t *pcb, int nsp, int lo, int hi) +{ + int range, procno, i, tofork, nnsp, nrem; + int fildes[2]; + audit_pcb_t *pcbn; + +#if AUDIT_PROC_TRACE + (void) fprintf(stderr, "mfork: nsp %d %d->%d\n", nsp, lo, hi); +#endif + + /* + * The range of pcb's to process is small enough now. Do the work. + */ + if (nsp <= max_sproc) { + pcb->pcb_flags |= PF_LEAF; /* leaf in process tree */ + pcb->pcb_below = audit_pcbs; /* proc pcbs from audit_pcbs */ + gather_pcb(pcb, lo, hi); + trim_mem(pcb); /* trim allocated memory */ + return (mproc(pcb)); /* do the work */ + } + /* + * Too many pcb's for one process - must fork. + * Try to balance the tree as it grows and make it short and fat. + * The thing to minimize is the number of times a record passes + * through a pipe. + */ + else { + /* + * Fork less than the maximum number of processes. + */ + if (nsp <= max_sproc * (max_sproc - 1)) { + tofork = nsp / max_sproc; + if (nsp % max_sproc) + tofork++; /* how many to fork */ + } + /* + * Fork the maximum number of processes. + */ + else { + tofork = max_sproc; /* how many to fork */ + } + /* + * Allocate the nodes below us in the process tree. + */ + pcb->pcb_below = (audit_pcb_t *) + a_calloc(tofork, sizeof (*pcb)); + nnsp = nsp / tofork; /* # of pcbs per forked process */ + nrem = nsp % tofork; /* remainder to spread around */ + /* + * Loop to fork all of the subs. Open a pipe for each. + * If there are any errors in pipes, forks, or getting streams + * for the pipes then quit altogether. + */ + for (i = 0; i < tofork; i++) { + pcbn = &pcb->pcb_below[i]; + pcbn->pcb_time = -1; + if (pipe(fildes)) { + perror(gettext( + "auditreduce: couldn't get a pipe")); + return (-1); + } + /* + * Convert descriptors to streams. + */ + if ((pcbn->pcb_fpr = fdopen(fildes[0], "r")) == NULL) { + perror(gettext("auditreduce: couldn't get read stream for pipe")); + return (-1); + } + if ((pcbn->pcb_fpw = fdopen(fildes[1], "w")) == NULL) { + perror(gettext("auditreduce: couldn't get write stream for pipe")); + return (-1); + } + if ((procno = fork()) == -1) { + perror(gettext("auditreduce: fork failed")); + return (-1); + } + /* + * Calculate the range of pcbs from audit_pcbs [] this + * branch of the tree will be responsible for. + */ + range = (nrem > 0) ? nnsp + 1 : nnsp; + /* + * Child route. + */ + if (procno == 0) { + pcbn->pcb_procno = getpid(); + c_close(pcb, i); /* close unused streams */ + /* + * Continue resolving this branch. + */ + return (mfork(pcbn, range, lo, lo + range - 1)); + } + /* Parent route. */ + else { + pcbn->pcb_procno = i; + /* allocate buffer to hold record */ + pcbn->pcb_rec = (char *)a_calloc(1, + AUDITBUFSIZE); + pcbn->pcb_size = AUDITBUFSIZE; + p_close(pcbn); /* close unused streams */ + + nrem--; + lo += range; + } + } + /* + * Done forking all of the subs. + */ + gather_pcb(pcb, 0, tofork - 1); + trim_mem(pcb); /* free unused memory */ + return (mproc(pcb)); + } +} + + +/* + * .func trim_mem - trim memory usage. + * .desc Free un-needed allocated memory. + * .call trim_mem(pcb). + * .arg pcb - ptr to pcb for current process. + * .ret void. + */ +static void +trim_mem(audit_pcb_t *pcb) +{ + int count; + size_t size; + + /* + * For the root don't free anything. We need to save audit_pcbs[] + * in case we are deleting the infiles at the end. + */ + if (pcb->pcb_flags & PF_ROOT) + return; + /* + * For a leaf save its part of audit_pcbs[] and then remove it all. + */ + if (pcb->pcb_flags & PF_LEAF) { + count = pcb->pcb_count; + size = sizeof (audit_pcb_t); + /* allocate a new buffer to hold the pcbs */ + pcb->pcb_below = (audit_pcb_t *)a_calloc(count, size); + /* save this pcb's portion */ + (void) memcpy((void *) pcb->pcb_below, + (void *) &audit_pcbs[pcb->pcb_lo], count * size); + rm_mem(pcb); + gather_pcb(pcb, 0, count - 1); + } + /* + * If this is an intermediate node then just remove it all. + */ + else { + rm_mem(pcb); + } +} + + +/* + * .func rm_mem - remove memory. + * .desc Remove unused memory associated with audit_pcbs[]. For each + * pcb in audit_pcbs[] free the record buffer and all of + * the fcbs. Then free audit_pcbs[]. + * .call rm_mem(pcbr). + * .arg pcbr - ptr to pcb of current process. + * .ret void. + */ +static void +rm_mem(audit_pcb_t *pcbr) +{ + int i; + audit_pcb_t *pcb; + audit_fcb_t *fcb, *fcbn; + + for (i = 0; i < pcbsize; i++) { + /* + * Don't free the record buffer and fcbs for the pcbs this + * process is using. + */ + if (pcbr->pcb_flags & PF_LEAF) { + if (pcbr->pcb_lo <= i || i <= pcbr->pcb_hi) + continue; + } + pcb = &audit_pcbs[i]; + free(pcb->pcb_rec); + for (fcb = pcb->pcb_first; fcb != NULL; /* */) { + fcbn = fcb->fcb_next; + free((char *)fcb); + fcb = fcbn; + } + } + free((char *)audit_pcbs); +} + + +/* + * .func c_close - close unused streams. + * .desc This is called for each child process just after being born. + * The child closes the read stream for the pipe to its parent. + * It also closes the read streams for the other children that + * have been born before it. If any closes fail a warning message + * is printed, but processing continues. + * .call ret = c_close(pcb, i). + * .arg pcb - ptr to the child's parent pcb. + * .arg i - iteration # of child in forking loop. + * .ret void. + */ +static void +c_close(audit_pcb_t *pcb, int i) +{ + int j; + audit_pcb_t *pcbt; + + /* + * Do all pcbs in parent's group up to and including us + */ + for (j = 0; j <= i; j++) { + pcbt = &pcb->pcb_below[j]; + if (fclose(pcbt->pcb_fpr) == EOF) { + if (!f_quiet) + perror(gettext("auditreduce: initial close on pipe failed")); + } + /* + * Free the buffer allocated to hold incoming records. + */ + if (i != j) { + free(pcbt->pcb_rec); + } + } +} + + +/* + * .func p_close - close unused streams for parent. + * .desc Called by the parent right after forking a child. + * Closes the write stream on the pipe to the child since + * we will never use it. + * .call p_close(pcbn), + * .arg pcbn - ptr to pcb. + * .ret void. + */ +static void +p_close(audit_pcb_t *pcbn) +{ + if (fclose(pcbn->pcb_fpw) == EOF) { + if (!f_quiet) + perror(gettext("auditreduce: close for write pipe failed")); + } +} + + +/* + * .func audit_stats - print statistics. + * .desc Print usage statistics for the user if the run fails. + * Tells them how many files they had and how many groups this + * totalled. Also tell them how many layers and processes the + * process tree had. + * .call audit_stats(). + * .arg none. + * .ret void. + */ +void +audit_stats(void) +{ + struct rlimit rl; + + if (getrlimit(RLIMIT_NOFILE, &rl) != -1) + (void) fprintf(stderr, + gettext("%s The system allows %d files per process.\n"), + ar, rl.rlim_cur); + (void) fprintf(stderr, gettext( +"%s There were %d file(s) %d file group(s) %d process(es) %d layer(s).\n"), + ar, filenum, pcbnum, total_procs, total_layers); +} + + +/* + * .func gather_pcb - gather pcbs. + * .desc Gather together the range of the sub-processes that we are + * responsible for. For a pcb that controls processes this is all + * of the sub-processes that it forks. For a pcb that controls + * files this is the the range of pcbs from audit_pcbs[]. + * .call gather_pcb(pcb, lo, hi). + * .arg pcb - ptr to pcb. + * .arg lo - lo index into pcb_below. + * .arg hi - hi index into pcb_below. + * .ret void. + */ +static void +gather_pcb(audit_pcb_t *pcb, int lo, int hi) +{ + pcb->pcb_lo = lo; + pcb->pcb_hi = hi; + pcb->pcb_count = hi - lo + 1; +} + + +/* + * .func calc_procs - calculate process parameters. + * .desc Calculate the current run's paramters regarding how many + * processes will have to be forked (maybe none). + * 5 is subtracted from maxfiles_proc to allow for stdin, stdout, + * stderr, and the pipe to a parent process. The outfile + * in the root process is assigned to stdout. The unused half of each + * pipe is closed, to allow for more connections, but we still + * have to have the 5th spot because in order to get the pipe + * we need 2 descriptors up front. + * .call calc_procs(). + * .arg none. + * .ret void. + */ +static void +calc_procs(void) +{ + int val; + int maxfiles_proc; + struct rlimit rl; + + if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { + perror("auditreduce: getrlimit"); + exit(1); + } + + maxfiles_proc = rl.rlim_cur; + + max_sproc = maxfiles_proc - 5; /* max subprocesses per process */ + + /* + * Calculate how many layers the process tree has. + */ + total_layers = 1; + for (/* */; /* */; /* */) { + val = a_pow(max_sproc, total_layers); + if (val > pcbnum) + break; + total_layers++; + } + /* + * Count how many processes are in the process tree. + */ + mcount(pcbnum, 0); + +#if AUDIT_PROC_TRACE + (void) fprintf(stderr, + "pcbnum %d filenum %d mfp %d msp %d ly %d tot %d\n\n", + pcbnum, filenum, maxfiles_proc, max_sproc, + total_layers, total_procs); +#endif +} + + +static int +a_pow(int base, int exp) +{ + int i; + int answer; + + if (exp == 0) { + answer = 1; + } else { + answer = base; + for (i = 0; i < (exp - 1); i++) + answer *= base; + } + return (answer); +} + + +/* + * .func mcount - main count. + * .desc Go through the motions of building the process tree just + * to count how many processes there are. Don't really + * build anything. Answer is in global var total_procs. + * .call mcount(nsp, lo). + * .arg nsp - number of subs for this tree branch. + * .arg lo - lo side of range of subs. + * .ret void. + */ +static void +mcount(int nsp, int lo) +{ + int range, i, tofork, nnsp, nrem; + + total_procs++; /* count another process created */ + + if (nsp > max_sproc) { + if (nsp <= max_sproc * (max_sproc - 1)) { + tofork = nsp / max_sproc; + if (nsp % max_sproc) + tofork++; + } else { + tofork = max_sproc; + } + nnsp = nsp / tofork; + nrem = nsp % tofork; + for (i = 0; i < tofork; i++) { + range = (nrem > 0) ? nnsp + 1 : nnsp; + mcount(range, lo); + nrem--; + lo += range; + } + } +} + + +/* + * .func delete_infiles - delete the input files. + * .desc If the user asked us to (via 'D' flag) then unlink the input files. + * .call ret = delete_infiles(). + * .arg none. + * .ret void. + */ +static void +delete_infiles(void) +{ + int i; + audit_pcb_t *pcb; + audit_fcb_t *fcb; + + for (i = 0; i < pcbsize; i++) { + pcb = &audit_pcbs[i]; + fcb = pcb->pcb_dfirst; + while (fcb != NULL) { + /* + * Only delete a file if it was succesfully processed. + * If there were any read errors or bad records + * then don't delete it. + * There may still be unprocessed records in it. + */ + if (fcb->fcb_flags & FF_DELETE) { + if (unlink(fcb->fcb_file)) { + if (f_verbose) { + (void) sprintf(errbuf, gettext( + "%s delete on %s failed"), + ar, fcb->fcb_file); + } + perror(errbuf); + } + } + fcb = fcb->fcb_next; + } + } +} + + +/* + * .func rm_outfile - remove the outfile. + * .desc Remove the file we are writing the records to. We do this if + * processing failed and we are quitting before finishing. + * Update - don't actually remove the outfile, but generate + * a warning about its possible heathen nature. + * .call ret = rm_outfile(). + * .arg none. + * .ret void. + */ +static void +rm_outfile(void) +{ +#if 0 + if (f_outfile) { + if (unlink(f_outtemp) == -1) { + (void) sprintf(errbuf, + gettext("%s delete on %s failed"), + ar, f_outtemp); + perror(errbuf); + } + } +#else + (void) fprintf(stderr, +gettext("%s Warning: Incomplete audit file may have been generated - %s\n"), + ar, + (f_outfile == NULL) ? gettext("standard output") : f_outfile); +#endif +} + + +/* + * .func close_outfile - close the outfile. + * .desc Close the file we are writing records to. + * .call ret = close_outfile(). + * .arg none. + * .ret 0 - close was succesful. + * .ret -1 - close failed. + */ +static int +close_outfile(void) +{ + if (fclose(stdout) == EOF) { + (void) sprintf(errbuf, gettext("%s close on %s failed"), + ar, f_outfile ? f_outfile : "standard output"); + perror(errbuf); + return (-1); + } + (void) fsync(fileno(stdout)); + return (rename_outfile()); +} + + +/* + * .func write_header - write audit file header. + * .desc Write an audit file header to the output stream. The time in the + * header is the time of the first record written to the stream. This + * routine is called by the process handling the root node of the + * process tree just before it writes the first record to the output + * stream. + * .ret 0 - succesful write. + * .ret -1 - failed write - message printed. + */ +int +write_header(void) +{ + return (write_file_token(f_start)); +} + + +static int +write_file_token(time_t when) +{ + adr_t adr; /* adr ptr */ + struct timeval tv; /* time now */ + char for_adr[16]; /* plenty of room */ +#ifdef _LP64 + char token_id = AUT_OTHER_FILE64; +#else + char token_id = AUT_OTHER_FILE32; +#endif + short i = 1; + char c = '\0'; + + tv.tv_sec = when; + tv.tv_usec = 0; + adr_start(&adr, for_adr); + adr_char(&adr, &token_id, 1); +#ifdef _LP64 + adr_int64(&adr, (int64_t *)&tv, 2); +#else + adr_int32(&adr, (int32_t *)&tv, 2); +#endif + adr_short(&adr, &i, 1); + adr_char(&adr, &c, 1); + + if (fwrite(for_adr, sizeof (char), adr_count(&adr), stdout) != + adr_count(&adr)) { + if (when == f_start) { + (void) sprintf(errbuf, + gettext("%s error writing header to %s. "), + ar, + f_outfile ? f_outfile : + gettext("standard output")); + } else { + (void) sprintf(errbuf, + gettext("%s error writing trailer to %s. "), + ar, + f_outfile ? f_outfile : + gettext("standard output")); + } + perror(errbuf); + return (-1); + } + return (0); +} + + +/* + * .func write_trailer - write audit file trailer. + * .desc Write an audit file trailer to the output stream. The finish + * time for the trailer is the time of the last record written + * to the stream. + * .ret 0 - succesful write. + * .ret -1 - failed write - message printed. + */ +static int +write_trailer(void) +{ + return (write_file_token(f_end)); +} + + +/* + * .func rename_outfile - rename the outfile. + * .desc If the user used the -O flag they only gave us the suffix name + * for the outfile. We have to add the time stamps to put the filename + * in the proper audit file name format. The start time will be the time + * of the first record in the file and the end time will be the time of + * the last record in the file. + * .ret 0 - rename succesful. + * .ret -1 - rename failed - message printed. + */ +static int +rename_outfile(void) +{ + char f_newfile[MAXFILELEN]; + char buf1[15], buf2[15]; + char *f_file, *f_nfile, *f_time, *f_name; + + if (f_outfile != NULL) { + /* + * Get string representations of start and end times. + */ + derive_str(f_start, buf1); + derive_str(f_end, buf2); + + f_nfile = f_time = f_newfile; /* working copy */ + f_file = f_name = f_outfile; /* their version */ + while (*f_file) { + if (*f_file == '/') { /* look for filename */ + f_time = f_nfile + 1; + f_name = f_file + 1; + } + *f_nfile++ = *f_file++; /* make copy of their version */ + } + *f_time = '\0'; + /* start time goes first */ + (void) strcat(f_newfile, buf1); + (void) strcat(f_newfile, "."); + /* then the finish time */ + (void) strcat(f_newfile, buf2); + (void) strcat(f_newfile, "."); + /* and the name they gave us */ + (void) strcat(f_newfile, f_name); + +#if AUDIT_FILE + (void) fprintf(stderr, "rename_outfile: <%s> --> <%s>\n", + f_outfile, f_newfile); +#endif + +#if AUDIT_RENAME + if (rename(f_outtemp, f_newfile) == -1) { + (void) fprintf(stderr, + "%s rename of %s to %s failed.\n", + ar, f_outtemp, f_newfile); + return (-1); + } + f_outfile = f_newfile; +#else + if (rename(f_outtemp, f_outfile) == -1) { + (void) fprintf(stderr, + gettext("%s rename of %s to %s failed.\n"), + ar, f_outtemp, f_outfile); + return (-1); + } +#endif + } + return (0); +} + + +/* + * .func open_outfile - open the outfile. + * .desc Open the outfile specified by the -O option. Assign it to the + * the standard output. Get a unique temporary name to use so we + * don't clobber an existing file. + * .ret 0 - no errors detected. + * .ret -1 - errors in processing (message already printed). + */ +static int +open_outfile(void) +{ + int tmpfd = -1; + + if (f_outfile != NULL) { + f_outtemp = (char *)a_calloc(1, strlen(f_outfile) + 8); + (void) strcpy(f_outtemp, f_outfile); + (void) strcat(f_outtemp, "XXXXXX"); + if ((tmpfd = mkstemp(f_outtemp)) == -1) { + (void) sprintf(errbuf, + gettext("%s couldn't create temporary file"), ar); + perror(errbuf); + return (-1); + } + (void) fflush(stdout); + if (tmpfd != fileno(stdout)) { + if ((dup2(tmpfd, fileno(stdout))) == -1) { + (void) sprintf(errbuf, + gettext("%s can't assign %s to the " + "standard output"), ar, f_outfile); + perror(errbuf); + return (-1); + } + (void) close(tmpfd); + } + } + return (0); +} + + +/* + * .func init_options - initialize the options. + * .desc Give initial and/or default values to some options. + * .call init_options(); + * .arg none. + * .ret void. + */ +static void +init_options(void) +{ + struct timeval tp; + struct timezone tpz; + + /* + * Get current time for general use. + */ + if (gettimeofday(&tp, &tpz) == -1) + perror(gettext("auditreduce: initial getttimeofday failed")); + + time_now = tp.tv_sec; /* save for general use */ + f_start = 0; /* first record time default */ + f_end = time_now; /* last record time default */ + m_after = 0; /* Jan 1, 1970 00:00:00 */ + + /* + * Setup initial size of audit_pcbs[]. + */ + pcbsize = PCB_INITSIZE; /* initial size of file-holding pcb's */ + + audit_pcbs = (audit_pcb_t *)a_calloc(pcbsize, sizeof (audit_pcb_t)); + + /* description of 'current' error */ + error_str = gettext("initial error"); + +} + + +/* + * .func a_calloc - audit calloc. + * .desc Calloc with check for failure. This is called by all of the + * places that want memory. + * .call ptr = a_calloc(nelem, size). + * .arg nelem - number of elements to allocate. + * .arg size - size of each element. + * .ret ptr - ptr to allocated and zeroed memory. + * .ret never - if calloc fails then we never return. + */ +void * +a_calloc(int nelem, size_t size) +{ + void *ptr; + + if ((ptr = calloc((unsigned)nelem, size)) == NULL) { + perror(gettext("auditreduce: memory allocation failed")); + exit(1); + } + return (ptr); +} + + +/* + * .func init_sig - initial signal catching. + * + * .desc + * Setup the signal catcher to catch the SIGCHLD signal plus + * "environmental" signals -- keyboard plus other externally + * generated signals such as out of file space or cpu time. If a + * child exits with either a non-zero exit code or was killed by + * a signal to it then we will also exit with a non-zero exit + * code. In this way abnormal conditions can be passed up to the + * root process and the entire run be halted. Also catch the int + * and quit signals. Remove the output file since it is in an + * inconsistent state. + * .call ret = init_sig(). + * .arg none. + * .ret 0 - no errors detected. + * .ret -1 - signal failed (message printed). + */ +static int +init_sig(void) +{ + if (signal(SIGCHLD, chld_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGCHLD signal failed")); + return (-1); + } + + if (signal(SIGHUP, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGHUP signal failed")); + return (-1); + } + if (signal(SIGINT, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGINT signal failed")); + return (-1); + } + if (signal(SIGQUIT, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGQUIT signal failed")); + return (-1); + } + if (signal(SIGABRT, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGABRT signal failed")); + return (-1); + } + if (signal(SIGTERM, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGTERM signal failed")); + return (-1); + } + if (signal(SIGPWR, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGPWR signal failed")); + return (-1); + } + if (signal(SIGXCPU, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGXCPU signal failed")); + return (-1); + } + if (signal(SIGXFSZ, int_handler) == SIG_ERR) { + perror(gettext("auditreduce: SIGXFSZ signal failed")); + return (-1); + } + + return (0); +} + + +/* + * .func chld_handler - handle child signals. + * .desc Catch the SIGCHLD signals. Remove the root process + * output file because it is in an inconsistent state. + * Print a message giving the signal number and/or return code + * of the child who caused the signal. + * .ret void. + */ +/* ARGSUSED */ +void +chld_handler(int sig) +{ + int pid; + int status; + + /* + * Get pid and reasons for cause of event. + */ + pid = wait(&status); + + if (pid > 0) { + /* + * If child received a signal or exited with a non-zero + * exit status then print message and exit + */ + if ((WHIBYTE(status) == 0 && WLOBYTE(status) != 0) || + (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)) { + (void) fprintf(stderr, + gettext("%s abnormal child termination - "), ar); + + if (WHIBYTE(status) == 0 && WLOBYTE(status) != 0) { + psignal(WLOBYTE(status), "signal"); + if (WCOREDUMP(status)) + (void) fprintf(stderr, + gettext("core dumped\n")); + } + + if (WHIBYTE(status) != 0 && WLOBYTE(status) == 0) + (void) fprintf(stderr, gettext( + "return code %d\n"), + WHIBYTE(status)); + + /* + * Get rid of outfile - it is suspect. + */ + if (f_outfile != NULL) { + (void) close_outfile(); + rm_outfile(); + } + /* + * Give statistical info that may be useful. + */ + audit_stats(); + + exit(1); + } + } +} + + +/* + * .func int_handler - handle quit/int signals. + * .desc Catch the keyboard and other environmental signals. + * Remove the root process output file because it is in + * an inconsistent state. + * .ret void. + */ +/* ARGSUSED */ +void +int_handler(int sig) +{ + if (getpid() == root_pid) { + (void) close_outfile(); + rm_outfile(); + exit(1); + } + /* + * For a child process don't give an error exit or the + * parent process will catch it with the chld_handler and + * try to erase the outfile again. + */ + exit(0); +} diff --git a/usr/src/cmd/auditreduce/option.c b/usr/src/cmd/auditreduce/option.c new file mode 100644 index 0000000000..abb702bb39 --- /dev/null +++ b/usr/src/cmd/auditreduce/option.c @@ -0,0 +1,1226 @@ +/* + * 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" + +/* + * Command line option processing for auditreduce. + * The entry point is process_options(), which is called by main(). + * Process_options() is the only function visible outside this module. + */ + +#include <locale.h> +#include <sys/zone.h> /* for max zonename length */ + +#ifdef TSOL +#include <tsol/label.h> +#endif /* TSOL */ + +#include "auditr.h" + +/* + * Object entry. + * Maps object strings specified on the command line to a flag + * used when searching by object type. + */ + +struct obj_ent { + char *obj_str; /* string specified on the command line */ + int obj_flag; /* flag used when searching */ +}; + +typedef struct obj_ent obj_ent_t; + +/* + * Supports searches by object type. + */ +static obj_ent_t obj_tbl[] = { + { "file", OBJ_PATH }, + { "filegroup", OBJ_FGROUP }, + { "fileowner", OBJ_FOWNER }, + { "lp", OBJ_LP }, + { "msgqid", OBJ_MSG }, + { "msgqgroup", OBJ_MSGGROUP }, + { "msgqowner", OBJ_MSGOWNER }, + { "path", OBJ_PATH }, + { "pid", OBJ_PROC }, + { "procgroup", OBJ_PGROUP }, + { "procowner", OBJ_POWNER }, + { "semid", OBJ_SEM }, + { "semgroup", OBJ_SEMGROUP }, + { "semowner", OBJ_SEMOWNER }, + { "shmid", OBJ_SHM }, + { "shmgroup", OBJ_SHMGROUP }, + { "shmowner", OBJ_SHMOWNER }, + { "sock", OBJ_SOCK } }; + +extern int derive_date(char *, struct tm *); +extern int parse_time(char *, int); +extern char *re_comp2(char *); +extern time_t tm_to_secs(struct tm *); + +static int a_isnum(char *, int); +static int check_file(audit_fcb_t *, int); +static int gather_dir(char *); +static audit_pcb_t *get_next_pcb(char *); +static obj_ent_t *obj_lkup(char *); +static int proc_class(char *); +static int proc_date(char *, int); +static int proc_file(char *, int); +static int process_fileopt(int, char *argv[], int); +static int proc_group(char *, gid_t *); +static int proc_id(char *, int); +static int proc_object(char *); +static void proc_pcb(audit_pcb_t *, char *, int); +#ifdef TSOL +static int proc_slabel(char *); +#endif /* TSOL */ +static int proc_subject(char *); +static int proc_type(char *); +static int proc_user(char *, uid_t *); +static int proc_zonename(char *); + +/* + * .func process_options - process command line options. + * .desc Process the user's command line options. These are of two types: + * single letter flags that are denoted by '-', and filenames. Some + * of the flags have arguments. Getopt() is used to get the flags. + * When this is done it calls process_fileopt() to handle any filenames + * that were there. + * .call ret = process_options(argc, argv). + * .arg argc - the original value. + * .arg argv - the original value. + * .ret 0 - no errors detected. + * .ret -1 - command line error detected (message already printed). + */ +int +process_options(int argc, char **argv) +{ + int opt; + int error = FALSE; + int error_combo = FALSE; + extern int optind; /* in getopt() */ + extern char *optarg; /* in getopt() - holds arg to flag */ + + static char *options = "ACD:M:NQR:S:VO:a:b:c:d:e:g:j:m:o:r:s:u:z:"; + + error_str = gettext("general error"); + + zonename = NULL; + /* + * Big switch to process the flags. + * Start_over: is for handling the '-' for standard input. Getopt() + * doesn't recognize it. + */ +start_over: + while ((opt = getopt(argc, argv, options)) != EOF) { + switch (opt) { + case 'A': /* all records from the files */ + f_all = TRUE; + break; + case 'C': /* process only completed files */ + f_complete = TRUE; + break; + case 'D': /* delete the files when done */ + /* force 'A' 'C' 'O' to be active */ + f_all = f_complete = TRUE; + f_outfile = optarg; + f_delete = TRUE; + break; + case 'M': /* only files from a certain machine */ + f_machine = optarg; + break; + case 'N': /* new object selection mode */ + new_mode = TRUE; + break; + case 'Q': /* no file error reporting */ + f_quiet = TRUE; + break; + case 'R': /* from specified root */ + f_root = optarg; + break; + case 'S': /* from specified server */ + f_server = optarg; + break; + case 'V': /* list all files as they are opened */ + f_verbose = TRUE; + break; + case 'O': /* write to outfile */ + f_outfile = optarg; + break; + case 'a': /* after 'date' */ + case 'b': /* before 'date' */ + case 'd': /* from 'day' */ + if (proc_date(optarg, opt)) + error = TRUE; + break; + case 'j': /* subject */ + if (proc_subject(optarg)) + error = TRUE; + break; + case 'm': /* message 'type' */ + if (proc_type(optarg)) + error = TRUE; + break; + case 'o': /* object type */ + if (proc_object(optarg)) + error = TRUE; + break; + case 'c': /* message class */ + if (proc_class(optarg)) + error = TRUE; + break; + case 'u': /* form audit user */ + case 'e': /* form effective user */ + case 'r': /* form real user */ + case 'f': /* form effective group */ + case 'g': /* form real group */ + if (proc_id(optarg, opt)) + error = TRUE; + break; +#ifdef TSOL + case 's': /* sensitivity label range */ + if (proc_slabel(optarg)) + error = TRUE; + break; +#endif /* TSOL */ + case 'z': /* zone name */ + if (proc_zonename(optarg)) + error = TRUE; + break; + default: + return (-1); + } + if (error) { + (void) fprintf(stderr, + gettext("%s command line error - %s.\n"), + ar, error_str); + return (-1); + } + } + /* catch '-' option for stdin processing - getopt() won't see it */ + if (optind < argc) { + if (argv[optind][0] == '-' && argv[optind][1] == '\0') { + optind++; + f_stdin = TRUE; + goto start_over; + } + } + /* + * Give a default value for 'b' option if not specified. + */ + if (m_before == 0) + m_before = MAXLONG; /* forever */ + /* + * Validate combinations of options. + * The following are done: + * 1. Can't have 'M' or 'S' or 'R' with filenames. + * 2. Can't have an after ('a') time after a before ('b') time. + * 3. Delete ('D') must have 'C' and 'A' and 'O' with it. + * 4. Input from stdin ('-') can't have filenames too. + */ + if ((f_machine || f_server || f_root) && (argc != optind)) { + error_str = gettext( + "no filenames allowed with 'M' or 'S' or 'R' options"); + error_combo = TRUE; + } + if (m_after >= m_before) { + error_str = + gettext("'a' parameter must be before 'b' parameter"); + error_combo = TRUE; + } + if (f_delete && + (!f_complete || !f_all || !f_outfile)) { + error_str = gettext( + "'C', 'A', and 'O' must be specified with 'D'"); + error_combo = TRUE; + } + if (f_stdin && (argc != optind)) { + error_str = gettext("no filenames allowed with '-' option"); + error_combo = TRUE; + } + /* + * If error with option combos then print message and exit. + * If there was an error with just an option then exit. + */ + if (error_combo) { + (void) fprintf(stderr, + gettext("%s command line error - %s.\n"), ar, error_str); + return (-1); + } + if (f_root == NULL) + f_root = "/etc/security/audit"; + /* + * Now handle any filenames included in the command line. + */ + return (process_fileopt(argc, argv, optind)); +} + +int +proc_subject(char *optarg) +{ + if (flags & M_SUBJECT) { + error_str = gettext("'j' option specified multiple times"); + return (-1); + } + flags |= M_SUBJECT; + subj_id = atol(optarg); + return (0); +} + + +int +proc_object(char *optarg) +{ + char *obj_str; + char *obj_val; + char *obj_arg; + int err; + + obj_ent_t *oep; + struct hostent *he; + + if (flags & M_OBJECT) { + error_str = gettext("'o' option specified multiple times"); + return (-1); + } + flags |= M_OBJECT; + if ((obj_arg = strdup(optarg)) == (char *)0) + return (-1); + if ((obj_str = strtok(optarg, "=")) == (char *)0 || + (oep = obj_lkup(obj_str)) == (obj_ent_t *)0 || + (obj_val = strtok((char *)0, "=")) == (char *)0) { + (void) sprintf(errbuf, gettext("invalid object arg (%s)"), + obj_arg); + error_str = errbuf; + return (-1); + } + + obj_flag = oep->obj_flag; + + switch (obj_flag) { + case OBJ_PATH: + if ((error_str = re_comp2(obj_val)) != (char *)NULL) { + return (-1); + } + return (0); + /* NOTREACHED */ + case OBJ_SOCK: + if (!a_isnum(obj_val, TRUE)) { + obj_id = atol(obj_val); + socket_flag = SOCKFLG_PORT; + return (0); + } + if (*obj_val == '0') { + (void) sscanf(obj_val, "%x", (uint_t *)&obj_id); + socket_flag = SOCKFLG_PORT; + return (0); + } + + he = getipnodebyname((const void *)obj_val, AF_INET6, 0, &err); + if (he == 0) { + he = getipnodebyname((const void *)obj_val, AF_INET, + 0, &err); + if (he == 0) { + (void) sprintf(errbuf, + gettext("invalid machine name (%s)"), + obj_val); + error_str = errbuf; + return (-1); + } + } + + if (he->h_addrtype == AF_INET6) { + /* LINTED */ + if (IN6_IS_ADDR_V4MAPPED((in6_addr_t *) + he->h_addr_list[0])) { + /* address is IPv4 (32 bits) */ + (void) memcpy(&obj_id, he->h_addr_list[0], 4); + ip_type = AU_IPv4; + } else { + (void) memcpy(ip_ipv6, he->h_addr_list[0], 16); + ip_type = AU_IPv6; + } + } else { + /* address is IPv4 (32 bits) */ + (void) memcpy(&obj_id, he->h_addr_list[0], 4); + ip_type = AU_IPv4; + } + + freehostent(he); + socket_flag = SOCKFLG_MACHINE; + return (0); + break; + case OBJ_MSG: + case OBJ_SEM: + case OBJ_SHM: + case OBJ_PROC: + obj_id = atol(obj_val); + return (0); + /* NOTREACHED */ + case OBJ_FGROUP: + case OBJ_MSGGROUP: + case OBJ_SEMGROUP: + case OBJ_SHMGROUP: + case OBJ_PGROUP: + return (proc_group(obj_val, &obj_group)); + /* NOTREACHED */ + case OBJ_FOWNER: + case OBJ_MSGOWNER: + case OBJ_SEMOWNER: + case OBJ_SHMOWNER: + case OBJ_POWNER: + return (proc_user(obj_val, &obj_owner)); + /* NOTREACHED */ + case OBJ_LP: /* lp objects have not yet been defined */ + default: /* impossible */ + (void) sprintf(errbuf, gettext("invalid object type (%s)"), + obj_str); + error_str = errbuf; + return (-1); + /* NOTREACHED */ + } /* switch */ + /*NOTREACHED*/ +} + + +obj_ent_t * +obj_lkup(char *obj_str) +{ + int i; + + for (i = 0; i < sizeof (obj_tbl) / sizeof (obj_ent_t); i++) + if (strcmp(obj_str, obj_tbl[i].obj_str) == 0) + return (&obj_tbl[i]); + + /* not in table */ + return ((obj_ent_t *)0); +} + + +/* + * .func proc_type - process record type. + * .desc Process a record type. It is either as a number or a mnemonic. + * .call ret = proc_type(optstr). + * .arg optstr - ptr to name or number. + * .ret 0 - no errors detected. + * .ret -1 - error detected (error_str contains description). + */ +int +proc_type(char *optstr) +{ + struct au_event_ent *aep; + + /* + * Either a number or a name. + */ + + if (flags & M_TYPE) { + error_str = gettext("'m' option specified multiple times"); + return (-1); + } + flags |= M_TYPE; + m_type = 0; + if (a_isnum(optstr, TRUE)) { + if ((aep = getauevnam(optstr)) != (struct au_event_ent *)NULL) + m_type = aep->ae_number; + } else { + if ((aep = getauevnum((au_event_t)atoi(optstr))) != + (struct au_event_ent *)NULL) + m_type = aep->ae_number; + } + if ((m_type == 0)) { + (void) sprintf(errbuf, gettext("invalid event (%s)"), optstr); + error_str = errbuf; + return (-1); + } + return (0); +} + + +/* + * .func a_isnum - is it a number? + * .desc Determine if a string is a number or a name. + * A number may have a leading '+' or '-', but then must be + * all digits. + * .call ret = a_isnum(str). + * .arg str - ptr to the string. + * .arg leading - TRUE if leading '+-' allowed. + * .ret 0 - is a number. + * .ret 1 - is not a number. + */ +int +a_isnum(char *str, int leading) +{ + char *strs; + + if ((leading == TRUE) && (*str == '-' || *str == '+')) + strs = str + 1; + else + strs = str; + + if (strlen(strs) == strspn(strs, "0123456789")) + return (0); + else + return (1); +} + + +/* + * .func proc_id - process user/group id's/ + * .desc Process either a user number/name or group number/name. + * For names check to see if the name is active in the system + * to derive the number. If it is not active then fail. For a number + * also check to see if it is active, but only print a warning if it + * is not. An administrator may be looking at activity of a 'phantom' + * user. + * .call ret = proc_id(optstr, opt). + * .arg optstr - ptr to name or number. + * .arg opt - 'u' - audit user, 'e' - effective user, 'r' - real user, + * 'g' - group, 'f' - effective group. + * .ret 0 - no errors detected. + * .ret -1 - error detected (error_str contains description). + */ +int +proc_id(char *optstr, int opt) +{ + switch (opt) { + case 'e': /* effective user id */ + if (flags & M_USERE) { + error_str = gettext( + "'e' option specified multiple times"); + return (-1); + } + flags |= M_USERE; + return (proc_user(optstr, &m_usere)); + /* NOTREACHED */ + case 'f': /* effective group id */ + if (flags & M_GROUPE) { + error_str = gettext( + "'f' option specified multiple times"); + return (-1); + } + flags |= M_GROUPE; + return (proc_group(optstr, &m_groupe)); + /* NOTREACHED */ + case 'r': /* real user id */ + if (flags & M_USERR) { + error_str = gettext( + "'r' option specified multiple times"); + return (-1); + } + flags |= M_USERR; + return (proc_user(optstr, &m_userr)); + /* NOTREACHED */ + case 'u': /* audit user id */ + if (flags & M_USERA) { + error_str = gettext( + "'u' option specified multiple times"); + return (-1); + } + flags |= M_USERA; + return (proc_user(optstr, &m_usera)); + /* NOTREACHED */ + case 'g': /* real group id */ + if (flags & M_GROUPR) { + error_str = gettext( + "'g' option specified multiple times"); + return (-1); + } + flags |= M_GROUPR; + return (proc_group(optstr, &m_groupr)); + /* NOTREACHED */ + default: /* impossible */ + (void) sprintf(errbuf, gettext("'%c' unknown option"), opt); + error_str = errbuf; + return (-1); + /* NOTREACHED */ + } + /*NOTREACHED*/ +} + + +int +proc_group(char *optstr, gid_t *gid) +{ + struct group *grp; + + if ((grp = getgrnam(optstr)) == NULL) { + if (!a_isnum(optstr, TRUE)) { + *gid = (gid_t)atoi(optstr); + return (0); + } + (void) sprintf(errbuf, gettext("group name invalid (%s)"), + optstr); + error_str = errbuf; + return (-1); + } + *gid = grp->gr_gid; + return (0); +} + + +int +proc_user(char *optstr, uid_t *uid) +{ + struct passwd *usr; + + if ((usr = getpwnam(optstr)) == NULL) { + if (!a_isnum(optstr, TRUE)) { + *uid = (uid_t)atoi(optstr); + return (0); + } + (void) sprintf(errbuf, gettext("user name invalid (%s)"), + optstr); + error_str = errbuf; + return (-1); + } + *uid = usr->pw_uid; + return (0); +} + + +/* + * .func proc_date - process date argument. + * .desc Handle a date/time argument. See if the user has erred in combining + * the types of date arguments. Then parse the string and check for + * validity of each part. + * .call ret = proc_date(optstr, opt). + * .arg optstr - ptr to date/time string. + * .arg opt - 'd' for day, 'a' for after, or 'b' for before. + * .ret 0 - no errors detected. + * .ret -1 - errors detected (error_str knows what it is). + */ +int +proc_date(char *optstr, int opt) +{ + static int m_day = FALSE; + + if (opt == 'd') { + if (m_day == TRUE) { + error_str = gettext( + "'d' option may not be used with 'a' or 'b'"); + return (-1); + } + m_day = TRUE; + } + if ((opt == 'd') && (m_before || m_after)) { + error_str = gettext( + "'d' option may not be used with 'a' or 'b'"); + return (-1); + } + if ((opt == 'a' || opt == 'b') && m_day) { + error_str = gettext( + "'a' or 'b' option may not be used with 'd'"); + return (-1); + } + if ((opt == 'a') && (m_after != 0)) { + error_str = gettext("'a' option specified multiple times"); + return (-1); + } + if ((opt == 'b') && (m_before != 0)) { + error_str = gettext("'b' option specified multiple times"); + return (-1); + } + if (parse_time(optstr, opt)) + return (-1); + return (0); +} + + +/* + * .func proc_class - process message class argument. + * .desc Process class type and see if it is for real. + * .call ret = proc_class(optstr). + * .arg optstr - ptr to class. + * .ret 0 - class has class. + * .ret -1 - class in no good. + */ +int +proc_class(char *optstr) +{ + if (flags & M_CLASS) { + error_str = gettext("'c' option specified multiple times"); + return (-1); + } + flags |= M_CLASS; + + if (getauditflagsbin(optstr, &mask) != 0) { + (void) sprintf(errbuf, gettext("unknown class (%s)"), optstr); + error_str = errbuf; + return (-1); + } + + if (mask.am_success != mask.am_failure) { + flags |= M_SORF; + } + + return (0); +} + + +/* + * .func process_fileopt - process command line file options. + * .desc Process the command line file options and gather the specified files + * together in file groups based upon file name suffix. The user can + * specify files explicitly on the command line or via a directory. + * This is called after the command line flags are processed (as + * denoted by '-'). + * .call ret = process_fileopt(argc, argv, optindex). + * .arg argc - current value of argc. + * .arg argv - current value of argv. + * .arg optindex- current index into argv (as setup by getopt()). + * .ret 0 - no errors detected. + * .ret -1 - error detected (message already printed). + */ +int +process_fileopt(int argc, char **argv, int optindex) +{ + int f_mode = FM_ALLDIR; + char f_dr[MAXNAMLEN+1]; + char *f_dir = f_dr; + char *fname; + static char *std = "standard input"; + audit_fcb_t *fcb; + DIR * dirp; + struct dirent *dp; + audit_pcb_t *pcb; + + /* + * Take input from stdin, not any files. + * Use a single fcb to do this. + */ + if (f_stdin) { + fcb = (audit_fcb_t *)a_calloc(1, sizeof (*fcb) + strlen(std)); + (void) strcpy(fcb->fcb_file, std); + fcb->fcb_suffix = fcb->fcb_name = fcb->fcb_file; + fcb->fcb_next = NULL; + fcb->fcb_start = 0; + fcb->fcb_end = MAXLONG; /* forever */ + if ((pcb = get_next_pcb((char *)NULL)) == (audit_pcb_t *)NULL) + return (-1); + pcb->pcb_suffix = fcb->fcb_file; + pcb->pcb_dfirst = pcb->pcb_first = fcb; /* one-item list */ + pcb->pcb_dlast = pcb->pcb_last = fcb; + pcb->pcb_cur = fcb; + } + /* + * No files specified on the command line. + * Process a directory of files or subdirectories. + */ + else if (argc == optindex) { + /* + * A specific server directory was requested. + */ + if (f_server) { + if (strchr(f_server, '/')) { /* given full path */ + f_dir = f_server; + f_mode = FM_ALLFILE; /* all files here */ + } else { /* directory off audit root */ + f_dir[0] = '\0'; + (void) strcat(f_dir, f_root); + (void) strcat(f_dir, "/"); + (void) strcat(f_dir, f_server); + f_mode = FM_ALLFILE; + } + } + /* + * Gather all of the files in the directory 'f_dir'. + */ + if (f_mode == FM_ALLFILE) { + if (gather_dir(f_dir)) { /* get those files together */ + return (-1); + } + } else { + /* + * Gather all of the files in all of the + * directories in 'f_root'. + */ + if ((dirp = opendir(f_root)) == NULL) { + (void) sprintf(errbuf, gettext( + "%s can't open directory %s"), ar, f_root); + perror(errbuf); + return (-1); + } + /* read the directory and process all of the subs */ + for (dp = readdir(dirp); + dp != NULL; dp = readdir(dirp)) { + if (dp->d_name[0] == '.') + continue; + f_dir[0] = '\0'; + (void) strcat(f_dir, f_root); + (void) strcat(f_dir, "/"); + (void) strcat(f_dir, dp->d_name); + if (gather_dir(f_dir)) /* process a sub */ + return (-1); + } + (void) closedir(dirp); + } + } else { + /* + * User specified filenames on the comm and line. + */ + f_cmdline = TRUE; + for (; optindex < argc; optindex++) { + fname = argv[optindex]; /* get a filename */ + if (proc_file(fname, FALSE)) + return (-1); + } + } + return (0); +} + + +/* + * .func gather_dir - gather a directory's files together. + * .desc Process all of the files in a specific directory. The files may + * be checked for adherence to the file name form at. + * If the directory can't be opened that is ok - just print + * a message and continue. + * .call ret = gather_dir(dir). + * .arg dir - ptr to full pathname of directory. + * .ret 0 - no errors detected. + * .ret -1 - error detected (message already printed). + */ +int +gather_dir(char *dir) +{ + char dname[MAXNAMLEN+1]; + char fname[MAXNAMLEN+1]; + DIR * dirp; + struct dirent *dp; + + (void) snprintf(dname, sizeof (dname), "%s/files", dir); + + if ((dirp = opendir(dname)) == NULL) { + if (errno != ENOTDIR) { + (void) sprintf(errbuf, + gettext("%s can't open directory - %s"), ar, dname); + perror(errbuf); + } + return (0); + } + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (dp->d_name[0] == '.') /* can't see hidden files */ + continue; + fname[0] = '\0'; + (void) strcat(fname, dname); /* create pathname of file */ + (void) strcat(fname, "/"); + (void) strcat(fname, dp->d_name); + if (proc_file(fname, TRUE)) + return (-1); + } + (void) closedir(dirp); + return (0); +} + + +/* + * .func proc_file - process a single candidate file. + * .desc Check out a file to see if it should be used in the merge. + * This includes checking the name (mode is TRUE) against the + * file format, checking access rights to the file, and thence + * getting and fcb and installing the fcb into the correct pcb. + * If the file fails then the fcb is not installed into a pcb + * and the file dissapears from view. + * .call proc_file(fname, mode). + * .arg fname - ptr to full pathna me of file. + * .arg mode - TRUE if checking adherence to file name format. + * .ret 0 - no fatal errors detected. + * .ret -1 - fatal error detected - quit altogether + * (message already printed). + */ +int +proc_file(char *fname, int mode) +{ + int reject = FALSE; + size_t len; + struct stat stat_buf; + audit_fcb_t *fcb, *fcbp, *fcbprev; + audit_pcb_t *pcb; + + /* + * See if it is a weird file like a directory or + * character special (around here?). + */ + if (stat(fname, &stat_buf)) { + return (0); + } + if ((stat_buf.st_mode & S_IFREG) == 0) + return (0); + /* + * Allocate a new fcb to hold fcb and full filename. + */ + len = sizeof (audit_fcb_t) + strlen(fname); + fcb = (audit_fcb_t *)a_calloc(1, len); + (void) strcpy(fcb->fcb_file, fname); + if (check_file(fcb, mode)) { /* check file name */ + if (!f_quiet) { + (void) fprintf(stderr, "%s %s:\n %s.\n", ar, + error_str, fname); + } + reject = TRUE; + } else { + /* + * Check against file criteria. + * Check finish-time here, and start-time later on + * while processing. + * This is because the start time on a file can be after + * the first record(s). + */ + if (f_complete && (fcb->fcb_flags & FF_NOTTERM) && !f_cmdline) + reject = TRUE; + if (!f_all && (fcb->fcb_end < m_after)) + reject = TRUE; + if (f_machine) { + if (strlen(fcb->fcb_suffix) != strlen(f_machine) || + (strcmp(fcb->fcb_suffix, f_machine) != 0)) { + reject = TRUE; + } + } + } + if (reject == FALSE) { + filenum++; /* count of total files to be processed */ + fcb->fcb_next = NULL; + if ((pcb = get_next_pcb(fcb->fcb_suffix)) == NULL) { + return (-1); + } + /* Place FCB into the PCB in order - oldest first. */ + fcbp = pcb->pcb_first; + fcbprev = NULL; + while (fcbp != NULL) { + if (fcb->fcb_start < fcbp->fcb_start) { + if (fcbprev) + fcbprev->fcb_next = fcb; + else + pcb->pcb_dfirst = pcb->pcb_first = fcb; + fcb->fcb_next = fcbp; + break; + } + fcbprev = fcbp; + fcbp = fcbp->fcb_next; + } + /* younger than all || empty list */ + if (!fcb->fcb_next) { + if (pcb->pcb_first == NULL) + pcb->pcb_dfirst = pcb->pcb_first = fcb; + pcb->pcb_dlast = pcb->pcb_last = fcb; + if (fcbprev) + fcbprev->fcb_next = fcb; + } + } else { + free((char *)fcb); /* rejected */ + } + return (0); +} + + +/* + * .func check_file - check filename and setup fcb. + * .desc Check adherence to the file format (do_check is TRUE) and setup + * the fcb with useful information. + * filename format: yyyymmddhhmmss.yyyymmddhhmmss.suffix + * yyyymmddhhmmss.not_terminated.suffix + * If do_check is FALSE then still see if the filename does confirm + * to the format. If it does then extract useful information from + * it (start time and end time). But if it doesn't then don't print + * any error messages. + * .call ret = check_file(fcb, do_check). + * .arg fcb - ptr to fcb that holds the file. + * .arg do_check - if TRUE do check adherence to file format. + * .ret 0 - no errors detected. + * .ret -1 - file failed somehow (error_str tells why). + */ +int +check_file(audit_fcb_t *fcb, int do_check) +{ + int ret; + char *namep, *slp; + char errb[256]; /* build error message */ + struct tm tme; + + errb[0] = '\0'; + /* get just the filename */ + for (slp = namep = fcb->fcb_file; *namep; namep++) { + if (*namep == '/') + slp = namep + 1; /* slp -> the filename itself */ + } + if (do_check == FALSE) { + fcb->fcb_end = MAXLONG; /* forever */ + fcb->fcb_suffix = NULL; + fcb->fcb_name = slp; + ret = 0; + } else { + ret = -1; + } + if ((int)strlen(slp) < 31) { + (void) sprintf(errbuf, gettext("filename too short (%d)"), + strlen(slp)); + error_str = errbuf; + return (ret); + } + /* + * Get working copy of filename. + */ + namep = (char *)a_calloc(1, strlen(slp) + 1); + (void) strcpy(namep, slp); + if (namep[14] != '.' || namep[29] != '.') { + (void) sprintf(errbuf, + gettext("invalid filename format (%c or %c)"), namep[14], + namep[29]); + error_str = errbuf; + free(namep); + return (ret); + } + namep[14] = '\0'; /* mark off start time */ + namep[29] = '\0'; /* mark off finish time */ + if (derive_date(namep, &tme)) { + (void) strcat(errb, gettext("starting time-stamp invalid - ")); + (void) strcat(errb, error_str); + (void) strcpy(errbuf, errb); + error_str = errbuf; + free(namep); + return (ret); + } + /* + * Keep start time from filename. Use it to order files in + * the file list. Later we will update this when we read + * the first record from the file. + */ + fcb->fcb_start = tm_to_secs(&tme); + + if (strcmp(&namep[15], "not_terminated") == 0) { + fcb->fcb_end = MAXLONG; /* forever */ + /* + * Only treat a 'not_terminated' file as such if + * it is not on the command line. + */ + if (do_check == TRUE) + fcb->fcb_flags |= FF_NOTTERM; + } else if (derive_date(&namep[15], &tme)) { + (void) strcat(errb, gettext("ending time-stamp invalid - ")); + (void) strcat(errb, error_str); + (void) strcpy(errbuf, errb); + error_str = errbuf; + free(namep); + return (ret); + } else { + fcb->fcb_end = tm_to_secs(&tme); + } + fcb->fcb_name = slp; + fcb->fcb_suffix = &slp[30]; + free(namep); + return (0); +} + + +/* + * .func get_next_pcb - get a pcb to use. + * .desc The pcb's in the array audit_pcbs are used to hold single file + * groups in the form of a linked list. Each pcb holds files that + * are tied together by a common suffix in the file name. Here we + * get either 1. the existing pcb holding a specified sufix or + * 2. a new pcb if we can't find an existing one. + * .call pcb = get_next_pcb(suffix). + * .arg suffix - ptr to suffix we are seeking. + * .ret pcb - ptr to pcb that hold s the sought suffix. + * .ret NULL- serious failure in memory allocation. Quit processing. + */ +audit_pcb_t * +get_next_pcb(char *suffix) +{ + int i = 0; + int zerosize; + unsigned int size; + audit_pcb_t *pcb; + + /* Search through (maybe) entire array. */ + while (i < pcbsize) { + pcb = &audit_pcbs[i++]; + if (pcb->pcb_first == NULL) { + proc_pcb(pcb, suffix, i); + return (pcb); /* came to an unused one */ + } + if (suffix) { + if (strcmp(pcb->pcb_suffix, suffix) == 0) + return (pcb); /* matched one with suffix */ + } + } + /* + * Uh-oh, the entire array is used and we haven't gotten one yet. + * Allocate a bigger array. + */ + pcbsize += PCB_INC; + size = pcbsize * sizeof (audit_pcb_t); + zerosize = size - ((pcbsize - PCB_INC) * sizeof (audit_pcb_t)); + if ((audit_pcbs = (audit_pcb_t *)realloc((char *)audit_pcbs, size)) == + NULL) { + (void) sprintf(errbuf, + gettext("%s memory reallocation failed (%d bytes)"), ar, + size); + perror(errbuf); + audit_stats(); /* give user statistics on usage */ + return (NULL); /* really bad thing to have happen */ + } + /* + * Don't know if realloc clears the new memory like calloc would. + */ + (void) memset((void *) & audit_pcbs[pcbsize-PCB_INC], 0, + (size_t)zerosize); + pcb = &audit_pcbs[pcbsize-PCB_INC]; /* allocate the first new one */ + proc_pcb(pcb, suffix, pcbsize - PCB_INC); + return (pcb); +} + + +/* + * .func proc_pcb - process pcb. + * .desc Common pcb processing for above routine. + * .call proc_pcb(pcb, suffix, i). + * .arg pcb - ptr to pcb. + * .arg suffix - prt to suffix tha t ties this group together. + * .arg i - index into audit_pcbs[ ]. + * .ret void. + */ +void +proc_pcb(audit_pcb_t *pcb, char *suffix, int i) +{ + if (suffix) + pcb->pcb_suffix = suffix; + pcbnum++; /* one more pcb in use */ + pcb->pcb_size = AUDITBUFSIZE; + pcb->pcb_rec = (char *)a_calloc(1, AUDITBUFSIZE); + pcb->pcb_time = -1; + pcb->pcb_flags |= PF_FILE; /* note this one controls files */ + pcb->pcb_procno = i; /* save index into audit_pcbs [] for id */ +} + + +#ifdef TSOL +/* + * .func proc_slabel - process sensitivity label range argument. + * .desc Parse sensitivity label range sl:sl + * .call ret = proc_slabel(optstr). + * .arg opstr - ptr to label range string + * .ret 0 - no errors detected. + * .ret -1 - errors detected or not Trusted Solaris (error_str set). + */ + +int +proc_slabel(char *optstr) +{ + char *p; + int error; + + if (flags & M_SLABEL) { + error_str = gettext("'s' option specified multiple times"); + return (-1); + } + + flags |= M_SLABEL; + p = strchr(optstr, ':'); + if (p == NULL) { + /* exact label match, lower and upper range bounds the same */ + if (stobsl(optstr, &m_slabel.lower_bound, NO_CORRECTION, + &error) == 0) { + (void) sprintf(errbuf, + gettext("invalid sensitivity label (%s) err %d"), + optstr, error); + error_str = errbuf; + return (-1); + } + m_slabel.upper_bound = m_slabel.lower_bound; + return (0); + } + if (p == optstr) { + /* lower bound is not specified .. default is admin_low */ + bsllow(&m_slabel.lower_bound); + if (stobsl(p + 1, &m_slabel.upper_bound, NO_CORRECTION, + &error) == 0) { + (void) sprintf(errbuf, + gettext("invalid sensitivity label (%s) err %d"), + p + 1, error); + error_str = errbuf; + return (-1); + } + return (0); + } + *p++ = '\0'; + if (stobsl(optstr, &m_slabel.lower_bound, NO_CORRECTION, &error) == 0) { + (void) sprintf(errbuf, + gettext("invalid sensitivity label (%s) err %d"), optstr, + error); + error_str = errbuf; + return (-1); + } + if (*p == '\0') + /* upper bound is not specified .. default is admin_high */ + bslhigh(&m_slabel.upper_bound); + else { + if (stobsl(p, &m_slabel.upper_bound, NO_CORRECTION, &error) == + 0) { + (void) sprintf(errbuf, + gettext("invalid sensitivity label (%s) err %d"), + p, error); + error_str = errbuf; + return (-1); + } + } + /* make sure that upper bound dominates the lower bound */ + if (!bldominates(&m_slabel.upper_bound, &m_slabel.lower_bound)) { + *--p = ':'; + (void) sprintf(errbuf, + gettext("invalid sensitivity label range (%s)"), optstr); + error_str = errbuf; + return (-1); + } + return (0); +} +#endif /* !TSOL */ + +/* + * proc_zonename - pick up zone name. + * + * all non-empty and not-too-long strings are valid since any name + * may be valid. + * + * ret 0: non-empty string + * ret -1: empty string or string is too long. + */ +static int +proc_zonename(char *optstr) +{ + size_t length = strlen(optstr); + if ((length < 1) || (length > ZONENAME_MAX)) { + (void) sprintf(errbuf, + gettext("invalid zone name: %s"), optstr); + error_str = errbuf; + return (-1); + } + zonename = strdup(optstr); + flags |= M_ZONENAME; + return (0); +} 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); +} diff --git a/usr/src/cmd/auditreduce/regex2.c b/usr/src/cmd/auditreduce/regex2.c new file mode 100644 index 0000000000..06ec9319f6 --- /dev/null +++ b/usr/src/cmd/auditreduce/regex2.c @@ -0,0 +1,143 @@ +/* + * 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 1993,1998,2001-2002 Sun Microsystems, Inc. + * All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Extend regular expression matching for the file objects to allow + * multiple regular expressions (instead of just 1), and to not select + * regular expressions starting with a "~". This will allow adminstrator + * to exclude uninteresting files from the audit trail. + */ + +#include <stdlib.h> +#include <string.h> +#include <libgen.h> + +struct exp { + char *s; /* The regular is expression */ + int not; /* Exclude if matched? */ + char *comp; /* The compiled regular expression */ +}; + +static char SEP = ','; /* separator used between reg exprs */ +static char NOT = '~'; /* Character used to exclude rex exprs */ +static int compile = 1; /* Must we compile the expressions */ + +static char *fexp = NULL; /* full list of regular expressions */ +static int nexp = 1; /* number of regular expressions in fexp */ +static struct exp *p_exp = NULL; /* list of individual expressions */ + +char * +re_comp2(s) + char *s; +{ + char *p; + int i; + static char *er = "regcmp: error"; + + compile = 1; + if (p_exp != NULL) { + for (i = 0; i < nexp; i++) + if (p_exp[i].comp != NULL) + free(p_exp[i].comp); + free(p_exp); + } + if (fexp != NULL) { + free(fexp); + } + fexp = strdup(s); + for (p = fexp, nexp = 1; *p != '\0'; p++) { + if (*p == SEP) { + nexp++; + } + } + p_exp = (struct exp *)malloc(nexp * sizeof (struct exp)); + for (i = 0, p = fexp; *p != '\0'; i++) { + p_exp[i].comp = NULL; + if (*p == NOT) { + p++; + p_exp[i].not = 1; + } else { + p_exp[i].not = 0; + } + p_exp[i].s = p; + while (*p != SEP && *p != '\0') + p++; + if (*p == SEP) { + *p = '\0'; + p++; + } + if (regcmp(p_exp[i].s, NULL) == NULL) + return (er); + } + return (NULL); +} + +int +re_exec2(s) + char *s; +{ + int i; + char *ret; + + if (compile) { + for (i = 0; i < nexp; i++) { + if ((p_exp[i].comp = regcmp(p_exp[i].s, NULL)) == NULL) + return (-1); + } + compile = 0; + } + for (i = 0; i < nexp; i++) { + ret = regex(p_exp[i].comp, s); + if (ret != NULL) { + return (!p_exp[i].not); + } + } + + /* no match and no more to check */ + return (0); + +} + +#ifdef DEBUG +re_debug_print() +{ + int i; + + if (p_exp == NULL) { + (void) printf("Expression is NULL\n"); + return; + } + for (i = 0; i < nexp; i++) { + (void) printf("exp #%d:", i+1); + if (p_exp[i].not) + (void) putchar('~'); + (void) printf("%s\n", p_exp[i].s); + } +} +#endif /* DEBUG */ diff --git a/usr/src/cmd/auditreduce/time.c b/usr/src/cmd/auditreduce/time.c new file mode 100644 index 0000000000..1852868308 --- /dev/null +++ b/usr/src/cmd/auditreduce/time.c @@ -0,0 +1,496 @@ +/* + * 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 (c) 1987-2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Time management functions for auditreduce. + */ + +#include "auditr.h" +#include <locale.h> +#include <libintl.h> + +int derive_date(char *, struct tm *); +void derive_str(time_t, char *); +int parse_time(char *, int); +time_t tm_to_secs(struct tm *); + +static int check_time(struct tm *); +static int days_in_year(int); +static char *do_invalid(void); +static time_t local_to_gm(struct tm *); + +static char *invalid_inter = NULL; + +/* + * Array of days per month. + */ +static int days_month[] = { + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + +char * +do_invalid(void) +{ + if (invalid_inter == NULL) + invalid_inter = gettext("invalid date/time format -"); + return (invalid_inter); +} + +/* + * .func local_to_gm - local time to gm time. + * .desc Convert a local time to Greenwhich Mean Time. + * The local time is in the struct tm (time.h) format, which + * is easily got from an ASCII input format (10:30:33 Jan 3, 1983). + * It works by assuming that the given local time is a GMT time and + * then asking the system for the corresponding local time. It then + * takes the difference between those two as the correction for + * time zones and daylight savings time. This is accurate unless + * the time the user asked for is near a DST switch. Then a + * correction is applied - it is assumed that if we can produce + * a GMT that, when run through localtime(), is equivalent to the + * user's original input, we have an accurate GMT. The applied + * correction simply adjusts the GMT by the amount that the derived + * localtime was off. See? + * It should be noted that when there is DST there is one local hour + * a year when time occurs twice (in the fall) and one local hour a + * year when time never occurs (in the spring). + * memcpy() is used because the calls to gmtime() and localtime() + * return pointers to static structures that are overwritten at each + * call. + * .call ret = local_to_gm(tme). + * .arg tme - ptr to struct tm (see time.h) containing local time. + * .ret time_t - seconds since epoch of equivalent GMT. + */ +time_t +local_to_gm(struct tm *tme) +{ + time_t secs, gsecs, lsecs, save_gsecs; + time_t r1secs, r2secs; + struct tm ltime, gtime; + + /* + * Get the input time in local and gmtime assuming the input + * was GMT (which it probably wasn't). + */ + r1secs = secs = tm_to_secs(tme); + (void) memcpy((void *)>ime, (void *)gmtime(&secs), sizeof (gtime)); + (void) memcpy((void *)<ime, (void *)localtime(&secs), sizeof (ltime)); + + /* + * Get the local and gmtime in seconds, from the above tm structures. + * Calculate difference between local and GMT. + */ + gsecs = tm_to_secs(>ime); + lsecs = tm_to_secs(<ime); + secs = lsecs - gsecs; + gsecs -= secs; + (void) memcpy((void *)<ime, (void *)localtime(&gsecs), + sizeof (ltime)); + + /* + * Now get a computed local time from the computed gmtime. + */ + save_gsecs = gsecs; + r2secs = tm_to_secs(<ime); + + /* + * If the user given local time is != computed local time then + * we need to try a correction. + */ + if (r1secs != r2secs) { + /* + * Use the difference between give localtime and computed + * localtime as our correction. + */ + if (r2secs > r1secs) { + gsecs -= r2secs - r1secs; + } else { + gsecs += r1secs - r2secs; + } + /* + * And try the comparison again... + */ + (void) memcpy((void *)<ime, (void *)localtime(&gsecs), + sizeof (ltime)); + r2secs = tm_to_secs(<ime); + /* + * If the correction fails then we are on a DST line + * and the user-given local time never happened. + * Do the best we can. + */ + if (r1secs != r2secs) { + gsecs = save_gsecs; + } + } + return (gsecs); +} + + +/* + * .func tm_to_secs - convert to seconds. + * .desc Convert a tm time structure (time.h) into seconds since + * Jan 1, 1970 00:00:00. The time is assumed to be GMT and + * so no daylight savings time correction is applied. That + * is left up to the system calls (localtime(), gmtime()). + * .call ret = tm_to_secs(tme). + * .arg tme - ptr to tm structure. + * .ret time_t - number of seconds. + */ +time_t +tm_to_secs(struct tm *tme) +{ + int leap_year = FALSE; + int days = 0; + time_t num_sec = 0; + + int sec = tme->tm_sec; + int min = tme->tm_min; + int hour = tme->tm_hour; + int day = tme->tm_mday; + int month = tme->tm_mon; + int year = tme->tm_year + 1900; + + if (days_in_year(year) == 366) + leap_year = TRUE; + + while (year > 1970) { + num_sec += days_in_year(--year) * 24 * 60 * 60; + } + while (month > 0) { + days = days_month[--month]; + if (leap_year && month == 1) { /* 1 is February */ + days++; + } + num_sec += days * 24 * 60 * 60; + } + num_sec += --day * 24 * 60 * 60; + num_sec += hour * 60 * 60; + num_sec += min * 60; + num_sec += sec; + + return (num_sec); +} + + +/* + * .func check_time - check tm structure. + * .desc Check the time in a tm structure to see if all of the fields + * are within range. + * .call err = check_time(tme). + * .arg tme - ptr to struct tm (see time.h). + * .ret 0 - time is ok. + * .ret -1 - time had a problem (description in error_str). + */ +int +check_time(struct tm *tme) +{ + error_str = NULL; + + if (tme->tm_sec < 0 || tme->tm_sec > 59) { + (void) sprintf(errbuf, + gettext("seconds out of range (%d)"), tme->tm_sec + 1); + error_str = errbuf; + } else if (tme->tm_min < 0 || tme->tm_min > 59) { + (void) sprintf(errbuf, + gettext("minutes out of range (%d)"), tme->tm_min + 1); + error_str = errbuf; + } else if (tme->tm_hour < 0 || tme->tm_hour > 23) { + (void) sprintf(errbuf, + gettext("hours out of range (%d)"), tme->tm_hour + 1); + error_str = errbuf; + } else if (tme->tm_mon < 0 || tme->tm_mon > 11) { + (void) sprintf(errbuf, + gettext("months out of range (%d)"), tme->tm_mon + 1); + error_str = errbuf; + } else if (tme->tm_year < 0) { + (void) sprintf(errbuf, + gettext("years out of range (%d)"), tme->tm_year); + error_str = errbuf; + } else if (tme->tm_mday < 1 || tme->tm_mday > days_month[tme->tm_mon]) { + if (!(days_in_year(tme->tm_year + 1900) == 366 && + tme->tm_mon == 1 && + tme->tm_mday == 29)) { /* leap year and February */ + (void) sprintf(errbuf, + gettext("days out of range (%d)"), tme->tm_mday); + error_str = errbuf; + } + } else if (tme->tm_wday < 0 || tme->tm_wday > 6) { + (void) sprintf(errbuf, + gettext("weekday out of range (%d)"), tme->tm_wday); + error_str = errbuf; + } else if (tme->tm_yday < 0 || tme->tm_yday > 365) { + (void) sprintf(errbuf, + gettext("day of year out of range (%d)"), tme->tm_yday); + error_str = errbuf; + } + + if (error_str == NULL) + return (0); + else + return (-1); +} + + +/* + * .func parse_time. + * .desc Parse a user time from the command line. The user time is assumed + * to be local time. + * Supported formats currently are: + * 1. +xt - where x is a number and t is a type. + * types are - 's' second, 'm' minute, 'h' hour, and 'd' day. + * 2. yymmdd - yyyymmdd. + * yymmddhh - yyyymmddhh. + * yymmddhhmm - yyyymmddhhmm. + * yymmddhhmmss - yyyymmddhhmmss. + * .call err = parse_time(str, opt). + * .arg str - ptr to user input string. + * .arg opt - time option being processed. + * .ret 0 - succesful. + * .ret -1 - failure (error message in error_str). + */ +int +parse_time(char *str, int opt) +{ + int ret, len, factor; + char *strxx; + long lnum; + struct tm thentime; + + len = strlen(str); + /* + * If the strlen < 6 then in the "-b +2d" type of format. + */ + if (len < 6) { + if (*str++ != '+') { + (void) sprintf(errbuf, gettext("%s needs '+' (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } + if (opt != 'b') { + (void) sprintf(errbuf, + gettext("%s only allowed with 'b' option (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } + if (m_after == 0) { + (void) sprintf(errbuf, + gettext("must have -a to use -b +nx form (%s)"), + str); + error_str = errbuf; + return (-1); + } + /* + * Find out what type of offset it is - 's' 'm' 'h' or 'd'. + * Make sure that the offset is all numbers. + */ + if ((strxx = strpbrk(str, "dhms")) == NULL) { + (void) sprintf(errbuf, + gettext("%s needs 'd', 'h', 'm', or 's' (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } else { + ret = *strxx; + *strxx = '\0'; + } + if (strlen(str) != strspn(str, "0123456789")) { + (void) sprintf(errbuf, + gettext("%s non-numeric offset (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } + factor = 1; /* seconds is default */ + if (ret == 'd') /* days */ + factor = 24 * 60 * 60; + else if (ret == 'h') /* hours */ + factor = 60 * 60; + else if (ret == 'm') /* minutes */ + factor = 60; + lnum = atol(str); + m_before = m_after + (lnum * factor); + return (0); + } + /* + * Must be a specific date/time format. + */ + if (derive_date(str, &thentime)) + return (-1); + /* + * For 'd' option clear out the hh:mm:ss to get to the start of the day. + * Then add one day's worth of seconds to get the 'b' time. + */ + if (opt == 'd') { + thentime.tm_sec = 0; + thentime.tm_min = 0; + thentime.tm_hour = 0; + m_after = local_to_gm(&thentime); + m_before = m_after + (24 * 60 * 60); + } else if (opt == 'a') { + m_after = local_to_gm(&thentime); + } else if (opt == 'b') { + m_before = local_to_gm(&thentime); + } + return (0); +} + + +/* + * .func derive_date. + * .desc Derive a date/time structure (tm) from a string. + * String is in one of these formats: + * [yy]yymmddhhmmss + * [yy]yymmddhhmm + * [yy]yymmddhh + * [yy]yymmdd + * .call ret = derive_date(str, tme). + * .arg str - ptr to input string. + * .arg tme - ptr to tm structure (time.h). + * .ret 0 - no errors in string. + * .ret -1 - errors in string (description in error_str). + */ +int +derive_date(char *str, struct tm *tme) +{ + char *strs; + char *digits = "0123456789"; + size_t len; + struct tm nowtime; + + len = strlen(str); + + if (len != strspn(str, digits)) { + (void) sprintf(errbuf, gettext("%s not all digits (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } + if (len % 2) { + (void) sprintf(errbuf, gettext("%s odd number of digits (%s)"), + do_invalid(), str); + error_str = errbuf; + return (-1); + } + /* + * May need larger string storage to add '19' or '20'. + */ + strs = (char *)a_calloc(1, len + 4); + + /* + * Get current time to see what century it is. + */ + (void) memcpy((char *)&nowtime, (char *)gmtime(&time_now), + sizeof (nowtime)); + /* + * If the year does not begin with '19' or '20', then report + * an error and abort. + */ + if ((str[0] != '1' || str[1] != '9') && /* 19XX */ + (str[0] != '2' || str[1] != '0')) { /* 20XX */ + (void) sprintf(errbuf, gettext("invalid year (%c%c%c%c)"), + str[0], str[1], str[2], str[3]); + error_str = errbuf; + free(strs); + return (-1); + } + + len = strlen(str); /* may have changed */ + if (len < 8 || len > 14) { + (void) sprintf(errbuf, + gettext("invalid date/time length (%s)"), str); + error_str = errbuf; + free(strs); + return (-1); + } + /* unspecified values go to 0 */ + (void) memset((void *) tme, 0, (size_t)sizeof (*tme)); + (void) strncpy(strs, str, 4); + strs[4] = '\0'; + tme->tm_year = atoi(strs) - 1900; /* get the year */ + (void) strncpy(strs, str + 4, 2); + strs[2] = '\0'; + tme->tm_mon = atoi(strs) - 1; /* get months */ + (void) strncpy(strs, str + 6, 2); + strs[2] = '\0'; + tme->tm_mday = atoi(strs); /* get days */ + if (len >= 10) { /* yyyymmddhh */ + (void) strncpy(strs, str + 8, 2); + strs[2] = '\0'; + tme->tm_hour = atoi(strs); /* get hours */ + } + if (len >= 12) { /* yyyymmddhhmm */ + (void) strncpy(strs, str + 10, 2); + strs[2] = '\0'; + tme->tm_min = atoi(strs); /* get minutes */ + } + if (len >= 14) { /* yyyymmddhhmmss */ + (void) strncpy(strs, str + 12, 2); + strs[2] = '\0'; + tme->tm_sec = atoi(strs); /* get seconds */ + } + free(strs); + return (check_time(tme)); /* lastly check the ranges */ +} + + +/* + * .func derive_str - derive string. + * .desc Derive a string representation of a time for a filename. + * The output is in the 14 character format yyyymmddhhmmss. + * .call derive_str(clock, buf). + * .arg clock - seconds since epoch. + * .arg buf - place to put resultant string. + * .ret void. + */ +void +derive_str(time_t clock, char *buf) +{ + struct tm gtime; + + (void) memcpy((void *) & gtime, (void *)gmtime(&clock), sizeof (gtime)); + + (void) sprintf(buf, "%4d", gtime.tm_year + 1900); + (void) sprintf(buf + 4, "%.2d", gtime.tm_mon + 1); + (void) sprintf(buf + 6, "%.2d", gtime.tm_mday); + (void) sprintf(buf + 8, "%.2d", gtime.tm_hour); + (void) sprintf(buf + 10, "%.2d", gtime.tm_min); + (void) sprintf(buf + 12, "%.2d", gtime.tm_sec); + buf[14] = '\0'; +} + + +int +days_in_year(int year) +{ + if (isleap(year)) + return (366); + + return (365); +} diff --git a/usr/src/cmd/auditreduce/token.c b/usr/src/cmd/auditreduce/token.c new file mode 100644 index 0000000000..a9a6df9350 --- /dev/null +++ b/usr/src/cmd/auditreduce/token.c @@ -0,0 +1,1966 @@ +/* + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Token processing for auditreduce. + */ + +#include <locale.h> +#include <sys/zone.h> +#include "auditr.h" +#include "toktable.h" + +extern int re_exec2(char *); + +static void anchor_path(char *path); +static char *collapse_path(char *s); +static void get_string(adr_t *adr, char **p); +static int ipc_type_match(int flag, char type); +static void skip_string(adr_t *adr); +static int xgeneric(adr_t *adr); + +#if AUDIT_REC +void +print_id(int id) +{ + char *suffix; + + if ((id < 0) || (id > MAXTOKEN) || + (tokentable[id].func == NOFUNC)) { + (void) fprintf(stderr, + "token_processing: token %d not found\n", id); + return; + } + + switch (id) { + case AUT_NEWGROUPS: + suffix = "_new"; + break; + case AUT_ATTR32: + suffix = "32"; + break; + case AUT_ARG64: + case AUT_RETURN64: + case AUT_ATTR64: + case AUT_HEADER64: + case AUT_SUBJECT64: + case AUT_PROCESS64: + case AUT_OTHER_FILE64: + suffix = "64"; + break; + case AUT_SOCKET_EX: + case AUT_IN_ADDR_EX: + suffix = "_ex"; + break; + case AUT_HEADER32_EX: + case AUT_SUBJECT32_EX: + case AUT_PROCESS32_EX: + suffix = "32_ex"; + break; + case AUT_HEADER64_EX: + case AUT_SUBJECT64_EX: + case AUT_PROCESS64_EX: + suffix = "64_ex"; + break; + default: + suffix = ""; + break; + } + (void) fprintf(stderr, "token_processing: %s%s\n", + tokentable[id].t_name, suffix); +} +#endif /* AUDIT_REC */ + +/* + * Process a token in a record to determine whether the record is interesting. + */ + +int +token_processing(adr_t *adr, int tokenid) +{ + if ((tokenid > 0) && (tokenid <= MAXTOKEN) && + (tokentable[tokenid].func != NOFUNC)) { +#if AUDIT_REC + print_id(tokenid); +#endif /* AUDIT_REC */ + return ((*tokentable[tokenid].func)(adr)); + } + + /* here if token id is not in table */ + return (-2); +} + + +/* There should not be any file or header tokens in the middle of a record */ + +/* ARGSUSED */ +int +file_token(adr_t *adr) +{ + return (-2); +} + +/* ARGSUSED */ +int +file64_token(adr_t *adr) +{ + return (-2); +} + +/* ARGSUSED */ +int +header_token(adr_t *adr) +{ + return (-2); +} + +/* ARGSUSED */ +int +header32_ex_token(adr_t *adr) +{ + return (-2); +} + +/* ARGSUSED */ +int +header64_ex_token(adr_t *adr) +{ + return (-2); +} + +/* ARGSUSED */ +int +header64_token(adr_t *adr) +{ + return (-2); +} + + +/* + * ====================================================== + * The following token processing routines return + * -1: if the record is not interesting + * -2: if an error is found + * ====================================================== + */ + +int +trailer_token(adr_t *adr) +{ + short magic_number; + uint32_t bytes; + + adrm_u_short(adr, (ushort_t *)&magic_number, 1); + if (magic_number != AUT_TRAILER_MAGIC) { + (void) fprintf(stderr, "%s\n", + gettext("auditreduce: Bad trailer token")); + return (-2); + } + adrm_u_int32(adr, &bytes, 1); + + return (-1); +} + + +/* + * Format of arbitrary data token: + * arbitrary data token id adr char + * how to print adr_char + * basic unit adr_char + * unit count adr_char, specifying number of units of + * data items depends on basic unit + * + */ +int +arbitrary_data_token(adr_t *adr) +{ + int i; + char c1; + short c2; + int32_t c3; + int64_t c4; + char how_to_print, basic_unit, unit_count; + + /* get how_to_print, basic_unit, and unit_count */ + adrm_char(adr, &how_to_print, 1); + adrm_char(adr, &basic_unit, 1); + adrm_char(adr, &unit_count, 1); + for (i = 0; i < unit_count; i++) { + switch (basic_unit) { + /* case AUR_BYTE: has same value as AUR_CHAR */ + case AUR_CHAR: + adrm_char(adr, &c1, 1); + break; + case AUR_SHORT: + adrm_short(adr, &c2, 1); + break; + case AUR_INT32: + adrm_int32(adr, (int32_t *)&c3, 1); + break; + case AUR_INT64: + adrm_int64(adr, (int64_t *)&c4, 1); + break; + default: + return (-2); + break; + } + } + return (-1); +} + + +/* + * Format of opaque token: + * opaque token id adr_char + * size adr_short + * data adr_char, size times + * + */ +int +opaque_token(adr_t *adr) +{ + skip_string(adr); + return (-1); +} + + + +/* + * Format of return32 value token: + * return value token id adr_char + * error number adr_char + * return value adr_u_int32 + * + */ +int +return_value32_token(adr_t *adr) +{ + char errnum; + uint32_t value; + + adrm_char(adr, &errnum, 1); + adrm_u_int32(adr, &value, 1); + if ((flags & M_SORF) && + ((global_class & mask.am_success) && (errnum == 0)) || + ((global_class & mask.am_failure) && (errnum != 0))) { + checkflags |= M_SORF; + } + return (-1); +} + +/* + * Format of return64 value token: + * return value token id adr_char + * error number adr_char + * return value adr_u_int64 + * + */ +int +return_value64_token(adr_t *adr) +{ + char errnum; + uint64_t value; + + adrm_char(adr, &errnum, 1); + adrm_u_int64(adr, &value, 1); + if ((flags & M_SORF) && + ((global_class & mask.am_success) && (errnum == 0)) || + ((global_class & mask.am_failure) && (errnum != 0))) { + checkflags |= M_SORF; + } + return (-1); +} + + +/* + * Format of sequence token: + * sequence token id adr_char + * audit_count int32_t + * + */ +int +sequence_token(adr_t *adr) +{ + int32_t audit_count; + + adrm_int32(adr, &audit_count, 1); + return (-1); +} + + +/* + * Format of text token: + * text token id adr_char + * text adr_string + * + */ +int +text_token(adr_t *adr) +{ + skip_string(adr); + return (-1); +} + + +/* + * Format of ip_addr token: + * ip token id adr_char + * address adr_int32 + * + */ +int +ip_addr_token(adr_t *adr) +{ + int32_t address; + + adrm_char(adr, (char *)&address, 4); + + return (-1); +} + +/* + * Format of ip_addr_ex token: + * ip token id adr_char + * ip type adr_int32 + * address 4*adr_int32 + * + */ +int +ip_addr_ex_token(adr_t *adr) +{ + int32_t address[4]; + int32_t type; + + adrm_int32(adr, (int32_t *)&type, 1); + adrm_int32(adr, (int32_t *)&address, 4); + + return (-1); +} + +/* + * Format of ip token: + * ip header token id adr_char + * version adr_char + * type of service adr_char + * length adr_short + * id adr_u_short + * offset adr_u_short + * ttl adr_char + * protocol adr_char + * checksum adr_u_short + * source address adr_int32 + * destination address adr_int32 + * + */ +int +ip_token(adr_t *adr) +{ + char version; + char type; + short len; + unsigned short id, offset, checksum; + char ttl, protocol; + int32_t src, dest; + + adrm_char(adr, &version, 1); + adrm_char(adr, &type, 1); + adrm_short(adr, &len, 1); + adrm_u_short(adr, &id, 1); + adrm_u_short(adr, &offset, 1); + adrm_char(adr, &ttl, 1); + adrm_char(adr, &protocol, 1); + adrm_u_short(adr, &checksum, 1); + adrm_char(adr, (char *)&src, 4); + adrm_char(adr, (char *)&dest, 4); + + return (-1); +} + + +/* + * Format of iport token: + * ip port address token id adr_char + * port address adr_short + * + */ +int +iport_token(adr_t *adr) +{ + short address; + + adrm_short(adr, &address, 1); + + return (-1); +} + + +/* + * Format of groups token: + * group token id adr_char + * group list adr_int32, 16 times + * + */ +int +group_token(adr_t *adr) +{ + int gid[16]; + int i; + int flag = 0; + + for (i = 0; i < 16; i++) { + adrm_int32(adr, (int32_t *)&gid[i], 1); + if (flags & M_GROUPR) { + if ((unsigned short)m_groupr == gid[i]) + flag = 1; + } + } + + if (flags & M_GROUPR) { + if (flag) + checkflags |= M_GROUPR; + } + return (-1); +} + +/* + * Format of newgroups token: + * group token id adr_char + * number of groups adr_short + * group list adr_int32, "number" times + * + */ +int +newgroup_token(adr_t *adr) +{ + gid_t gid; + int i; + short int number; + + adrm_short(adr, &number, 1); + + for (i = 0; i < number; i++) { + adrm_int32(adr, (int32_t *)&gid, 1); + if (flags & M_GROUPR) { + if (m_groupr == gid) + checkflags |= M_GROUPR; + } + } + + return (-1); +} + +/* + * Format of argument32 token: + * argument token id adr_char + * argument number adr_char + * argument value adr_int32 + * argument description adr_string + * + */ +int +argument32_token(adr_t *adr) +{ + char arg_num; + int32_t arg_val; + + adrm_char(adr, &arg_num, 1); + adrm_int32(adr, &arg_val, 1); + skip_string(adr); + + return (-1); +} + +/* + * Format of argument64 token: + * argument token id adr_char + * argument number adr_char + * argument value adr_int64 + * argument description adr_string + * + */ +int +argument64_token(adr_t *adr) +{ + char arg_num; + int64_t arg_val; + + adrm_char(adr, &arg_num, 1); + adrm_int64(adr, &arg_val, 1); + skip_string(adr); + + return (-1); +} + +int +acl_token(adr_t *adr) +{ + + int32_t id; + int32_t mode; + int32_t type; + + adrm_int32(adr, &type, 1); + adrm_int32(adr, &id, 1); + adrm_int32(adr, &mode, 1); + + return (-1); +} + +/* + * Format of attribute token: (old pre SunOS 5.7 format) + * attribute token id adr_char + * mode adr_int32 (printed in octal) + * uid adr_int32 + * gid adr_int32 + * file system id adr_int32 + * node id adr_int32 + * device adr_int32 + * + */ +int +attribute_token(adr_t *adr) +{ + int32_t dev; + int32_t file_sysid; + int32_t gid; + int32_t mode; + int32_t nodeid; + int32_t uid; + + adrm_int32(adr, &mode, 1); + adrm_int32(adr, &uid, 1); + adrm_int32(adr, &gid, 1); + adrm_int32(adr, &file_sysid, 1); + adrm_int32(adr, &nodeid, 1); + adrm_int32(adr, &dev, 1); + + if (!new_mode && (flags & M_USERE)) { + if (m_usere == uid) + checkflags |= M_USERE; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == gid) + checkflags |= M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_FGROUP) && + (obj_group == gid)) + checkflags |= M_OBJECT; + else if ((obj_flag & OBJ_FOWNER) && + (obj_owner == uid)) + checkflags |= M_OBJECT; + } + return (-1); +} + +/* + * Format of attribute32 token: + * attribute token id adr_char + * mode adr_int32 (printed in octal) + * uid adr_int32 + * gid adr_int32 + * file system id adr_int32 + * node id adr_int64 + * device adr_int32 + * + */ +int +attribute32_token(adr_t *adr) +{ + int32_t dev; + int32_t file_sysid; + int32_t gid; + int32_t mode; + int64_t nodeid; + int32_t uid; + + adrm_int32(adr, &mode, 1); + adrm_int32(adr, &uid, 1); + adrm_int32(adr, &gid, 1); + adrm_int32(adr, &file_sysid, 1); + adrm_int64(adr, &nodeid, 1); + adrm_int32(adr, &dev, 1); + + if (!new_mode && (flags & M_USERE)) { + if (m_usere == uid) + checkflags |= M_USERE; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == gid) + checkflags |= M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_FGROUP) && + (obj_group == gid)) + checkflags |= M_OBJECT; + else if ((obj_flag & OBJ_FOWNER) && + (obj_owner == uid)) + checkflags |= M_OBJECT; + } + return (-1); +} + +/* + * Format of attribute64 token: + * attribute token id adr_char + * mode adr_int32 (printed in octal) + * uid adr_int32 + * gid adr_int32 + * file system id adr_int32 + * node id adr_int64 + * device adr_int64 + * + */ +int +attribute64_token(adr_t *adr) +{ + int64_t dev; + int32_t file_sysid; + int32_t gid; + int32_t mode; + int64_t nodeid; + int32_t uid; + + adrm_int32(adr, &mode, 1); + adrm_int32(adr, &uid, 1); + adrm_int32(adr, &gid, 1); + adrm_int32(adr, &file_sysid, 1); + adrm_int64(adr, &nodeid, 1); + adrm_int64(adr, &dev, 1); + + if (!new_mode && (flags & M_USERE)) { + if (m_usere == uid) + checkflags |= M_USERE; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == gid) + checkflags |= M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_FGROUP) && + (obj_group == gid)) + checkflags |= M_OBJECT; + else if ((obj_flag & OBJ_FOWNER) && + (obj_owner == uid)) + checkflags |= M_OBJECT; + } + return (-1); +} + + +/* + * Format of command token: + * attribute token id adr_char + * argc adr_short + * argv len adr_short variable amount of argv len + * argv text argv len and text + * . + * . + * . + * envp count adr_short variable amount of envp len + * envp len adr_short and text + * envp text envp len + * . + * . + * . + * + */ +int +cmd_token(adr_t *adr) +{ + short cnt; + short i; + + adrm_short(adr, &cnt, 1); + + for (i = 0; i < cnt; i++) + skip_string(adr); + + adrm_short(adr, &cnt, 1); + + for (i = 0; i < cnt; i++) + skip_string(adr); + + return (-1); +} + + +/* + * Format of exit token: + * attribute token id adr_char + * return value adr_int32 + * errno adr_int32 + * + */ +int +exit_token(adr_t *adr) +{ + int32_t retval; + int32_t errno; + + adrm_int32(adr, &retval, 1); + adrm_int32(adr, &errno, 1); + return (-1); +} + +/* + * Format of strings array token: + * token id adr_char + * count value adr_int32 + * strings null terminated strings + */ +static int +strings_common_token(adr_t *adr) +{ + int count, i; + char c; + + adrm_int32(adr, (int32_t *)&count, 1); + for (i = 1; i <= count; i++) { + adrm_char(adr, &c, 1); + while (c != (char)0) + adrm_char(adr, &c, 1); + } + /* no dump option here, since we will have variable length fields */ + return (-1); +} + +int +path_attr_token(adr_t *adr) +{ + return (strings_common_token(adr)); +} + +int +exec_args_token(adr_t *adr) +{ + return (strings_common_token(adr)); +} + +int +exec_env_token(adr_t *adr) +{ + return (strings_common_token(adr)); +} + +/* + * Format of liaison token: + */ +int +liaison_token(adr_t *adr) +{ + int32_t li; + + adrm_int32(adr, &li, 1); + return (-1); +} + + +/* + * Format of path token: + * path adr_string + */ +int +path_token(adr_t *adr) +{ + if ((flags & M_OBJECT) && (obj_flag == OBJ_PATH)) { + char *path; + + get_string(adr, &path); + if (path[0] != '/') + /* + * anchor the path. user apps may not do it. + */ + anchor_path(path); + /* + * match against the collapsed path. that is what user sees. + */ + if (re_exec2(collapse_path(path)) == 1) + checkflags |= M_OBJECT; + free(path); + } else { + skip_string(adr); + } + return (-1); +} + + +/* + * Format of System V IPC permission token: + * System V IPC permission token id adr_char + * uid adr_int32 + * gid adr_int32 + * cuid adr_int32 + * cgid adr_int32 + * mode adr_int32 + * seq adr_int32 + * key adr_int32 + * label adr_opaque, sizeof (bslabel_t) + * bytes + */ +int +s5_IPC_perm_token(adr_t *adr) +{ + int32_t uid, gid, cuid, cgid, mode, seq; + int32_t key; + + adrm_int32(adr, &uid, 1); + adrm_int32(adr, &gid, 1); + adrm_int32(adr, &cuid, 1); + adrm_int32(adr, &cgid, 1); + adrm_int32(adr, &mode, 1); + adrm_int32(adr, &seq, 1); + adrm_int32(adr, &key, 1); + + if (!new_mode && (flags & M_USERE)) { + if (m_usere == uid) + checkflags |= M_USERE; + } + + if (!new_mode && (flags & M_USERE)) { + if (m_usere == cuid) + checkflags |= M_USERE; + } + + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == gid) + checkflags |= M_GROUPR; + } + + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == cgid) + checkflags |= M_GROUPR; + } + + if ((flags & M_OBJECT) && + ((obj_owner == uid) || + (obj_owner == cuid) || + (obj_group == gid) || + (obj_group == cgid))) { + + switch (obj_flag) { + case OBJ_MSGGROUP: + case OBJ_MSGOWNER: + if (ipc_type_match(OBJ_MSG, ipc_type)) + checkflags |= M_OBJECT; + break; + case OBJ_SEMGROUP: + case OBJ_SEMOWNER: + if (ipc_type_match(OBJ_SEM, ipc_type)) + checkflags |= M_OBJECT; + break; + case OBJ_SHMGROUP: + case OBJ_SHMOWNER: + if (ipc_type_match(OBJ_SHM, ipc_type)) + checkflags |= M_OBJECT; + break; + } + } + return (-1); +} + + +/* + * Format of process32 token: + * process token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int32*2 + * + */ +int +process32_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int32_t port, machine; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int32(adr, &port, 1); + adrm_int32(adr, &machine, 1); + + if (!new_mode && (flags & M_USERA)) { + if (m_usera == auid) + checkflags |= M_USERA; + } + if (!new_mode && (flags & M_USERE)) { + if (m_usere == euid) + checkflags |= M_USERE; + } + if (!new_mode && (flags & M_USERR)) { + if (m_userr == ruid) + checkflags |= M_USERR; + } + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == rgid) + checkflags |= M_GROUPR; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == egid) + checkflags |= M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_PROC) && + (obj_id == pid)) { + checkflags |= M_OBJECT; + } else if ((obj_flag & OBJ_PGROUP) && + ((obj_group == egid) || + (obj_group == rgid))) { + checkflags |= M_OBJECT; + } else if ((obj_flag & OBJ_POWNER) && + ((obj_owner == euid) || + (obj_group == ruid))) { + checkflags |= M_OBJECT; + } + } + return (-1); +} + +/* + * Format of process32 token: + * process token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int32*6 + * + */ +int +process32_ex_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int32_t port, type, addr[4]; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int32(adr, &port, 1); + adrm_int32(adr, &type, 1); + adrm_int32(adr, &addr[0], 4); + + if (!new_mode && (flags & M_USERA)) { + if (m_usera == auid) + checkflags = checkflags | M_USERA; + } + if (!new_mode && (flags & M_USERE)) { + if (m_usere == euid) + checkflags = checkflags | M_USERE; + } + if (!new_mode && (flags & M_USERR)) { + if (m_userr == ruid) + checkflags = checkflags | M_USERR; + } + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == egid) + checkflags = checkflags | M_GROUPR; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == egid) + checkflags = checkflags | M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_PROC) && + (obj_id == pid)) { + checkflags = checkflags | M_OBJECT; + } else if ((obj_flag & OBJ_PGROUP) && + ((obj_group == egid) || + (obj_group == rgid))) { + checkflags = checkflags | M_OBJECT; + } else if ((obj_flag & OBJ_POWNER) && + ((obj_owner == euid) || + (obj_group == ruid))) { + checkflags = checkflags | M_OBJECT; + } + } + return (-1); +} + +/* + * Format of process64 token: + * process token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int64+adr_int32 + * + */ +int +process64_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int64_t port; + int32_t machine; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int64(adr, &port, 1); + adrm_int32(adr, &machine, 1); + + if (!new_mode && (flags & M_USERA)) { + if (m_usera == auid) + checkflags |= M_USERA; + } + if (!new_mode && (flags & M_USERE)) { + if (m_usere == euid) + checkflags |= M_USERE; + } + if (!new_mode && (flags & M_USERR)) { + if (m_userr == ruid) + checkflags |= M_USERR; + } + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == rgid) + checkflags |= M_GROUPR; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == egid) + checkflags |= M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_PROC) && + (obj_id == pid)) { + checkflags |= M_OBJECT; + } else if ((obj_flag & OBJ_PGROUP) && + ((obj_group == egid) || + (obj_group == rgid))) { + checkflags |= M_OBJECT; + } else if ((obj_flag & OBJ_POWNER) && + ((obj_owner == euid) || + (obj_group == ruid))) { + checkflags |= M_OBJECT; + } + } + return (-1); +} + +/* + * Format of process64 token: + * process token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int64+5*adr_int32 + * + */ +int +process64_ex_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int64_t port; + int32_t type, addr[4]; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int64(adr, &port, 1); + adrm_int32(adr, &type, 1); + adrm_int32(adr, &addr[0], 4); + + if (!new_mode && (flags & M_USERA)) { + if (m_usera == auid) + checkflags = checkflags | M_USERA; + } + if (!new_mode && (flags & M_USERE)) { + if (m_usere == euid) + checkflags = checkflags | M_USERE; + } + if (!new_mode && (flags & M_USERR)) { + if (m_userr == ruid) + checkflags = checkflags | M_USERR; + } + if (!new_mode && (flags & M_GROUPR)) { + if (m_groupr == egid) + checkflags = checkflags | M_GROUPR; + } + if (!new_mode && (flags & M_GROUPE)) { + if (m_groupe == egid) + checkflags = checkflags | M_GROUPE; + } + + if (flags & M_OBJECT) { + if ((obj_flag & OBJ_PROC) && + (obj_id == pid)) { + checkflags = checkflags | M_OBJECT; + } else if ((obj_flag & OBJ_PGROUP) && + ((obj_group == egid) || + (obj_group == rgid))) { + checkflags = checkflags | M_OBJECT; + } else if ((obj_flag & OBJ_POWNER) && + ((obj_owner == euid) || + (obj_group == ruid))) { + checkflags = checkflags | M_OBJECT; + } + } + return (-1); +} + +/* + * Format of System V IPC token: + * System V IPC token id adr_char + * object id adr_int32 + * + */ +int +s5_IPC_token(adr_t *adr) +{ + int32_t ipc_id; + + adrm_char(adr, &ipc_type, 1); /* Global */ + adrm_int32(adr, &ipc_id, 1); + + if ((flags & M_OBJECT) && + ipc_type_match(obj_flag, ipc_type) && + (obj_id == ipc_id)) + checkflags |= M_OBJECT; + + return (-1); +} + + +/* + * Format of socket token: + * socket_type adrm_short + * remote_port adrm_short + * remote_inaddr adrm_int32 + * + */ +int +socket_token(adr_t *adr) +{ + short socket_type; + short remote_port; + int32_t remote_inaddr; + + adrm_short(adr, &socket_type, 1); + adrm_short(adr, &remote_port, 1); + adrm_char(adr, (char *)&remote_inaddr, 4); + + if ((flags & M_OBJECT) && (obj_flag == OBJ_SOCK)) { + if (socket_flag == SOCKFLG_MACHINE) { + if (remote_inaddr == obj_id) + checkflags |= M_OBJECT; + } else if (socket_flag == SOCKFLG_PORT) { + if (remote_port == obj_id) + checkflags |= M_OBJECT; + } + } + return (-1); +} + + +/* + * Format of socket token: + * socket_type adrm_short + * remote_port adrm_short + * remote_inaddr adrm_int32 + * + */ +int +socket_ex_token(adr_t *adr) +{ + short socket_domain; + short socket_type; + short ip_size; + short local_port; + int32_t local_inaddr[4]; + short remote_port; + int32_t remote_inaddr[4]; + + adrm_short(adr, &socket_domain, 1); + adrm_short(adr, &socket_type, 1); + adrm_short(adr, &ip_size, 1); + + /* validate ip size */ + if ((ip_size != AU_IPv6) && (ip_size != AU_IPv4)) + return (0); + + adrm_short(adr, &local_port, 1); + adrm_char(adr, (char *)local_inaddr, ip_size); + + adrm_short(adr, &remote_port, 1); + adrm_char(adr, (char *)remote_inaddr, ip_size); + + /* if IP type mis-match, then nothing to do */ + if (ip_size != ip_type) + return (-1); + + if ((flags & M_OBJECT) && (obj_flag == OBJ_SOCK)) { + if (socket_flag == SOCKFLG_MACHINE) { + if (ip_type == AU_IPv4) { + if ((local_inaddr[0] == obj_id) || + (remote_inaddr[0] == obj_id)) + checkflags |= M_OBJECT; + } else { + if (((local_inaddr[0] == ip_ipv6[0]) && + (local_inaddr[1] == ip_ipv6[1]) && + (local_inaddr[2] == ip_ipv6[2]) && + (local_inaddr[3] == ip_ipv6[3])) || + ((remote_inaddr[0] == ip_ipv6[0]) && + (remote_inaddr[1] == ip_ipv6[1]) && + (remote_inaddr[2] == ip_ipv6[2]) && + (remote_inaddr[3] == ip_ipv6[3]))) + checkflags |= M_OBJECT; + } + } else if (socket_flag == SOCKFLG_PORT) { + if ((local_port == obj_id) || (remote_port == obj_id)) + checkflags |= M_OBJECT; + } + } + return (-1); +} + + +/* + * Format of subject32 token: + * subject token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int32*2 + * + */ +int +subject32_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int32_t port, machine; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int32(adr, &port, 1); + adrm_int32(adr, &machine, 1); + + if (flags & M_SUBJECT) { + if (subj_id == pid) + checkflags |= M_SUBJECT; + } + if (flags & M_USERA) { + if (m_usera == auid) + checkflags |= M_USERA; + } + if (flags & M_USERE) { + if (m_usere == euid) + checkflags |= M_USERE; + } + if (flags & M_USERR) { + if (m_userr == ruid) + checkflags |= M_USERR; + } + if (flags & M_GROUPR) { + if (m_groupr == rgid) + checkflags |= M_GROUPR; + } + if (flags & M_GROUPE) { + if (m_groupe == egid) + checkflags |= M_GROUPE; + } + return (-1); +} + +/* + * Format of subject32_ex token: + * subject token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid_addr adr_int32*6 + * + */ +int +subject32_ex_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int32_t port, type, addr[4]; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int32(adr, &port, 1); + adrm_int32(adr, &type, 1); + adrm_int32(adr, &addr[0], 4); + + if (flags & M_SUBJECT) { + if (subj_id == pid) + checkflags = checkflags | M_SUBJECT; + } + if (flags & M_USERA) { + if (m_usera == auid) + checkflags = checkflags | M_USERA; + } + if (flags & M_USERE) { + if (m_usere == euid) + checkflags = checkflags | M_USERE; + } + if (flags & M_USERR) { + if (m_userr == ruid) + checkflags = checkflags | M_USERR; + } + if (flags & M_GROUPR) { + if (m_groupr == egid) + checkflags = checkflags | M_GROUPR; + } + if (flags & M_GROUPE) { + if (m_groupe == egid) + checkflags = checkflags | M_GROUPE; + } + return (-1); +} + +/* + * Format of subject64 token: + * subject token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int64+adr_int32 + * + */ +int +subject64_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int64_t port; + int32_t machine; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int64(adr, &port, 1); + adrm_int32(adr, &machine, 1); + + if (flags & M_SUBJECT) { + if (subj_id == pid) + checkflags |= M_SUBJECT; + } + if (flags & M_USERA) { + if (m_usera == auid) + checkflags |= M_USERA; + } + if (flags & M_USERE) { + if (m_usere == euid) + checkflags |= M_USERE; + } + if (flags & M_USERR) { + if (m_userr == ruid) + checkflags |= M_USERR; + } + if (flags & M_GROUPR) { + if (m_groupr == rgid) + checkflags |= M_GROUPR; + } + if (flags & M_GROUPE) { + if (m_groupe == egid) + checkflags |= M_GROUPE; + } + return (-1); +} + +/* + * Format of subject64 token: + * subject token id adr_char + * auid adr_int32 + * euid adr_int32 + * egid adr_int32 + * ruid adr_int32 + * rgid adr_int32 + * pid adr_int32 + * sid adr_int32 + * termid adr_int64+5*adr_int32 + * + */ +int +subject64_ex_token(adr_t *adr) +{ + int32_t auid, euid, egid, ruid, rgid, pid; + int32_t sid; + int64_t port; + int32_t type, addr[4]; + + adrm_int32(adr, &auid, 1); + adrm_int32(adr, &euid, 1); + adrm_int32(adr, &egid, 1); + adrm_int32(adr, &ruid, 1); + adrm_int32(adr, &rgid, 1); + adrm_int32(adr, &pid, 1); + adrm_int32(adr, &sid, 1); + adrm_int64(adr, &port, 1); + adrm_int32(adr, &type, 1); + adrm_int32(adr, &addr[0], 4); + + if (flags & M_SUBJECT) { + if (subj_id == pid) + checkflags = checkflags | M_SUBJECT; + } + if (flags & M_USERA) { + if (m_usera == auid) + checkflags = checkflags | M_USERA; + } + if (flags & M_USERE) { + if (m_usere == euid) + checkflags = checkflags | M_USERE; + } + if (flags & M_USERR) { + if (m_userr == ruid) + checkflags = checkflags | M_USERR; + } + if (flags & M_GROUPR) { + if (m_groupr == egid) + checkflags = checkflags | M_GROUPR; + } + if (flags & M_GROUPE) { + if (m_groupe == egid) + checkflags = checkflags | M_GROUPE; + } + return (-1); +} + +/* + * ----------------------------------------------------------------------- + * tid_token(): Process tid token and display contents + * + * Format of tid token: + * tid token id adr_char + * address type adr_char + * For address type of AU_IPADR... + * remote port adr_short + * local port adr_short + * IP type adr_int32 + * IP addr adr_int32 if IPv4 + * IP addr 4 x adr_int32 if IPv6 + * address types other than AU_IPADR are not yet defined + * ----------------------------------------------------------------------- + */ +int +tid_token(adr_t *adr) +{ + int32_t address[4]; + int32_t ip_type; + char tid_type; + short rport; + short lport; + + adrm_char(adr, &tid_type, 1); + switch (tid_type) { + case AU_IPADR: + adrm_short(adr, &rport, 1); + adrm_short(adr, &lport, 1); + adrm_int32(adr, &ip_type, 1); + adrm_char(adr, (char *)&address, ip_type); + break; + default: + return (0); + } + return (-1); +} + +/* + * ----------------------------------------------------------------------- + * zonename_token(): Process zonename token and display contents + * + * Format of zonename token: + * zonename token id adr_char + * zone name adr_string + * ----------------------------------------------------------------------- + */ +int +zonename_token(adr_t *adr) +{ + char *name; + + if (flags & M_ZONENAME) { + get_string(adr, &name); + if (strncmp(zonename, name, ZONENAME_MAX) == 0) + checkflags |= M_ZONENAME; + free(name); + } else { + skip_string(adr); + } + return (-1); +} + +/* + * Format of xatom token: + */ +int +xatom_token(adr_t *adr) +{ + skip_string(adr); + + return (-1); +} + +/* + * Format of xselect token: + */ +int +xselect_token(adr_t *adr) +{ + skip_string(adr); + skip_string(adr); + skip_string(adr); + + return (-1); +} + +/* + * anchor a path name with a slash + * assume we have enough space + */ +void +anchor_path(char *path) +{ + (void) memmove((void *)(path + 1), (void *)path, strlen(path) + 1); + *path = '/'; +} + + +/* + * copy path to collapsed path. + * collapsed path does not contain: + * successive slashes + * instances of dot-slash + * instances of dot-dot-slash + * passed path must be anchored with a '/' + */ +char * +collapse_path(char *s) +{ + int id; /* index of where we are in destination string */ + int is; /* index of where we are in source string */ + int slashseen; /* have we seen a slash */ + int ls; /* length of source string */ + + ls = strlen(s) + 1; + + slashseen = 0; + for (is = 0, id = 0; is < ls; is++) { + /* thats all folks, we've reached the end of input */ + if (s[is] == '\0') { + if (id > 1 && s[id-1] == '/') { + --id; + } + s[id++] = '\0'; + break; + } + /* previous character was a / */ + if (slashseen) { + if (s[is] == '/') + continue; /* another slash, ignore it */ + } else if (s[is] == '/') { + /* we see a /, just copy it and try again */ + slashseen = 1; + s[id++] = '/'; + continue; + } + /* /./ seen */ + if (s[is] == '.' && s[is+1] == '/') { + is += 1; + continue; + } + /* XXX/. seen */ + if (s[is] == '.' && s[is+1] == '\0') { + if (id > 1) + id--; + continue; + } + /* XXX/.. seen */ + if (s[is] == '.' && s[is+1] == '.' && s[is+2] == '\0') { + is += 1; + if (id > 0) + id--; + while (id > 0 && s[--id] != '/'); + id++; + continue; + } + /* XXX/../ seen */ + if (s[is] == '.' && s[is+1] == '.' && s[is+2] == '/') { + is += 2; + if (id > 0) + id--; + while (id > 0 && s[--id] != '/'); + id++; + continue; + } + while (is < ls && (s[id++] = s[is++]) != '/'); + is--; + } + return (s); +} + + +int +ipc_type_match(int flag, char type) +{ + if (flag == OBJ_SEM && type == AT_IPC_SEM) + return (1); + + if (flag == OBJ_MSG && type == AT_IPC_MSG) + return (1); + + if (flag == OBJ_SHM && type == AT_IPC_SHM) + return (1); + + return (0); +} + + +void +skip_string(adr_t *adr) +{ + ushort_t c; + + adrm_u_short(adr, &c, 1); + adr->adr_now += c; +} + + +void +get_string(adr_t *adr, char **p) +{ + ushort_t c; + + adrm_u_short(adr, &c, 1); + *p = a_calloc(1, (size_t)c); + adrm_char(adr, *p, c); +} + + +/* + * Format of host token: + * host ard_uint32 + */ +int +host_token(adr_t *adr) +{ + uint32_t host; + + adrm_u_int32(adr, &host, 1); + + return (-1); +} + +/* + * Format of useofauth token: + * uauth token id adr_char + * uauth adr_string + * + */ +int +useofauth_token(adr_t *adr) +{ + skip_string(adr); + return (-1); +} + +int +xcolormap_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + +int +xcursor_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + +int +xfont_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + +int +xgc_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + +int +xpixmap_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + +int +xwindow_token(adr_t *adr) +{ + return (xgeneric(adr)); +} + + +/* + * Format of xgeneric token: + * XID adr_int32 + * creator UID adr_int32 + * + * Includes: xcolormap, xcursor, xfont, xgc, xpixmap, and xwindow + */ +int +xgeneric(adr_t *adr) +{ + int32_t xid; + int32_t uid; + + adrm_int32(adr, &xid, 1); + adrm_int32(adr, &uid, 1); + + if (flags & M_USERE) { + if (m_usere == uid) + checkflags = checkflags | M_USERE; + } + + return (-1); +} + + +/* + * Format of xproperty token: + * XID adr_int32 + * creator UID adr_int32 + * atom string adr_string + */ +int +xproperty_token(adr_t *adr) +{ + int32_t xid; + int32_t uid; + + adrm_int32(adr, &xid, 1); + adrm_int32(adr, &uid, 1); + skip_string(adr); + + if (flags & M_USERE) { + if (m_usere == uid) + checkflags = checkflags | M_USERE; + } + + return (-1); +} + + +/* + * Format of xclient token: + * xclient id adr_int32 + */ +int +xclient_token(adr_t *adr) +{ + int32_t client_id; + + adrm_int32(adr, &client_id, 1); + + return (-1); +} + +/* + * Format of clearance token: + * clearance adr_char*(sizeof (bclear_t)) + */ +#ifndef TSOL +/* ARGSUSED */ +#endif /* !TSOL */ +int +clearance_token(adr_t *adr) +{ +#ifdef TSOL + bclear_t clearance; + + adrm_char(adr, (char *)&clearance, sizeof (bclear_t)); + return (-1); +#else /* !TSOL */ + return (-2); +#endif /* TSOL */ +} + + +/* + * Format of ilabel token: + * ilabel adr_char*(sizeof (bilabel_t)) + */ +#ifndef TSOL +/* ARGSUSED */ +#endif /* !TSOL */ +int +ilabel_token(adr_t *adr) +{ +#ifdef TSOL + bilabel_t ilabel; + + adrm_char(adr, (char *)&ilabel, sizeof (ilabel)); + + return (-1); +#else /* !TSOL */ + return (-2); +#endif /* TSOL */ +} + +/* + * Format of privilege set token: + * priv_set type string + * priv_set string + */ + +int +privilege_token(adr_t *adr) +{ + skip_string(adr); /* set type name */ + skip_string(adr); /* privilege set */ + return (-1); +} + +/* + * Format of slabel token: + * slabel adr_char*(sizeof (bslabel_t)) + */ +#ifndef TSOL +/* ARGSUSED */ +#endif /* !TSOL */ +int +slabel_token(adr_t *adr) +{ +#ifdef TSOL + bslabel_t slabel; + + adrm_char(adr, (char *)&slabel, sizeof (slabel)); + + if (flags & M_SLABEL) { + if (blinrange(&slabel, &m_slabel)) + checkflags = checkflags | M_SLABEL; + } + + return (-1); +#else /* !TSOL */ + return (-2); +#endif /* TSOL */ +} + + +/* + * Format of useofpriv token: + * success/failure adr_char + * TSOL: + * privilege adr_int32 + * SOL: + * privilege(s) adr_string + */ +#ifndef TSOL +/* ARGSUSED */ +#endif /* !TSOL */ +int +useofpriv_token(adr_t *adr) +{ + char flag; + +#ifdef TSOL + priv_t priv; + + adrm_char(adr, &flag, 1); + adrm_int32(adr, (int32_t *)&priv, 1); + + return (-1); +#else /* !TSOL */ + + adrm_char(adr, &flag, 1); + skip_string(adr); + return (-1); +#endif /* TSOL */ +} |
