adt.c revision f89940742f5d14dde79b69b98a414dd7b7f585c7
/*
* 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
*/
/*
*/
#include <bsm/adt_event.h>
#include <assert.h>
#include <bsm/audit_record.h>
#include <door.h>
#include <errno.h>
#include <generic.h>
#include <md5.h>
#include <netdb.h>
#include <nss_dbdefs.h>
#include <pwd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <synch.h>
#include <sys/systeminfo.h>
#include <syslog.h>
#include <thread.h>
#include <unistd.h>
#include <adt_xlate.h>
#include <adt_ucred.h>
#include <libinetutil.h>
static int adt_init(adt_internal_state_t *, int);
static void adt_setto_unaudited(adt_internal_state_t *);
static int adt_get_local_address(int, struct ifaddrlist *);
#ifdef C2_DEBUG
#else
#define DPRINTF(x)
#define DFLUSH
#endif
/*
* Local audit states are a bit mask
*
* The global audit states are
*
* AUC_ENABLED 1 - loaded and enabled
*
* The local Zone states are
*
* AUC_AUDITING 0x1 - audit daemon is active
* AUC_NOAUDIT 0x2 - audit daemon is not active
* AUC_INIT_AUDIT 0x4 - audit is ready but auditd has not run
* AUC_NOSPACE 0x8 - audit enabled, no space for audit records
*
* The only values returned by auditon(A_GETCOND) are:
* AUC_INIT_AUDIT, AUC_AUDITING, AUC_NOAUDIT, AUC_NOSPACE
*
* The pseudo audit state used when the c2audit module is excluded is
*
* AUC_DISABLED 0x100 - c2audit module is excluded
*/
/*
* adt_write_syslog
*
* errors that are not the user's fault (bugs or whatever in
* the underlying audit code are noted in syslog.)
*
* Avoid calling adt_write_syslog for things that can happen
* at high volume.
*
* syslog's open (openlog) and close (closelog) are interesting;
* openlog *may* create a file descriptor and is optional. closelog
* *will* close any open file descriptors and is also optional.
*
* Since syslog may also be used by the calling application, the
* choice is to avoid openlog, which sets some otherwise useful
* parameters, and to embed "Solaris_audit" in the log message.
*/
void
{
int save_errno = errno;
int mask_priority;
(void) setlogmask(mask_priority);
errno = save_errno;
}
/*
* return true if c2audit is not excluded.
*
* For purpose of this API, anything but AUC_DISABLED
* is enabled; however one never actually sees
* AUC_DISABLED since auditon returns ENOTSUP in that case. Any
* auditon error is considered the same as ENOTSUP for our
* purpose. auditstate is not changed by auditon if an error
* is returned.
*/
/*
* XXX this should probably be eliminated and adt_audit_state() replace it.
* All the legitimate uses are to not fork a waiting process for
* process exit processing, as in su, login, dtlogin. Other bogus
* users are zoneadmd and init.
* All but dtlogin are in ON, so we can do this without cross gate
* synchronization.
*
* No longer used in adt.c.
*/
adt_audit_enabled(void)
{
return (auditstate != AUC_DISABLED);
}
/*
* See adt_audit_enabled() for state discussions.
* The state parameter is a hedge until all the uses become clear.
* Likely if adt_audit_enabled is brought internal to this file,
* it could be modified to take one or more parameters to describe the
* state.
*/
adt_audit_state(int states)
{
}
/*
* Get user_specific/non-attributable audit mask. This may be called even when
* auditing is off.
*/
static int
{
long buff_sz;
char *pwd_buff;
if (auditstate & AUC_DISABLED) {
/* c2audit excluded */
mask->am_success = 0;
mask->am_failure = 0;
adt_write_syslog("couldn't determine maximum size of "
"password buffer", errno);
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
return (0);
}
/*
* adt_get_unique_id -- generate a hopefully unique 32 bit value
*
*
* An MD5 hash is taken on a buffer of
* hostname . audit id . unix time . pid . count
*
* "count = noise++;" is subject to a race condition but I don't
* see a need to put a lock around it.
*/
{
char hostname[MAXHOSTNAMELEN];
union {
au_id_t v[4];
} output;
static int noise = 0;
}
while (retval == 0) { /* 0 is the only invalid result */
sizeof (pid_t));
}
return (retval);
}
/*
* the following "port" function deals with the following issues:
*
* 1 the kernel and ucred deal with a dev_t as a 64 bit value made
* up from a 32 bit major and 32 bit minor.
* 2 User space deals with a dev_t as either the above 64 bit value
* or a 32 bit value made from a 14 bit major and an 18 bit minor.
* 3 The various audit interfaces (except ucred) pass the 32 or
* 64 bit version depending the architecture of the userspace
* application. If you get a port value from ucred and pass it
* to the kernel via auditon(), it must be squeezed into a 32
* bit value because the kernel knows the userspace app's bit
* size.
*
* The internal state structure for adt (adt_internal_state_t) uses
* from 64 or 32 bit applications, so they always send 64 bits and
* the 32 bit end(s) are responsible to convert 32 -> 64 -> 32 as
* appropriate.
*/
/*
* adt_cpy_tid() -- if lib is 64 bit, just copy it (dev_t and port are
* both 64 bits). If lib is 32 bits, squeeze the two-int port into
* a 32 bit dev_t. A port fits in the "minor" part of au_port_t,
* so it isn't broken up into pieces. (When it goes to the kernel
* pieces.)
*/
static void
{
#ifdef _LP64
#else /* _LP64 */
#endif /* _LP64 */
}
/*
* adt_start_session -- create interface handle, create context
*
* The imported_state input is normally NULL, if not, it represents
* a continued session; its values obviate the need for a subsequent
* call to adt_set_user().
*
* The flag is used to decide how to set the initial state of the session.
* If 0, the session is "no audit" until a call to adt_set_user; if
* ADT_USE_PROC_DATA, the session is built from the process audit
* characteristics obtained from the kernel. If imported_state is
* not NULL, the resulting audit mask is an OR of the current process
* audit mask and that passed in.
*
* The basic model is that the caller can use the pointer returned
* by adt_start_session whether or not auditing is enabled or an
* error was returned. The functions that take the session handle
* as input generally return without doing anything if auditing is
* disabled.
*/
int
{
/* test and set auditstate */
if (adt_audit_state(AUC_DISABLED)) {
/* c2audit excluded */
*new_session = NULL;
return (0);
}
goto return_err;
}
goto return_err;
}
goto return_err_free; /* errno from adt_init() */
}
/*
* The imported state overwrites the initial state if the
* imported state represents a valid audit trail
*/
if (imported_state != NULL) {
goto return_err_free;
}
} else if (flags & ADT_USE_PROC_DATA) {
}
DPRINTF(("(%lld) Starting session id = %08X\n",
return (0);
*new_session = NULL;
return (-1);
}
/*
* adt_load_table()
*
* loads the event translation table into the audit session.
*/
void
{
}
}
/*
* adt_get_asid() and adt_set_asid()
*
* if you use this interface, you are responsible to insure that the
* rest of the session data is populated correctly before calling
* adt_proccess_attr()
*
* neither of these are intended for general use and will likely
* remain private interfaces for a long time. Forever is a long
* time. In the case of adt_set_asid(), you should have a very,
* very good reason for setting your own session id. The process
* audit characteristics are not changed by put, use adt_set_proc().
*
* These are "volatile" (more changable than "evolving") and will
* probably change in the S10 period.
*/
void
{
if (session_data == NULL) {
*asid = 0;
} else {
}
}
void
{
if (session_data != NULL) {
}
}
/*
* adt_get_auid() and adt_set_auid()
*
* neither of these are intended for general use and will likely
* remain private interfaces for a long time. Forever is a long
* time. In the case of adt_set_auid(), you should have a very,
* very good reason for setting your own audit id. The process
* audit characteristics are not changed by put, use adt_set_proc().
*/
void
{
if (session_data == NULL) {
*auid = AU_NOAUDITID;
} else {
}
}
void
{
if (session_data != NULL) {
}
}
/*
* adt_get_termid(), adt_set_termid()
*
* if you use this interface, you are responsible to insure that the
* rest of the session data is populated correctly before calling
* adt_proccess_attr()
*
* The process audit characteristics are not changed by put, use
* adt_set_proc().
*/
void
{
if (session_data == NULL) {
} else {
*termid =
}
}
void
const au_tid_addr_t *termid)
{
if (session_data != NULL) {
*termid;
}
}
/*
* adt_get_mask(), adt_set_mask()
*
* if you use this interface, you are responsible to insure that the
* rest of the session data is populated correctly before calling
* adt_proccess_attr()
*
* The process audit characteristics are not changed by put, use
* adt_set_proc().
*/
void
{
if (session_data == NULL) {
mask->am_success = 0;
mask->am_failure = 0;
} else {
}
}
void
{
if (session_data != NULL) {
}
}
/*
* helpers for adt_load_termid
*/
static void
{
}
static void
{
}
/*
* adt_load_termid: convenience function; inputs file handle and
* outputs an au_tid_addr struct.
*
* This code was stolen from audit_settid.c; it differs from audit_settid()
* in that it does not write the terminal id to the process.
*/
int
{
struct sockaddr_in6 peer;
struct sockaddr_in6 sock;
/* get peer name if its a socket, else assume local terminal */
< 0) {
}
goto return_err;
}
goto return_err;
}
/* get sock name */
goto return_err_free;
}
} else {
}
return (0);
return (-1);
}
static boolean_t
{
struct auditinfo_addr audit_data;
return (B_FALSE);
}
return (B_FALSE);
sizeof (au_tid_addr_t));
return (B_TRUE);
}
/*
* adt_get_hostIP - construct a terminal id from a hostname
*
* Returns 0 = success
* -1 = failure and errno = ENETDOWN with the address
* defaulted to IPv4 loopback.
*/
static int
{
int tries = 3;
char msg[512];
int eai_err;
while ((tries-- > 0) &&
/*
* getaddrinfo returns its own set of errors.
* Log them here, so any subsequent syslogs will
* have a context. adt_get_hostIP callers can only
* return errno, so subsequent syslogs may be lacking
* that getaddrinfo failed.
*/
adt_write_syslog(msg, 0);
break;
}
/* see if resolution becomes available */
(void) sleep(1);
}
/* LINTED */
AU_IPv4);
} else {
/* LINTED */
AU_IPv6);
}
return (0);
/*
* auditd is running so there should be a
* kernel audit context
*/
sizeof (audit_info)) < 0) {
adt_write_syslog("unable to get kernel audit context",
errno);
goto try_interface;
}
adt_write_syslog("setting Audit IP address to kernel", 0);
return (0);
}
{
struct ifaddrlist al;
int family;
char ntop[INET6_ADDRSTRLEN];
/*
* getaddrinfo has failed to map the hostname
* to an IP address, try to get an IP address
* from a local interface. If none up, default
* to loopback.
*/
adt_write_syslog("adt_get_local_address "
"failed, no Audit IP address available, "
"faking loopback and error",
errno);
AU_IPv4);
return (-1);
}
}
} else {
}
sizeof (ntop)));
adt_write_syslog(msg, 0);
return (0);
}
}
/*
* adt_load_hostname() is called when the caller does not have a file
* handle that gives access to the socket info or any other way to
* pass in both port and ip address. The hostname input is ignored if
* the terminal id has already been set; instead it returns the
* existing terminal id.
*
* If c2audit is excluded, success is returned.
* If the hostname lookup fails, the loopback address is assumed,
* errno is set to ENETDOWN, this allows the caller to interpret
* whether failure is fatal, and if not to have a address for the
* hostname.
* Otherwise the caller would need to be aware of the audit state.
*
* Other errors are ignored if not auditing.
*/
int
{
if (adt_audit_state(AUC_DISABLED)) {
/* c2audit excluded */
return (0);
}
goto return_err;
}
if (adt_have_termid(p_term)) {
return (0);
}
}
return (0);
} else {
return (-1);
}
if (auditstate & AUC_NOAUDIT) {
return (0);
}
return (-1);
}
/*
* adt_load_ttyname() is called when the caller does not have a file
* handle that gives access to the local terminal or any other way
* of determining the device id. The ttyname input is ignored if
* the terminal id has already been set; instead it returns the
* existing terminal id.
*
* If c2audit is excluded, success is returned.
* The local hostname is used for the local IP address.
* If that hostname lookup fails, the loopback address is assumed,
* errno is set to ENETDOWN, this allows the caller to interpret
* whether failure is fatal, and if not to have a address for the
* hostname.
* Otherwise the caller would need to be aware of the audit state.
*
* Other errors are ignored if not auditing.
*/
int
{
if (adt_audit_state(AUC_DISABLED)) {
/* c2audit excluded */
return (0);
}
goto return_err;
}
if (adt_have_termid(p_term)) {
return (0);
}
goto return_err_free; /* errno from sysinfo */
}
goto return_err_free;
}
}
return (0);
} else {
return (-1);
}
if (auditstate & AUC_NOAUDIT) {
return (0);
}
return (-1);
}
/*
* adt_get_session_id returns a stringified representation of
* the audit session id. See also adt_get_asid() for how to
* get the unexpurgated version. No guarantees as to how long
* the returned string will be or its general form; hex for now.
*
* An empty string is returned if auditing is off; length = 1
* and the pointer is valid.
*
* returns strlen + 1 if buffer is valid; else 0 and errno.
*/
{
/*
* output is 0x followed by
* two characters per byte
* plus terminator,
* except leading 0's are suppressed, so a few bytes may
* be unused.
*/
return (0);
}
**buff = '\0';
return (1);
}
/* length < 1 is a bug: the session data type may have changed */
return (length);
}
/*
* adt_end_session -- close handle, clear context
*
* if as_check is invalid, no harm, no foul, EXCEPT that this could
* be an attempt to free data already free'd, so output to syslog
* to help explain why the process cored dumped.
*/
int
{
if (session_data != NULL) {
} else {
}
}
/* no errors yet defined */
return (0);
}
/*
* adt_dup_session -- copy the session data
*/
int
{
int rc = 0;
if (dest_state == NULL) {
rc = -1;
goto return_rc;
}
sizeof (struct adt_internal_state));
source_state->as_label)) != 0) {
dest_state = NULL;
}
}
}
return (rc);
}
/*
* from_export_format()
* read from a network order buffer into struct adt_session_data
*/
static size_t
const adt_export_data_t *external)
{
struct export_header head;
struct export_link link;
char *p = (char *)external;
return (0);
}
/*
* Skip newer versions.
*/
while (version > PROTOCOL_VERSION_2) {
if (offset < 1) {
return (0); /* failed to match version */
}
p += offset; /* point to next version # */
return (0);
}
adrm_start(&context, p);
}
/*
* Adjust buffer pointer to the first data item (euid).
*/
if (p == (char *)external) {
} else {
}
/*
* if down rev version, neither pid nor label are included
* in v1 ax_size_of_tsol_data intentionally ignored
*/
if (version == PROTOCOL_VERSION_1) {
} else if (version == PROTOCOL_VERSION_2) {
if (label_len > 0) {
/* read in and deal with different sized labels. */
return (0);
}
if (label_len > my_label_len) {
return (0);
}
} else {
}
}
return (length);
}
/*
* adt_to_export_format
* read from struct adt_session_data into a network order buffer.
*
* (network order 'cause this data may be shared with a remote host.)
*/
static size_t
{
struct export_header head;
struct export_link tail;
label_len = blabel_size();
}
/* version 2 first */
sizeof (struct adt_export_v2) + label_len;
/* serialize the label */
}
/* now version 1 */
/* ignored in v1 */
/* finally terminator */
return (head.ax_buffer_length);
}
/*
* adt_ucred_label() -- if label is available, duplicate it.
*/
static m_label_t *
{
}
return (ul);
}
/*
* adt_import() -- convert from network order to machine-specific order
*/
static int
{
/* save local audit state */
return (-1); /* errno from adt_from_export_format */
/*
* If audit isn't enabled on the remote, they were unable
* to generate the audit mask, so generate it based on
* local configuration. If the user id has changed, the
* resulting mask may miss some subtleties that occurred
* on the remote system.
*
* If the remote failed to generate a terminal id, it is not
* recoverable.
*/
return (-1);
&mask))
return (-1);
}
}
return (0);
}
/*
* adt_export_session_data()
* copies a adt_session_data struct into a network order buffer
*
* In a misconfigured network, the local host may have auditing
* off while the destination may have auditing on, so if there
* is sufficient memory, a buffer will be returned even in the
* audit off case.
*/
{
length = blabel_size();
}
return (0);
goto return_length_free;
goto return_length_free;
}
} else {
}
return (length);
return (0);
}
static void
{
} else {
sizeof (au_tid_addr_t));
sizeof (au_mask_t));
state->as_have_user_data = 0;
}
}
/*
* adt_init -- set session context by copying the audit characteristics
*
* By default, an audit session is based on the process; the default
* is overriden by adt_set_user()
*/
static int
{
/* ensure auditstate is set */
(void) adt_audit_state(0);
if (use_proc_data) {
const au_tid64_addr_t *tid;
/*
* Even if the ucred is NULL, the underlying
* credential may have a valid terminal id; if the
* terminal id is set, then that's good enough. An
* example of where this matters is failed login,
* calling login; login does not load the credential
* since auth failed.
*/
if (!adt_have_termid(
return (-1);
} else {
} else {
return (-1);
}
tid);
} else {
return (-1);
}
}
}
} else {
}
sizeof (state->as_kernel_audit_policy))) {
return (-1); /* errno set by auditon */
}
&adt_preload);
return (0);
}
/*
* adt_set_proc
*
* Copy the current session state to the process. If this function
* is called, the model becomes a process model rather than a
* session model.
*
* In the current implementation, the value state->as_have_user_data
* must contain all of: ADT_HAVE_{AUID,MASK,TID,ASID}. These are all set
* by adt_set_user() when the ADT_SETTID or ADT_NEW flag is passed in.
*
*/
int
{
if (session_data == NULL) {
return (0);
}
(ADT_HAVE_ALL & ~ADT_HAVE_IDS)) {
goto return_err;
}
sizeof (auditinfo_addr_t)) < 0) {
goto return_err; /* errno set by setaudit_addr() */
}
return (0);
return (-1);
}
static int
{
if (ruid == ADT_NO_AUDIT) {
return (0);
}
return (-1);
/* Assume intending to audit as this process */
}
return (0);
}
static int
{
return (-1);
}
DPRINTF(("changed mask to %08X/%08X for ruid=%d\n",
ruid));
return (0);
}
/*
* adt_set_user -- see also adt_set_from_ucred()
*
* "unattributed." If ruid, change the model to session.
*
* only valid with ADT_UPDATE.
*
* ADT_NO_AUDIT is the external equivalent to AU_NOAUDITID -- there
* isn't a good reason to call adt_set_user() with it unless you don't
* have a good value yet and intend to replace it later; auid will be
* AU_NOAUDITID.
*
* adt_set_user should be called even if auditing is not enabled
* so that adt_export_session_data() will have useful stuff to
* work with.
*
* See the note preceding adt_set_proc() about the use of ADT_HAVE_TID
* and ADT_HAVE_ALL.
*/
int
enum adt_user_context user_context)
{
int rc;
return (0);
switch (user_context) {
case ADT_NEW:
return (-1);
}
(au_tid_addr_t *)termid)) != 0)
return (rc);
break;
case ADT_UPDATE:
return (-1);
}
if (ruid != ADT_NO_CHANGE)
return (rc);
break;
case ADT_USER:
return (-1);
}
break;
case ADT_SETTID:
/* avoid fooling pam_setcred()... */
return (0);
default:
return (-1);
}
if (ruid == ADT_NO_AUDIT) {
} else {
if (ruid != ADT_NO_CHANGE)
if (euid != ADT_NO_CHANGE)
if (rgid != ADT_NO_CHANGE)
if (egid != ADT_NO_CHANGE)
}
if (ruid == ADT_NO_ATTRIB) {
}
return (0);
}
/*
* adt_set_from_ucred()
*
* an alternate to adt_set_user that fills the same role but uses
* a pointer to a ucred rather than a list of id's. If the ucred
* pointer is NULL, use the credential from the this process.
*
* A key difference is that for ADT_NEW, adt_set_from_ucred() does
* not overwrite the asid and auid unless auid has not been set.
* ADT_NEW differs from ADT_UPDATE in that it does not OR together
* the incoming audit mask with the one that already exists.
*
* adt_set_from_ucred should be called even if auditing is not enabled
* so that adt_export_session_data() will have useful stuff to
* work with.
*/
int
enum adt_user_context user_context)
{
int rc = -1;
const au_tid64_addr_t *tid64;
return (0);
goto return_rc;
}
switch (user_context) {
case ADT_NEW:
} else {
}
rc = 0;
goto return_rc;
} else {
}
break;
case ADT_UPDATE:
goto return_rc;
}
goto return_rc;
break;
case ADT_USER:
goto return_rc;
}
break;
default:
goto return_rc;
}
rc = 0;
if (local_uc) {
}
return (rc);
}
/*
* adt_alloc_event() returns a pointer to allocated memory
*
*/
{
struct adt_event_state *event_state;
/*
* need to return a valid event pointer even if audit is
* off, else the caller will end up either (1) keeping its
* If auditing is on, the session data must be valid; otherwise
* we don't care.
*/
if (session_data != NULL) {
}
if (event_state == NULL)
goto return_ptr;
/*
* preload data so the adt_au_*() functions can detect un-supplied
* values (0 and NULL are free via calloc()).
*/
if (session_data != NULL) {
}
return (return_event);
}
/*
* adt_getXlateTable -- look up translation table address for event id
*/
static adt_translation_t *
{
/* xlate_table is global in adt_xlate.c */
return (p_event);
p_xlate++;
}
return (NULL);
}
/*
* adt_calcOffsets
*
* the call to this function is surrounded by a mutex.
*
* i walks down the table picking up next_token. j walks again to
* calculate the offset to the input data. k points to the next
* token's row. Finally, l, is used to sum the values in the
* datadef array.
*
* What's going on? The entry array is in the order of the input
* fields but the processing of array entries is in the order of
* the output (see next_token). Calculating the offset to the
* "next" input can't be done in the outer loop (i) since i doesn't
* point to the current entry and it can't be done with the k index
* because it doesn't represent the order of input fields.
*
* While the resulting algorithm is n**2, it is only done once per
* event type.
*/
/*
* adt_calcOffsets is only called once per event type, but it uses
* the address alignment of memory allocated for that event as if it
* were the same for all subsequently allocated memory. This is
* what matters for figuring out the correct alignment is the size
* of the array element.
*/
static void
{
int i, j;
void *struct_start = p_data;
for (i = 0; i < tablesize; i++) {
continue;
}
prev_size = 0;
for (j = 0; j < p_entry[i].en_count_types; j++) {
this_size = sizeof (enum adt_generic);
else
/* adj for first entry */
if (prev_size == 0)
} else {
}
}
}
}
/*
* adt_generate_event
* generate event record from external struct. The order is based on
* the output tokens, allowing for the possibility that the input data
* is in a different order.
*
*/
static int
struct adt_event_state *p_event,
{
/*
* offsets are not pre-calculated; the initial offsets are all
* 0; valid offsets are >= 0. Offsets for no-input tokens such
* as subject are set to -1 by adt_calcOffset()
*/
if (p_xlate->tx_offsetsCalculated == 0) {
(void) mutex_lock(&lock);
(void *)p_extdata);
(void) mutex_unlock(&lock);
}
}
return (adt_token_close(p_event));
}
/*
* adt_put_event -- main event generation function.
* The input "event" is the address of the struct containing
* event-specific data.
*
* However if auditing is off or the session handle
* is NULL, no attempt to write a record is made.
*/
int
{
struct adt_event_state *event_state;
return (-1);
}
/* if this is a broken session or not auditing, exit */
(AUC_AUDITING | AUC_NOSPACE))) {
return (0);
}
/* look up the event */
return (-1);
}
}
return (0);
}
/*
* adt_free_event -- invalidate and free
*/
void
{
struct adt_event_state *event_state;
return;
event_state->ae_check = 0;
}
/*
* adt_is_selected -- helper to adt_selected(), below.
*
* "sorf" is "success or fail" status; au_preselect compares
* that with success, fail, or both.
*/
static int
{
int prs_sorf;
if (sorf == 0)
else
}
/*
* selected -- see if this event is preselected.
*
* if errors are encountered trying to check a preselection mask
* or look up a user name, the event is selected. Otherwise, the
* preselection mask is used for the job.
*/
static int
{
return (1); /* default is "selected" */
}
/* non-attributable? */
sizeof (namask)) != 0) {
return (1);
}
} else {
status));
}
}
/*
* Can't map the host name to an IP address in
* adt_get_hostIP. Get something off an interface
* to act as the hosts IP address for auditing.
*/
static int
{
struct ifaddrlist *ifal;
int ifal_count;
int i;
return (-1);
}
for (i = 0; i < ifal_count; i++) {
/*
* loopback always defined,
* even if there is no real address
*/
break;
}
}
if (i >= ifal_count) {
/*
* Callers of adt_get_hostIP() can only return
* errno to their callers and eventually the application.
* Picked one that seemed least worse for saying no
* usable address for Audit terminal ID.
*/
return (-1);
}
return (0);
}