See http://jurassic.eng/~tpanero/audit/api/version/bsmAPI1.0.html for the HTML original of this text document.

Draft 1.0, February 27, 2001

A Threaded BSM Interface

Overview

The proposal is that this new interface be implemented as a contract private interface for SMC and SSH but designed to become a public interface to replace the current private BSM hooks used by login, su, inetd, and other user-space applications. The new interface, like the old, is intended to sit on top of the public (au_) BSM interface, which is neither appropriate for or used by current applications.

The new interface project makes no changes to the current kernel implementation of auditing or to the public au_* user-space interface. Administration and current utilities are also unchanged. New audit token types will be introduced that will require additions to the praudit (log display) command.

This document uses "SMC" to mean the set of administration consoles including SMC and WBEM and also the specific services available within those consoles. However, the API defined here has a larger scope than just support of SMC.

Threading

The existing public BSM interfaces (au_*) are thread safe. The existing private hooks are not thread safe; they were written to meet application-specific requirements which did not include threads and so managed to avoid the issue of threading until the advent of AdminSuite 3 (Seabreeze.)

While it is necessary to be thread safe, there is no dependence on a thread id by BSM; what BSM tracks is a session defined by a handle returned by adt_start_session(). A client session is tracked from before the client is authenticated to when the client connection is dropped.

The adt_start_session() function requires the caller to allocate an opaque data structure for the use of the API. As described in the next section, this data structure provides the mechanism for tracking a session across processes and hosts. The present BSM implementation pulls the audit characteristics from the process; adt_start_session() stores these in a thread-safe data structure instead.

There is an important limitation to work around: kernel auditing uses the audit characteristics stored in the proc structure to determine what audit records to generate and to complete the record header. For SMC, this is not an issue since the SMC process is not audited -- the service is spawned from init and inherits the audit characteristics that say "don't." The API defined here requires that one explicitly choose between a process model with user-space and kernel auditing or a thread model with user-space only auditing. This choice of model is made via the final parameter of the adt_session_attr() function.

Multi-Process, Multi-Host Sessions

For SMC, we must generate session ids that are unique to the network so that a session can be tracked across hosts. (In SMC for Solaris 8, all services are part of the SMC or WBEM process, but the SMC model includes the concept of servers in other processes or hosts.) In the current BSM implementation, a session id is generated when a user is authenticated and, presently, there is no mechanism to continue a session across processes.

As described for threading, above, an opaque data structure is allocated in the caller's data space; the caller must pass this structure to any separate processes. See adt_start_session() and adt_export_session_data() for how a session is started and continued. For each process which receives the opaque data, a new handle is generated via a call to adt_start_session(). In either case (use of the default from the process or use of passed parameters), audit records are generated using the uid/gid fields in the opaque structure.

"Impersonation" and "Acting on-behalf-of"

The terms "impersonation" and "acting on-behalf-of" are related but different. The AdminSuite 3 server acts on behalf of the client; it authenticates the client and does authorization based on the user's permissions. Rather than using setuid, it executes the requested function with the real and effect uid of root. Trusted Solaris provides audit support for the concept of "acting on-behalf-of:"

Extensibility

The problem of extensibility is

  1. How to provide for generation of new audit records.
  2. How to provide for changes to audit records.
  3. How to maintain data hiding / abstraction across the interface

The first pass at the BSM API will not be customer extensible, but the implementation will serve as a prototype for how to provide for creation and modification of audit event records. Briefly, the API interface is described with XML, the audit event records and their tokens are defined with XML, the XML is used to generate the API header file and a c file that contains a table used to map from the external definition to the actual event record formats.

Abstraction and Typing

The API must hide data: Any literal values passed across the API must be mapped by the implementation to the semantically equivalent internal data or structure.

The API provides abstraction at several levels:

The Trusted Solaris auditwrite() implementation also provides for generating a set of records for one event; this capability is not provided for in the proposed API. The current use of record-specific structures for data passing would need to be extended so that a single structure would provide the data needed for each record generated; it does not appear that any changes to the API would be needed to support this one event to many record concept.

The C API

General C Functions

The first group are used for both process-based applications such as login and session-based applications such as SMC. All in this group are intended to have Java wrappers.


session_data = adt_start_session(const char *service,
				const void *existing_state,
				const adt_session_flags_t flags);
Allocates the data structure to be used for this audit session. If the "imported_session" pointer is not NULL, copy in the client session data provided by the caller (and convert to host-specific data ordering).

The returned value, session_data, is NULL if auditing is off or if there is an error; the error is returned via errno (errno == ENOTACTIVE if auditing is off), which is set to zero for the auditing-off case. Otherwise, session_data points to the session data. It is ok to call all the other functions of the API with a NULL pointer - they will return without complaining -- and without doing anything else, either.

adt_start_session() uses audit id which are already set for the process. (See adt_process_attr() and adt_session_attr() for how the process characteristics are set and how they are overridden for a thread-based session.) The audit session id is returned for the caller to use as a client session id if desired. session_data points to an opaque data structure which contains the audit state information for the session, a workspace for record generation, and a workspace for client use (see adt_put_event().)

