/*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
* auditwrite() - Construct and write user level records to the audit trail.
*/
/* Include common system files first */
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <strings.h>
#include <stdarg.h>
#include <syslog.h>
#include <stdio.h>
#include <thread.h>
#include <synch.h>
#include <bsm/audit_record.h>
#include "auditwrite.h"
#include <bsm/audit_uevents.h>
#include <priv.h>
/*
* invocation flags
*/
/* needs to be restored */
/*
* required attribute flags
* if these attributes are not included in the record, they are added
*/
#define AW_CTRLCMD_FLAGS \
/*
* AW_NOUSERDCMD - these cmds may not be used with AW_USERD on auditwrite call.
*/
#define AW_NOUSERDCMD_FLAGS \
#define AW_SUCCESS_RTN (0)
{ \
aw_set_err(error); \
aw_restore(); \
return (AW_ERR_RTN); \
} \
}
{ \
aw_set_err(error); \
aw_restore(); \
return (AW_ERR_RTN); \
}
/*
* Where control commands end and attribute commands begin.
*/
((cmd_num) < AW_CMD_CUTOFF)
((cmd_num) >= AW_CMD_CUTOFF)
/*
* Currently, AW_MAX_REC_SIZE applies to both audit(2). This
* auditctl(2) change. It's defined here because the kernel imposed maximum
* record size is not program visible.
*/
/*
* Number of record pointers to initially allocate
*/
/*
* A record descriptor that is not allocated.
*/
/*
* This is a fakeout for auditwrite. We don't have a
* auditctl(A_AUDIT), so we'll emulate this with existing
* functionality.
*/
struct aw_context {
};
int old_cur_rd;
/* Data structures used to account for and queue audit record buffers */
struct aw_rec {
};
/*
* Command table. Contains the command and the number of args that follow
* the command.
*
* If you add to the list, be aware that this is an array, and
* in indexed accordingly. I don't know why the cmd_number field
* was ever used.
*/
static struct {
int cmd_number;
int cmd_numargs;
} aw_cmd_table[] = {
{AW_END, 0},
/*
* Control commands. These control the behavior of auditwrite.
*/
{AW_ABORT, 0},
{AW_APPEND, 0},
{AW_DEFAULTRD, 0},
{AW_DISCARD, 0},
{AW_DISCARDRD, 1},
{AW_FLUSH, 0},
{AW_GETRD, 1},
{AW_NOPRESELECT, 0},
{AW_NOQUEUE, 0},
{AW_NOSAVE, 0},
{AW_NOSERVER, 0},
{AW_PRESELECT, 1},
{AW_QUEUE, 1},
{AW_SAVERD, 1},
{AW_SERVER, 0},
{AW_USERD, 1},
{AW_WRITE, 0},
{AW_END, 0}, /* Reserved for future use */
{AW_END, 0},
{AW_END, 0},
{AW_END, 0},
{AW_END, 0},
{AW_END, 0},
{AW_END, 0},
/*
* Attribute commands. These tell audiwrite how many attributes
* of data to expect.
*/
{AW_ACL, 0}, /* Don't support ACL's yet */
{AW_ARG, 3},
{AW_ATTR, 6},
{AW_DATA, 4},
{AW_EVENT, 1},
{AW_EVENTNUM, 1},
{AW_EXEC_ARGS, 1},
{AW_EXEC_ENV, 1},
{AW_EXIT, 2},
{AW_GROUPS, 2},
{AW_IN_ADDR, 1},
{AW_IPC, 2},
{AW_END, 0}, /* obsolete AW_IPC_PERM */
{AW_IPORT, 1},
{AW_OPAQUE, 2},
{AW_PATH, 1},
{AW_PROCESS, 8},
{AW_RETURN, 2},
{AW_SOCKET, 1},
{AW_SUBJECT, 8},
{AW_TEXT, 1},
{AW_UAUTH, 1},
{AW_CMD, 3},
{AW_END, 0}, /* Reserved for future use */
{AW_END, 0},
{AW_END, 0},
{AW_END, 0},
{AW_LEVEL, 1},
{AW_LIAISON, 1},
{AW_PRIVILEGE, 2},
{AW_SLABEL, 1},
{AW_USEOFPRIV, 2},
{AW_END, 0}, /* Reserved for future use */
{AW_END, 0},
{AW_END, 0},
{AW_XATOM, 1},
{AW_XCOLORMAP, 2},
{AW_XCURSOR, 2},
{AW_XFONT, 2},
{AW_XGC, 2},
{AW_END, /* OBS */ 0},
{AW_XPIXMAP, 2},
{AW_XPROPERTY, 3},
{AW_END, /* OBS */ 0},
{AW_XSELECT, 3},
{AW_XWINDOW, 2},
{AW_XCLIENT, 1},
{AW_PROCESS_EX, 8},
{AW_SUBJECT_EX, 8}
};
/* externally accessible data */
static char *aw_errlist[] = {
"No error",
"Address invalid",
"Memory allocation failure",
"auditon(2) failed",
"audit(2) failed",
"Command incomplete",
"Command invalid",
"Command in effect",
"Command not in effect",
"More than one control command specified",
"Event ID invalid",
"Event ID not set",
"getaudit(2) or getaudit_addr(2) failed",
"Queue size invalid",
"Record descriptor invalid",
"Record too big",
"No process label",
};
/* Data used by parsing routines and auditwrite */
/* used if invoker doesn't specify one */
/* every audit record */
/* of efficiency */
static void aw_abort(void);
static int aw_chk_addr(caddr_t p);
static int aw_chk_event_id(int rd);
static int aw_chk_print(char arg);
static int aw_chk_type(char arg);
static void aw_cleanup(void);
static char aw_cvrt_print(char arg);
static char aw_cvrt_type(char arg);
static int aw_do_subject(int rd);
static int aw_do_write(void);
static int aw_write_cleanup(void);
static void aw_queue_dealloc(void);
static int aw_queue_flush(void);
static int aw_queue_write(int rd);
static int aw_rec_alloc(int *rdp);
#ifdef NOTYET
#endif /* NOTYET */
static void aw_rec_dealloc(int rd);
static int aw_return_attrib(int rd);
static void aw_set_err(int error);
static int aw_init(void);
static void aw_restore(void);
static int aw_audit_write(int rd);
static int aw_auditctl_write(int rd);
#ifdef DEBUG
#endif
extern int cannot_audit(int);
/*
* a w _ g e t _ a r g s ( )
*
* Gets arguments off the stack;
*
*/
{ \
int i; \
\
for (i = 0; i < (numargs); i++) \
}
/*
* a w _ s k i p _ a r g ( )
*
* Skip args on the invocation line.
*
*/
{ \
int i; \
\
for (i = 0; i < (numskips); i++) \
}
/*
* a u d i t w r i t e ( )
*
* Construct and write user level audit records to the audit trail.
*
*/
/*VARARGS*/
int
{
register int i; /* counter */
/* Is auditing even enabled? If not, just exit */
if (cannot_audit(0) == 1)
/* Grab the lock */
(void) mutex_lock(&mutex_auditwrite);
#ifdef DEBUG
#endif /* DEBUG */
/*
* first time initialization stuff.
* get the preselection mask and the audit policy.
* allocate a default record buffer.
*/
if (aw_init() == AW_ERR_RTN) {
(void) mutex_unlock(&mutex_auditwrite);
return (AW_ERR_RTN);
}
/*
* set context, parse the invocation line and get the command.
*/
if (retval != AW_ERR_RTN) {
/* need to rewind the command line first... */
}
if (retval == AW_ERR_RTN) {
aw_abort();
aw_restore();
(void) mutex_unlock(&mutex_auditwrite);
return (AW_ERR_RTN);
}
#ifdef DEBUG
#endif /* DEBUG */
switch (aw_iflags & AW_NORMALCMD_FLAGS) {
case AW_WRITE_FLAG:
/*
* Preselect the record here.
* If we're not going to write it, no sense in constructing it.
*/
retval = aw_write_cleanup();
break;
}
if (aw_iflags & AW_ATTRIB_FLAG) {
break;
}
retval = aw_write_cleanup();
break;
case AW_APPEND_FLAG:
break;
break;
case AW_ABORT_FLAG:
aw_abort();
break;
case AW_DEFAULTRD_FLAG:
break;
case AW_DISCARD_FLAG:
/*
* deallocate all records
*/
for (i = 0; i < aw_num_recs; i++)
aw_rec_dealloc(i);
/*
* deallocate the queue
*/
/*
* save buffer is gone
*/
break;
case AW_DISCARDRD_FLAG:
break;
else {
}
/*
* special case - reallocate the default rd
* if user blows it away.
*/
== AW_ERR_RTN)
break;
}
/*
* if user blows away the current rd, set it back
* to the default
*/
}
break;
case AW_FLUSH_FLAG:
retval = aw_queue_flush();
break;
case AW_GETRD_FLAG:
break;
break;
case AW_NOQUEUE_FLAG:
break;
}
break;
case AW_NOPRESELECT_FLAG: {
/* Get the info from the proc */
retval = AW_ERR_RTN;
}
/* Stuff the real values in */
break;
}
case AW_NOSAVE_FLAG:
break;
case AW_NOSERVER_FLAG:
break;
case AW_PRESELECT_FLAG:
break;
case AW_QUEUE_FLAG:
break;
case AW_SAVERD_FLAG:
break;
/*
* SAVERD can be used by long-running processes
* (servers) to set-up context for a new "subject".
* Take the opportunity here to force a check of
* the event file on disk for any changes.
*/
/* XXXX refreshauevcache(); */
break;
case AW_SERVER_FLAG:
break;
default:
break;
}
if (retval == AW_ERR_RTN)
aw_abort();
/* Free up the lock */
(void) mutex_unlock(&mutex_auditwrite);
#ifdef DEBUG
#endif /* DEBUG */
aw_restore();
#ifdef DEBUG
#endif /* DEBUG */
return (retval);
}
/*
* a w _ a b o r t ( )
*
* Called when an an error occurs. Write any incomplete or buffered records.
*/
static void
aw_abort(void)
{
uint_t i;
/* Write queued or partial records */
if (aw_static_flags & AW_QUEUE_FLAG)
(void) aw_queue_flush();
else
for (i = 0; i < aw_num_recs; i++) {
(void) aw_audit_write(i);
}
}
aw_cleanup();
"aborted: aw_errno = %d = %s, errno = %d = %s",
(void) closelog();
}
/*
* Several programs, most noticably init(1M), have their own local
* copies of bcopy(3C), which take precedence over lib C's
* bcopy(3C) that we previously used here. memmove(3C) does the same
* thing, and doesn't have any name collisions...so far.
*/
/*
* a w _ b u f _ a p p e n d ( )
*
* Append some data from one buffer to another
*
*/
static int
{
if (l2 == 0)
return (AW_SUCCESS_RTN);
return (AW_SUCCESS_RTN);
}
== (caddr_t)0)
return (AW_SUCCESS_RTN);
}
/*
* a w _ b u f _ p r e p e n d ( )
*
* Prepend the contents of one buffer to another
*
*/
static int
{
if (l2 == 0)
return (AW_SUCCESS_RTN);
return (AW_SUCCESS_RTN);
}
== (caddr_t)0)
return (AW_SUCCESS_RTN);
}
/*
* a w _ c h k _ a d d r ( )
*
* Make sure address is within allowable boundaries. This is done to minimize
* core dumps (mostly SIGSEGV and SIGBUS) that can occur when a bad
* invocation line is passed.
*
*/
static int
{
/*
* if pointer is null, it's bogus
*/
if (p == (caddr_t)0)
return (AW_ERR_RTN);
return (AW_SUCCESS_RTN);
}
/*
* a w _ c h k _ e v e n t _ i d ( )
*
* Make sure event id is set.
*/
static int
{
return (AW_ERR_RTN);
return (AW_SUCCESS_RTN);
}
/*
* a w _ c h k _ p r i n t ( )
*
* Indicate validity of arbitrary data print arg.
*/
static int
{
switch (arg) {
case AWD_BINARY:
case AWD_OCTAL:
case AWD_DECIMAL:
case AWD_HEX:
case AWD_STRING:
return (AW_SUCCESS_RTN);
default:
return (AW_ERR_RTN);
}
/*NOTREACHED*/
}
/*
* a w _ c h k _ t y p e ( )
*
* Indicate validity of arbitrary data type arg.
*/
static int
{
switch (arg) {
case AWD_BYTE:
case AWD_CHAR:
case AWD_SHORT:
case AWD_INT:
case AWD_LONG:
case AWD_INT32:
case AWD_INT64:
return (AW_SUCCESS_RTN);
default:
return (AW_ERR_RTN);
}
/*NOTREACHED*/
}
/*
* a w _ c h k _ r d ( )
*
* Make sure record descriptor is valid
*/
static int
{
return (AW_SUCCESS_RTN);
}
/*
* a w _ c l e a n u p ( )
*
* Free all buffer space. Reset all static flags.
*
*/
static void
aw_cleanup(void)
{
int i;
/* Deallocate all audit records and record pointer array */
for (i = 0; i < aw_num_recs; i++) {
aw_rec_dealloc(i);
}
/* Deallocate audit record queue */
/* Reset flags */
}
/*
* a w _ c v r t _ p a t h ( )
*
* Get path ready for the audit trail by prepending the absolute root.
*/
static char
char **pathp) /* converted path */
{
int cmd;
if (path[0] == '/')
else
return (AW_SUCCESS_RTN);
}
/*
* a w _ c v r t _ t y p e ( )
*
* Convert arbitrary data print suggestions to token print suggestions.
*/
static char
{
switch (arg) {
case AWD_BINARY:
return (AUP_BINARY);
case AWD_OCTAL:
return (AUP_OCTAL);
case AWD_DECIMAL:
return (AUP_DECIMAL);
case AWD_HEX:
return (AUP_HEX);
case AWD_STRING:
return (AUP_STRING);
}
return ((char)~0);
}
/*
* a w _ c v r t _ t y p e ( )
*
* Convert arbitrary data type to token data type.
*/
static char
{
switch (arg) {
case AWD_BYTE:
return (AUR_BYTE);
case AWD_CHAR:
return (AUR_CHAR);
case AWD_SHORT:
return (AUR_SHORT);
case AWD_INT:
return (AUR_INT);
case AWD_LONG:
return (AUR_INT32);
case AWD_INT32:
return (AUR_INT32);
case AWD_INT64:
return (AUR_INT64);
}
return ((char)~0);
}
/*
* a w _ d o _ s u b j e c t ( )
*
* Check the audit policy and add any necessary attribs.
* The remaining policies such as seq and trailers are done by audit(2).
*/
static int
{
/*
* if the record does not contain a subject attribute
* prepend one now
*/
return (AW_SUCCESS_RTN);
/*
* Add the subject token using the values we have.
* Append them to the record under construction
*/
== (token_t *)0)
AW_ERR_RTN) {
return (AW_ERR_RTN);
}
/* Go grab the sensitivity label for this process */
/* Now output the SL */
return (AW_ERR_RTN);
}
/* Now add the groups */
if (audit_policies & AUDIT_GROUP) {
return (AW_ERR_RTN);
}
}
/*
* The sequence token is no longer required to be added by
* auditwrite(), it's added by BSM.
*/
return (AW_SUCCESS_RTN);
}
/*
* a w _ d o _ w r i t e ( )
*
* Write an audit record.
*/
static int
aw_do_write(void)
{
/*
* an attempt to write an audit record without an event id
* set is a serious error
*/
if (aw_static_flags & AW_SAVERD_FLAG) {
} else {
}
if (aw_static_flags & AW_SAVERD_FLAG)
return (AW_ERR_RTN);
/*
* if we are a server, we don't need to add subject and return
* attributes.
*/
if ((aw_static_flags & AW_SERVER_FLAG) == 0) {
return (AW_ERR_RTN);
}
/*
* Must add a return attribute in all cases if one
* has not already been added. this attribute denotes
*/
return (AW_ERR_RTN);
/* Now finish up by writing the header attribute */
return (AW_ERR_RTN);
/*
* if queueing is on write to the queue
*/
if (aw_static_flags & AW_QUEUE_FLAG)
return (aw_queue_write(cur_rd));
/*
* if we are a server, we need to use auditctl(2)
*/
if (aw_static_flags & AW_SERVER_FLAG)
return (aw_auditctl_write(cur_rd));
/*
* default case. we are not a server and we are not queueing.
*/
return (aw_audit_write(cur_rd));
}
static int
aw_write_cleanup(void)
{
}
/*
* If we are in context for a descriptor, now that the
* descriptor is gone we must clean up its save rd if any.
*/
}
return (AW_SUCCESS_RTN);
}
/*
* a w _ f r e e ( )
*
* Only free good addrs.
*/
static void
{
if (p != (caddr_t)0)
free((void *)p);
}
/*
* a w _ f r e e _ t o k ( )
*
* Free tokens.
*/
static void
{
}
/*
* a w _ g e n _ r e c ( )
*
* Traverse the invocation line again. This time grab all the record attributes,
* convert them to ADR format and append them to the current record buffer.
*/
static int
{
int a; /* invocation line argument */
a = param;
while (a != AW_END) {
if (AW_IS_CONTROL_CMD(a)) {
continue;
}
switch (a) {
case AW_ARG:
(char *)ad[1],
return (AW_ERR_RTN);
}
break;
case AW_ATTR: {
/*
* This is a bit of a hack. Rather than
* write a new au_to_attr() routine, we
* simply allocate a new vattr and stuff
* values in.
*/
return (AW_ERR_RTN);
}
break;
}
case AW_DATA:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_EVENT:
== (au_event_ent_t *)NULL)
else
break;
case AW_EVENTNUM:
if ((cacheauevent(&auevent,
else
break;
case AW_EXEC_ARGS:
if (!(audit_policies & AUDIT_ARGV))
break;
== (token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_EXEC_ENV:
if (!(audit_policies & AUDIT_ARGE))
break;
== (token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_EXIT:
return (AW_ERR_RTN);
}
break;
case AW_GROUPS:
if (!(audit_policies & AUDIT_GROUP))
break;
return (AW_ERR_RTN);
}
break;
case AW_IN_ADDR:
return (AW_ERR_RTN);
}
break;
case AW_IPC:
return (AW_ERR_RTN);
}
break;
case AW_IPORT:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_OPAQUE:
return (AW_ERR_RTN);
}
break;
case AW_PATH:
return (AW_ERR_RTN);
return (AW_ERR_RTN);
return (AW_ERR_RTN);
}
break;
case AW_PRIVILEGE:
return (AW_ERR_RTN);
}
break;
case AW_LEVEL:
case AW_SLABEL:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_PROCESS:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_PROCESS_EX:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_RETURN:
return (AW_ERR_RTN);
}
/*
*/
break;
#if 0
case AW_SOCKET:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
#endif
case AW_SUBJECT:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_SUBJECT_EX:
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_USEOFPRIV:
}
return (AW_ERR_RTN);
}
break;
case AW_TEXT:
if ((tokp = au_to_text((char *)
return (AW_ERR_RTN);
}
break;
case AW_UAUTH:
if ((tokp = au_to_uauth((char *)
return (AW_ERR_RTN);
}
break;
case AW_CMD: {
if (audit_policies & AUDIT_ARGE)
return (AW_ERR_RTN);
}
break;
}
case AW_XATOM:
== (token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_XCLIENT:
if ((tokp = au_to_xclient(
return (AW_ERR_RTN);
}
break;
case AW_XCURSOR:
if ((tokp = au_to_xcursor(
return (AW_ERR_RTN);
}
break;
case AW_XCOLORMAP:
if ((tokp = au_to_xcolormap(
return (AW_ERR_RTN);
}
break;
case AW_XFONT:
return (AW_ERR_RTN);
}
break;
case AW_XGC:
return (AW_ERR_RTN);
}
break;
case AW_XPIXMAP:
if ((tokp = au_to_xpixmap(
return (AW_ERR_RTN);
}
break;
case AW_XPROPERTY:
if ((tokp = au_to_xproperty(
(token_t *)0)
return (AW_ERR_RTN);
}
break;
case AW_XSELECT:
return (AW_ERR_RTN);
}
break;
case AW_XWINDOW:
if ((tokp = au_to_xwindow(
return (AW_ERR_RTN);
}
break;
default:
} /* switch */
} /* while */
return (AW_SUCCESS_RTN);
}
/*
* a w _ h e a d ( )
*
* Add a header to an audit record.
*
* Note that we no longer need to add a trailer in Solaris 2.x, as this
* is handled by the audit(2) system call.
*/
static int
{
/*
* Need to fix up the size correctly.
*/
return (AW_ERR_RTN);
}
return (AW_SUCCESS_RTN);
}
/*
* a w _ p a r s e ( )
*
* Parse the invocation line looking for invalid commands and invalid data
* (bad pointers).
*
* Returns AW_ERR_RTN when:
* more than one control command has been specified.
*
* Returns AW_SUCCESS_RTN upon success.
*/
static int
{
int a;
/*
* During the port from TS 2, we had to slightly reorg code, thus
* I'm simply going to continue to use the "a" variable.
*/
a = param;
while (a != AW_END) {
if (a < AW_CMD_MIN || a > AW_CMD_MAX)
/*
* EVENT attribute and RETURN attribute have preselection
* info. Need to gobble up that info here so that we can
* preselect without the overhead of record construction.
*/
if (AW_IS_DATA_CMD(a) &&
((a != AW_EVENT) && (a != AW_EVENTNUM)) &&
(a != AW_RETURN)) {
/* Reload with next value of "a" */
continue;
}
switch (a) {
/* AW_ABORT is not documented. It is used for debugging */
case AW_ABORT:
break;
case AW_APPEND:
break;
case AW_EVENT:
== (au_event_ent_t *)0)
else
break;
case AW_EVENTNUM:
if ((cacheauevent(&auevent,
else
break;
case AW_QUEUE:
if (aw_static_flags & AW_QUEUE_FLAG)
if (aw_queue_hiwater > AW_MAX_REC_SIZE ||
aw_queue_hiwater == 0)
break;
case AW_DEFAULTRD:
break;
case AW_DISCARD:
break;
case AW_DISCARDRD:
/*
* A specified rd of -1 here means that the
* default rd should be discarded.
*/
if (user_rd == -1)
break;
case AW_FLUSH:
if (!(aw_static_flags & AW_QUEUE_FLAG))
break;
case AW_GETRD:
break;
case AW_NOPRESELECT:
if (!(aw_static_flags & AW_PRESELECT_FLAG))
break;
case AW_NOQUEUE:
if (!(aw_static_flags & AW_QUEUE_FLAG))
aw_queue_hiwater = 0;
break;
case AW_NOSAVE:
if (!(aw_static_flags & AW_SAVERD_FLAG))
break;
case AW_NOSERVER:
if (!(aw_static_flags & AW_SERVER_FLAG))
break;
case AW_PRESELECT:
sizeof (au_mask_t));
}
break;
case AW_RETURN:
/*
*/
break;
case AW_SAVERD:
break;
case AW_SERVER:
break;
case AW_USERD:
/*
* Already handled a valid one in aw_set_context().
*/
break;
case AW_WRITE:
break;
default:
} /* switch */
/* Reload with the next value of "a" */
} /* while */
/* Must have a control command */
if (!(aw_iflags & AW_CTRLCMD_FLAGS))
/* Must be an attribute command with AW_APPEND control command */
if ((aw_iflags & AW_APPEND_FLAG) &&
!(aw_iflags & AW_ATTRIB_FLAG))
/*
* If there was an attribute command, need a control command to that
* tells what to do with the attributes.
*/
if ((aw_iflags & AW_ATTRIB_FLAG) &&
!((aw_iflags & AW_APPEND_FLAG) ||
(aw_iflags & AW_WRITE_FLAG)))
return (AW_SUCCESS_RTN);
}
/*
* a w _ p r e s e l e c t ( )
*
* Do user level audit preselection
*
* Returns:
* 1 - audit event is preselected
* 0 - audit event is not preselected
*/
static int
{
}
/*
* a w _ q u e u e _ d e a l l o c ( )
*
* Deallocate audit record queue.
*/
static void
aw_queue_dealloc(void)
{
aw_queue_bytes = 0;
}
/*
* a w _ q u e u e _ f l u s h ( )
*
* Flush audit record queue.
*/
static int
aw_queue_flush(void)
{
/* write all records on queue to trail */
if (aw_queue_bytes) {
aw_queue) == -1)
aw_queue_bytes = 0;
}
return (AW_SUCCESS_RTN);
}
/*
* a w _ q u e u e _ w r i t e ( )
*
* "Queue" an audit record. Actually, each record passed is appended to a
* buffer. This buffer eventually gets written with auditctl(2). Auditctl(2)
* will process the records in the order in which it receives them. This
* creates a "queueing" effect.
*/
static int
{
(void) aw_queue_flush();
return (AW_SUCCESS_RTN);
}
/* no queue? allocate it now. */
return (AW_ERR_RTN);
/* did we reach the hi-water mark? */
if (aw_queue_bytes >= aw_queue_hiwater)
if (aw_queue_flush() == AW_ERR_RTN)
return (AW_ERR_RTN);
return (AW_SUCCESS_RTN);
}
/*
* a w _ r e c _ i n i t ( )
*
* Init a rec area.
*
*/
static void
{
}
/*
* a w _ r e c _ a l l o c ( )
*
* Allocate a buffer to store an audit record.
*
*/
static int
{
int slot;
/* allocate the audit record buffer pointers */
/* allocate the record */
return (AW_ERR_RTN);
aw_rec_init(aw_recs[0]);
*rdp = 0;
return (AW_SUCCESS_RTN);
}
/* linear search to find the next open slot */
/* allocate the record */
return (AW_ERR_RTN);
return (AW_SUCCESS_RTN);
}
/* no open slots, allocate for another */
(aw_rec_t **)0)
/* allocate the record */
slot = aw_num_recs;
== (aw_rec_t *)0)
return (AW_ERR_RTN);
*rdp = aw_num_recs++;
return (AW_SUCCESS_RTN);
}
#ifdef NOTYET
/*
* a w _ r e c _ a p p e n d ( )
*
* Concatentate two previously allocated records.
*
*/
static int
{
}
}
#endif /* NOTYET */
/*
* a w _ r e c _ d e a l l o c ( )
*
* Deallocate a previously allocated audit record buffer.
*
*/
static void
{
/* free the audit record buffer */
return;
/* free the record */
}
/*
* a w _ r e c _ p r e p e n d ( )
*
* Prepend a record buffer with the contents of another record buffer.
*
*/
static int
{
}
static int
{
/*
* append a return token indicating a success event
*/
return (AW_ERR_RTN);
}
return (AW_SUCCESS_RTN);
}
/*
* a w _ s e t _ e r r ( )
*
* This routine sets aw_errno. It insures aw_errno is set
* once per invocation.
*/
static void
{
}
/*
* a w _ s e t _ e v e n t ( )
*
* Set event id and class.
*/
static void
{
}
/*
* a w _ i n i t ( )
*
* if this is the first invocation of auditwrite(3), do some setup
*/
static int
aw_init(void)
{
/*
* allocate a default audit record buf if we don't have one.
*/
}
/*
* current record buf was recently deallocated
* set it back to the default
*/
if (aw_static_flags & AW_INVOKED_BEFORE_FLAG) {
return (AW_SUCCESS_RTN);
}
/*
* First call setup
*
* Cache the preselection mask and the audit policies in order
* to reduce system call overhead. If they change, we will be
* auditing with stale values.
*/
/* Stuff the real values in */
return (AW_SUCCESS_RTN);
}
/*
* a w _ s e t _ c o n t e x t ( )
*
* set context as needed.
*/
static int
{
int a;
a = param;
/*
* If the input params start with USERD and after this there's
* anything besides AW_END, then we need to switch to the context
* for that record descriptor.
*/
if (a != AW_USERD)
return (AW_SUCCESS_RTN);
if (a != AW_END) {
/*
* USERD is used with another command.
* Save context first, then load context for the
* given rd.
*/
old_cur_rd = cur_rd;
/*
* Now load up our values.
*/
/* initialize as needed... */
if (aw_init() == AW_ERR_RTN) {
return (AW_ERR_RTN);
}
aw_iflags |= AW_SAVEDONE;
}
/*
* Finish basic USERD processing here.
*/
return (AW_SUCCESS_RTN);
}
/*
* a w _ r e s t o r e ( )
*
* restore context if needed.
*/
static void
aw_restore(void)
{
if (aw_iflags & AW_SAVEDONE) {
/*
* Save context for our rd first... If our rd is gone
* by now, we can't and won't need to do this part.
*/
if ((user_rd <= aw_num_recs) &&
}
/*
* Now restore the old values.
*/
cur_rd = old_cur_rd;
aw_iflags &= ~AW_SAVEDONE;
}
}
/*
* a w _ a u d i t _ w r i t e ( )
*
* Write an audit record to the audit trail using the audit(2) system call.
*/
static int
{
return (AW_SUCCESS_RTN);
}
/*
* a w _ a u d i t c t l _ w r i t e ( )
*
* Write an audit record to the audit trail using the auditctl(2) system call.
*/
static int
{
return (AW_SUCCESS_RTN);
}
#ifdef DEBUG
/*
* aw_debuglog: dump auditwrite parameters and current state
* to the debug file.
*
* General format of such an entry:
*
* xxx e pid= nnn stat-flags= xxxxxx aw_errno= n cur_rd= n
* dflt_rd= n save_rd= n arg1 arg2 ... arg11
*
* ...where:
* xxx = text, generally either "in" (auditwrite begin) or "out" (exit)
* e = auditwrite return value (significant only with "out")
* arg1, = auditwrite arguments (1st 11 only, whether used or not)
* arg2
* ...
*
*/
static int cntr = 0;
static void
{
void *a;
int i;
FILE *f;
if (f == NULL) {
return;
}
if (strcmp(s, "in ") == 0) {
cntr++;
}
(void) fprintf(f, "%9s ", s);
goto done;
/*
* Now dump in the arguments auditwrite was called with... Since
* the number of args is variable, just dump the first 10 or so
* (some of which may not actually have been passed).
*/
a = (void *)param;
for (i = 1; i <= 10; i++) {
(void) fprintf(f, "%d ", a);
}
done:
(void) fprintf(f, "\n");
(void) fclose(f);
}
#endif
/*
* aw_strerror: return the error string
*/
char *
{
return (aw_errlist[aw_errnum]);
else
return (NULL);
}
/*
* aw_geterrno: return the aw_errno for the given descriptor.
*/
int
{
int err;
(void) mutex_lock(&mutex_auditwrite);
(void) mutex_unlock(&mutex_auditwrite);
return (AW_ERR_RD_INVALID);
}
(void) mutex_unlock(&mutex_auditwrite);
return (err);
}
/*
* aw_perror_c: common internal routine to return the error string
*/
static void
{
char *c;
c = aw_errlist[err];
else
c = "Unknown error";
if (s && *s) {
}
}
/*
* aw_perror: return the error string
*/
void
aw_perror(const char *s)
{
aw_perror_c(aw_errno, s);
}
/*
* aw_perror_r: return the error string
*/
void
{
int err;
aw_perror_c(err, s);
}
/*
* Currently we are using Solaris 2.x BSM's audit mechanism,
* which doesn't have the large queue buffer mechanism. Rather
* than rewrite the system call, we'll simply emulate the large
* buffer write. If this gets to be problem in performance,
* we can readd the system call.
*/
static int
{
/* The only remaining option to auditctl is be A_AUDIT */
return (-1);
while (bytes_left > (uint32_t)0) {
/* Where to start parsing */
/* Make sure we have a header and output the record */
(bytes > bytes_left)) {
return (-1);
}
/* Use the audit(2) errno */
return (-1);
}
bytes_left -= bytes;
}
/* Last minute check to make sure we wrote out the exact number */
if (bytes_left != 0) {
return (-1);
}
return (0);
}