/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains the auditing system call code.
*
*/
#include <sys/pathname.h>
#include <sys/sysmacros.h>
#include <c2/audit_kernel.h>
#include <c2/audit_record.h>
#define HEADER_SIZE32 0;
static void au_output_thread();
/*
* This is the loadable module wrapper.
*/
/*
* Module linkage information for the kernel.
*/
&mod_miscops, "Solaris Auditing (C2)"
};
};
int
_init()
{
return (mod_install(&modlinkage));
}
int
_fini()
{
return (EBUSY);
}
int
{
}
/*
* The audit system call. Trust what the user has sent down and save it
* away in the audit file. User passes a complete audit record and its
* length. We will fill in the time stamp, check the header and the length
* Put a trailer and a sequence token if policy requires.
* In the future length might become size_t instead of an int.
*
* The call is valid whether or not AUDIT_PERZONE is set (think of
* login to a zone). When the local audit state (auk_auditstate) is
* AUC_INIT_AUDIT, records are accepted even though auditd isn't
* running.
*/
int
{
char c;
int count, l;
int host_len;
/* if auditing not enabled, then don't generate an audit record */
return (0);
/* Only privileged processes can audit */
if (secpolicy_audit_modify(CRED()) != 0)
return (EPERM);
/* Max user record size is 32K */
if (length > AUDIT_REC_SIZE)
return (E2BIG);
/*
* The specified length must be at least as big as the smallest
* possible header token. Later after beginning to scan the
* header we'll determine the true minimum length according to
* the header type and attributes.
*/
sizeof (char) + sizeof (short) + sizeof (short) + \
(sizeof (int32_t) * 2))
if (length < AU_MIN_HEADER_LEN)
return (EINVAL);
/* Read in user's audit record */
while (count) {
m = au_getclr();
if (!s)
s = n = m;
else {
n->next_buf = m;
n = m;
}
/* copyin failed release au_membuf */
au_free_rec(s);
return (EFAULT);
}
record += l;
count -= l;
}
/* Now attach the entire thing to ad */
/* validate header token type. trust everything following it */
(void) adr_getchar(&hadr, &c);
switch (c) {
case AUT_HEADER32:
/* size vers+event_ID+event_modifier fields */
break;
#ifdef _LP64
case AUT_HEADER64:
/* size vers+event_ID+event_modifier fields */
break;
#endif
case AUT_HEADER32_EX:
/*
* grab the host address type (length), then rewind.
* This is safe per the previous minimum length check.
*/
/* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */
break;
#ifdef _LP64
case AUT_HEADER64_EX:
/*
* the host address type (length), then rewind.
* This is safe per the previous minimum length check.
*/
/* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */
break;
#endif
default:
/* Header is wrong, reject message */
au_free_rec(s);
return (EINVAL);
}
au_free_rec(s);
return (0);
}
/* advance over header token length field */
/* validate version */
(void) adr_getchar(&hadr, &c);
if (c != TOKEN_VERSION) {
/* version is wrong, reject message */
au_free_rec(s);
return (EINVAL);
}
/* backup to header length field (including version field) */
/*
* add on the zonename token if policy AUDIT_ZONENAME is set
*/
if (zlen > 0) {
}
}
/* Add an (optional) sequence token. NULL offset if none */
/* get the sequnce token */
m = au_to_seq();
/* sequence token 5 bytes long */
length += 5;
/* link to audit record (i.e. don't pack the data) */
/* advance to count field of token */
} else
/* add the (optional) trailer token */
/* trailer token is 7 bytes long */
length += 7;
/* append to audit record */
}
/* audit record completely assembled. set the length */
/* We are done put it on the queue */
return (0);
}
/*
* auditdoor starts a kernel thread to generate output from the audit
* queue. The thread terminates when it detects auditing being turned
* off, such as when auditd exits with a SIGTERM. If a subsequent
* auditdoor arrives while the thread is running, the door descriptor
* of the last auditdoor in will be used for output. auditd is responsible
* for insuring that multiple copies are not running.
*/
int
{
int do_create = 0;
if (secpolicy_audit_config(CRED()) != 0)
return (EPERM);
return (EINVAL);
kctx = GET_KCTX_NGZ;
/*
* convert file pointer to file descriptor
* Note: fd ref count incremented here.
*/
return (EBADF);
}
"auditdoor() did not get the expected door descriptor\n");
return (EINVAL);
}
/*
* If the output thread is already running, then replace the
* door descriptor with the new one and continue; otherwise
* create the thread too. Since au_output_thread makes a call
* to au_doorio() which also does
* done after the unlock...
*/
if (!kctx->auk_output_active) {
do_create = 1;
}
if (do_create) {
}
return (0);
}
static void
{
return;
}
/*
* au_queue_kick -- wake up the output queue after delay ticks
*/
static void
{
/*
* wakeup reader if its not running and there is something
* to do. It also helps that kctx still be valid...
*/
return;
/* fire off timeout event to kick audit queue awake */
}
/*
* output thread
*
* this runs "forever" where "forever" means until either auk_auditstate
* changes from AUC_AUDITING or if the door descriptor becomes invalid.
*
* there is one thread per active zone if AUC_PERZONE is set. Since
* there is the possibility that a zone may go down without auditd
* terminating properly, a zone shutdown kills its au_output_thread()
* via taskq_destroy().
*/
static void
{
int error = 0;
/*
* Wait for work, until a signal arrives,
* or until auditing is disabled.
*/
while (!error) {
/* safety check. kick writer awake */
cv_broadcast(&(kctx->
}
au_resid);
goto output_exit;
}
}
/*
* au_doorio() calls au_door_upcall which holds
* auk_svc_lock; au_doorio empties the queue before
* returning.
*/
} else {
/* auditing turned off while we slept */
break;
}
}
kctx->auk_output_active = 0;
}