adt.c revision 85e8d33eda72d79b047f9f6d1d38e71c94352fdb
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. * 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 * 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. * return true if audit is enabled. "Enabled" is any state * other than AUC_DISABLED. * AUC_INIT_AUDIT -- c2audit queuing enabled. * AUC_AUDITING -- up and running * AUC_DISABLED -- no audit subsystem loaded * AUC_UNSET -- early boot state * AUC_NOAUDIT -- subsystem loaded, turned off via * AUC_NOSPACE -- up and running, but log partitions are full * For purpose of this API, anything but AUC_DISABLED or * AUC_UNSET is enabled; however one never actually sees * AUC_DISABLED since auditon returns EINVAL in that case. Any * auditon error is considered the same as EINVAL for our * purpose. auditstate is not changed by auditon if an error * 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 * 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 can take a parameter discussing the state. * The man page for getpwuid_r says the buffer must be big enough * or ERANGE will be returned, but offers no guidance for how big * the buffer should be or a way to calculate it. If you get * ERANGE, double pwd_buff's size. * This may be called even when auditing is off. * getpwuid_r returns NULL without setting * errno if the user does not exist; only * if the input is the wrong length does it * adt_get_unique_id -- generate a hopefully unique 32 bit value * there will be a follow up to replace this with the use of /dev/random * 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. unsigned char obuff[
128/
8];
while (
retval == 0) {
/* 0 is the only invalid result */ * 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 * The internal state structure for adt (adt_internal_state_t) uses * dev_t, so adt converts data from ucred to fit. The import/export * 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 * 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 * and back, however, it will have been split into major/minor * 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 /* ensure that auditstate is set */ * The imported state overwrites the initial state if the * imported state represents a valid audit trail DPRINTF((
"(%d) Starting session id = %08X\n",
* loads the event translation table into the audit session. * 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 * 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. * 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(). * 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 * The process audit characteristics are not changed by put, use * 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 * The process audit characteristics are not changed by put, use * helpers for adt_load_termid * 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. /* get peer name if its a socket, else assume local terminal */ * 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. /* see if resolution becomes available */ * getaddrinfo has failed to map the hostname * to an IP address, try to get an IP address * from a local interface. "failed, no Audit IP address available",
* 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 * If audit is off and the hostname lookup fails, no error is * returned, since an error may be interpreted by the caller * as grounds for denying a login. Otherwise the caller would * need to be aware of the audit state. * 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 * If audit is off and the ttyname lookup fails, no error is * returned, since an error may be interpreted by the caller * as grounds for denying a login. Otherwise the caller would * need to be aware of the audit state. * 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 * except leading 0's are suppressed, so a few bytes may /* length < 1 is a bug: the session data type may have changed */ * 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. /* no errors yet defined */ * adt_dup_session -- copy the session data * read from a network order buffer into struct adt_session_data return (0);
/* failed to match version */ p +=
offset;
/* point to next version # */ * Adjust buffer pointer to the first data item (euid). * if down rev version, neither pid nor label are included * in v1 ax_size_of_tsol_data intentionally ignored /* read in and deal with different sized labels. */ * read from struct adt_session_data into a network order buffer. * (network order 'cause this data may be shared with a remote host.) /* serialize the label */ * adt_import_proc() is used by a server acting on behalf * of a client which has connected via an ipc mechanism such as * Since the interface is via ucred, the info.ap_termid.port * value is always the 64 bit version. What is stored depends * on how libbsm is compiled. * ucred_getauid() returns AU_NOAUDITID if audit is off, which * is the right answer for adt_import_proc(). * Create a local context as near as possible. * yes, state is supposed to be free'd for both pass and fail * adt_ucred_label() -- if label is available, duplicate it. * adt_import() -- convert from network order to machine-specific order /* save local audit enabled 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 * If the remote failed to generate a terminal id, it is not * 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 * adt_init -- set session context by copying the audit characteristics * from the proc and picking up current uid/tid information. * By default, an audit session is based on the process; the default * is overriden by adt_set_user() * 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 return (-
1);
/* errno set by auditon */ * Copy the current session state to the process. If this function * is called, the model becomes a process model rather than a * 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. goto return_err;
/* errno set by setaudit_addr() */ /* Assume intending to audit as this process */ DPRINTF((
"changed mask to %08X/%08X for ruid=%d\n",
* adt_set_user -- see also adt_set_from_ucred() * ADT_NO_ATTRIB is a valid uid/gid meaning "not known" or * "unattributed." If ruid, change the model to session. * ADT_NO_CHANGE is a valid uid/gid meaning "do not change this value" * 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 * adt_set_user should be called even if auditing is not enabled * so that adt_export_session_data() will have useful stuff to * See the note preceding adt_set_proc() about the use of ADT_HAVE_TID /* avoid fooling pam_setcred()... */ * 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 * adt_alloc_event() returns a pointer to allocated memory * need to return a valid event pointer even if audit is * off, else the caller will end up either (1) keeping its * own flags for on/off or (2) writing to a NULL pointer. * If auditing is on, the session data must be valid; otherwise * preload data so the adt_au_*() functions can detect un-supplied * values (0 and NULL are free via calloc()). * adt_getXlateTable -- look up translation table address for event id * 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 * 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 * 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 * guaranteed by calloc/malloc. Arrays take special handling since * what matters for figuring out the correct alignment is the size /* adj for first entry */ * 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. * 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() * adt_put_event -- main event generation function. * The input "event" is the address of the struct containing * However if auditing is off or the session handle * is NULL, no attempt to write a record is made. /* if audit off or this is a broken session, exit */ * adt_free_event -- invalidate and free * adt_is_selected -- helper to adt_selected(), below. * "sorf" is "success or fail" status; au_preselect compares * that with success, fail, or both. * 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. return (
1);
/* default is "selected" */ * 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. * loopback always defined, * even if there is no real address * 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.