The service name is the same string as used for the PAM service name.

The flags value is initially unused for the base Solaris, but is defined for the future. Trusted Solaris will use this field to indicate that the underlying audit implementation should buffer record generation. (The implementation isolates token handling to the file adt_token.c; for Trusted Solaris this file is the place to integrate or layer Trusted Solaris extensions to audit handling such as X-windows buffering and and sensitivity labels.


session_id = adt_get_session_id(adt_session_data_t session_data);
adt_session_id() returns the audit session id for this session.

status = adt_end_session(adt_session_data_t session_data);
adt_end_session() frees the session data memory.

status = adt_session_attr(adt_session_data_t session_data,
	    uid_t euid,
	    gid_t egid,
	    uid_t ruid, 
	    gid_t rgid,
	    char * hostname,
            uint  port,
            enum adt_model model);

Sets thread-specific override values to those set for the process by adt_process_attr().

The hostname is used rather than a file handle because of the need to wrap this function with a Java method. Port should be set to 0 if it is not known or if the user is local.

"model" is either ADT_PROCESS_MODEL or ADT_SESSION_MODEL. The former is for applications such as login, SHH, and ftp and the latter is for applications such as SMC (Solaris Management Console) and the media server.


rc = adt_put_event(adt_event_t event_data,
              int exit_status,
              int exit_error);
event_data points to a structure specific to this event (obtained via a call to adt_alloc_event().) adt_put_event() generates the event's record, subject to preselection. The exit_status and exit_error are used in the event's exit token.

event = adt_alloc_event(adt_event_id_t event_id,
    adt_session_data_t session_data);

adt_alloc_event allocates and returns a pointer to a structure for the specific event record. It initializes a private piece of the structure to tie the event with the current session and record the event record type. Since the caller is not expected to maintain information about whether auditing is active, a structure is allocated even if auditing is inactive.

Each event has a structure defined in api.h


void adt_free_event(adt_event_data_t *event_data);
This frees the structure allocated by adt_alloc_event(). The structure is reusable; calling adt_put_event does not change the structure content. However, if the event structure contains pointers, the user is responsible for freeing the memory it points to; if the user passes static strings, s/he need not worry about adt_free_event() attempting to free them.

size = adt_export_session_data(void *external, adt_session_data_t internal,
			size_t max_size);
adt_export_session_data() makes a network-order copy of the session data (excluding the workspaces). "external_data" is a user-supplied buffer into which adt_export-session_data() will write no more than max_size bytes. This is the data block which is the optional "existing_state" input to adt_start_session().

Special Purpose C Functions

This second group are intended for use by process-based operations such as login, cron, and halt. We'll need to decide if there is any value in providing Java wrappers for these functions. None are needed for SMC.


status = adt_process_attr(adt_session_data_t session_data, int fh,
    enum adt_user_context_t user_context);
  

This function is intended for applications that have a login-like function, such as rlogind, ftpd, sshd and login; it commits the audit characteristics to the proc structure. (Actually, it commits them to system calls which presently store audit characteristics in proc.) This function is not intended for use by non-audited processes such as a multi-threaded administration server. See adt_session_attr().

adt_process_attr() sets the audit id for the process.

The audit preselection mask for uid uid is set for the current process. The values for user_context affect this as follows:

If uid is -1, then the preselection mask is not changed. Example -- rlogin and telnet need to set the terminal id before they exec login, i.e., before the uid is known.

The filehandle is for the local or remote connection. For a local log in, it is filehandle 0, for a remote login it is the socket handle. If filehandle is -1, the terminal id is not set. Note: This is not a data value that a Java wrapper can generate. If it is decided that a Java program need to do process login-like operations, we'll need a new interface. For the existing set of C applications, the use of the filehandle makes sense.


status = adt_set_stamp(adt_session_data_t session_data, char *path);
  
Not yet prototyped. This function is defined to satisfy the need for certain applications, such as cron and at, to store audit characteristics for future use. Initially, it will replace the BSM hooks that generate the *.au files one sees in the crontabs and at directories.

status = adt_get_stamp(adt_session_data_t session_data, char *path);
  
Not yet prototyped. This function is defined to satisfy the need for certain applications, such as cron and at, to store audit characteristics for future use. Initially, it will replace the BSM hooks that read the *.au files one sees in the crontabs and at directories.

status = adt_wait_audit(void);
  
Not yet prototyped. This function is defined to satisfy the need for certain applications, such as halt, uadmin, and reboot, to wait for the audit daemon to finish writing audit records. Otherwise, the halt operation can kill the audit daemon before it is done and the audit of halt is lost.

C Examples

  1. A login session start and end: adt_session_data_t ah; au_id_t session_id; adt_event_data_t *event; {... connection established with client ...} ah = adt_start_session("login", NULL, 0); {...complete successful authentication; fh is user device/socket ...} adt_process_attr(ah, fh, ADTUC_NEW); event = adt_alloc_event(AUE_login, ah); event->adt_login.message = ADT0_SUCCESS; adt_put_event(event, 0, 0); adt_free_event(event); {...continue process, with misc auditable events occurring...} {...logging out...} event = adt_alloc_event(AUE_logout, ah); adt_put_event(ah, event, 0, 0); adt_free_event(event); rc = adt_end_session(ah); ...
  2. Unsuccessful login to SMC: adt_session_data_t ah; adt_event_data_t *auth; ah = adt_start_session("SMC", NULL, 0); adt_session_attr(ah, -1, -1, -1, -1, "nishiki1", 24, ADT_SESSION_MODEL); /* -1 indicates invalid id */ auth = adt_alloc_event(AUE_admin_authenticate, ah); auth->adt_admin_authenticate.message = ADT0_SUCCESS; adt_put_event(auth, 0, 0); adt_free_event(auth); rc = adt_end_session(ah); ... For more examples, see the directory (on Jurassic) ~tpanero/proj/audit/api/src. The relevant files are: adt_xlateH.txt -- template for adt_xlate.h, used to generate audit records from the API-defined data structures. adtH.txt -- template for adt.h, which is the header file for the new API. adt_xlateC.txt -- template for adt_xlate.c, which is the tables used to generate audit records. adt.xml -- XML definition of the API. It is used to generate adt_xlate.h, adt_xlate.c and adt.h using the templates described above. adt_test.c -- a test program, still growing. Best place to mine for compiled, tested examples. adt.c -- the primary api interface. adt_token.c -- token-specific code.

Java Audit Service / JNI Support

Detailed Data Description

To do -- add Java method description to each. Remember "throws whatever" when appropriate.

Function Name
Data Item In/Out C type Java Type
adt_start_session()
return out adt_session_data_t * byte[]
exception on error
service name in const char * string
existing state in char * byte[]
flags in uint64 long
adt_get_session_id()
return out uint64_t long
exception on error
adt_end_session()
return out int void
exception on error
session data in adt_session_data_t * byte[]
adt_session_attr()
return out int int
exception on error
session data in adt_session_data_t * byte[]
effective uid in uid_t
int, if Intel or 64bit Sparc
long otherwise
int
effective gid in gid_t
same as above
int
real uid in uid_t
same as above
int
real gid in gid_t
same as above
int
host name in char * string
port number in unsigned int unsigned int
session data in adt_session_data_t * byte[]
model in enum adt_model none
event data in adt_event_data_t * byte[]
exit status in int int
exit error in int int
adt_alloc_event()
return out adt_event_data_t * byte[]
exception on error
session data in adt_session_data_t * byte[]
adt_export_session_data()
For the JNI, the return value is byte[] (external data)
return out size_t external data (byte[])
exception on error
external data out char * none
session data in adt_session_data_t * byte[]
max size in size_t
int
int
adt_process_attr(): No Java interface
adt_set_stamp(): No Java interface
adt_get_stamp(): No Java interface
adt_wait_audit(): No Java interface

Revisions

February 27, 2001  1.0 Changed service name to a string and removed it from the api header file. The service name is now defined to be the PAM service name. Removed incorrect speculation about future use of the cred structure. Added new section on the JNI interface. Modified the event() function so that more than one event object can be instantiated at one time. Modified adt_start_session() to remove the session id parameter and created adt_get_session_id() to replace it. This fits the Java model closer; also, most callers could care less what the session id i. This draft was submitted for PSARC inception.
November 14, 2000  0.5 Extended the discussion of threading to discuss the proc structure and future plans vis-a-vis the cred structure. Changed the title to match the one-pager's project name.
Sept 13, 2000  0.4 Added discussion of multi-process, multi-host audit sessions and modified the API to match. Moved the discussions of alternatives to a separate document. Added to the discussion on extensibility. Made extensive revisions to the functions, including renaming. Added functions necessary to replace the existing audit hooks.
June 14, 2000  0.3 Improvements and corrections based on discussions with John Plocher and Paul Fronberg. I removed the audit_set() function and added the adt_set_attr() (now adt_process_attr() and adt_session_attr()) function in response to comments by Gary and John. I also tried to make it clear that the attributes defined for the interface are abstractions of the underlying attributes so we can maintain decent data hiding.
May 31, 2000  0.2 (Thanks to Bill Edwards and Bing Xia.) "Viper" is the toolkit used to build administration consoles such as "SMC" and "WBEM." The confusion between threads and sessions is corrected. Bill also suggested that the secure client session id be used as a way to tie audit records to the SMC/WBEM logs. I also corrected the reference to the non-existing "audit_thread()" function.
May 2, 2000  0.1 initial draft

Last modified: Tue Feb 27 14:09:06 PST 2001 by Tony Panero

URL: http://jurassic/~tpanero/audit/bsmAPI.html