OpenSolaris_b135/lib/libbsm/common/au_open.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <bsm/audit.h>
#include <bsm/libbsm.h>
#include <bsm/audit_record.h>
#include <synch.h>


/*
 * Open an audit record = find a free descriptor and pass it back.
 * The descriptors are in a "fixed" length array which is extended
 * whenever it gets full.
 *
 *  Since the expected frequency of copies is expected to be low,
 *  and since realloc loses data if it fails to expand the buffer,
 *  calloc() is used rather than realloc().
 */

/*
 * AU_TABLE_MAX must be a integer multiple of AU_TABLE_LENGTH
 */
#define	AU_TABLE_LENGTH	16
#define	AU_TABLE_MAX	256

static token_t	**au_d;
static int	au_d_length = 0;	/* current table length */
static int	au_d_required_length = AU_TABLE_LENGTH; /* new table length */
static mutex_t  mutex_au_d = DEFAULTMUTEX;

int
au_open(void)
{
	int d;			/* descriptor */
	token_t	**au_d_new;

	(void) mutex_lock(&mutex_au_d);

	if (au_d_required_length > au_d_length) {
		au_d_new = (token_t **)calloc(au_d_required_length,
		    sizeof (au_d));

		if (au_d_new == NULL) {
			au_d_required_length = au_d_length;
			(void) mutex_unlock(&mutex_au_d);
			return (-1);
		}
		if (au_d_length > 0) {
			(void) memcpy(au_d_new, au_d, au_d_length *
			    sizeof (au_d));
			free(au_d);
		}
		au_d = au_d_new;
		au_d_length = au_d_required_length;
	}
	for (d = 0; d < au_d_length; d++) {
		if (au_d[d] == (token_t *)0) {
			au_d[d] = (token_t *)&au_d;
			(void) mutex_unlock(&mutex_au_d);
			return (d);
		}
	}
	/*
	 * table full; make more room.
	 * AU_TABLE_MAX limits recursion.
	 * Logic here expects AU_TABLE_MAX to be multiple of AU_TABLE_LENGTH
	 */
	if (au_d_length >= AU_TABLE_MAX) {
		(void) mutex_unlock(&mutex_au_d);
		return (-1);
	}
	au_d_required_length += AU_TABLE_LENGTH;
	(void) mutex_unlock(&mutex_au_d);

	return (au_open());
}

/*
 * Write to an audit descriptor.
 * Add the mbuf to the descriptor chain and free the chain passed in.
 */

int
au_write(int d, token_t *m)
{
	token_t *mp;

	if (d < 0)
		return (-1);
	if (m == (token_t *)0)
		return (-1);
	(void) mutex_lock(&mutex_au_d);
	if ((d >= au_d_length) || (au_d[d] == (token_t *)0)) {
		(void) mutex_unlock(&mutex_au_d);
		return (-1);
	} else if (au_d[d] == (token_t *)&au_d) {
		au_d[d] = m;
		(void) mutex_unlock(&mutex_au_d);
		return (0);
	}
	for (mp = au_d[d]; mp->tt_next != (token_t *)0; mp = mp->tt_next)
		;
	mp->tt_next = m;
	(void) mutex_unlock(&mutex_au_d);
	return (0);
}

/*
 * Close an audit descriptor.
 * Use the second parameter to indicate if it should be written or not.
 */
int
au_close(int d, int right, au_event_t e_type)
{
	au_emod_t e_mod;
	struct timeval now;	/* current time */
	adr_t adr;		/* adr header */
	auditinfo_addr_t	audit_info;
	au_tid_addr_t	*host_info = &audit_info.ai_termid;
	token_t *dchain;	/* mbuf chain which is the tokens */
	token_t *record;	/* mbuf chain which is the record */
	char data_header;	/* token type */
	char version;		/* token version */
	char *buffer;		/* to build record into */
	int  byte_count;	/* bytes in the record */
	int   v;

	(void) mutex_lock(&mutex_au_d);
	if (d < 0 || d >= au_d_length ||
	    ((dchain = au_d[d]) == (token_t *)0)) {
		(void) mutex_unlock(&mutex_au_d);
		return (-1);
	}

	au_d[d] = (token_t *)0;

	if (dchain == (token_t *)&au_d) {
		(void) mutex_unlock(&mutex_au_d);
		return (0);
	}
	/*
	 * If not to be written toss the record
	 */
	if (!right) {
		while (dchain != (token_t *)0) {
			record = dchain;
			dchain = dchain->tt_next;
			free(record->tt_data);
			free(record);
		}
		(void) mutex_unlock(&mutex_au_d);
		return (0);
	}

	/*
	 * Count up the bytes used in the record.
	 */
	byte_count = sizeof (char) * 2 + sizeof (short) * 2 +
			sizeof (int32_t) + sizeof (struct timeval);

	for (record = dchain; record != (token_t *)0;
		record = record->tt_next) {
			byte_count += record->tt_size;
	}

#ifdef _LP64
#define	HEADER_ID	AUT_HEADER64
#define	HEADER_ID_EX	AUT_HEADER64_EX
#else
#define	HEADER_ID	AUT_HEADER32
#define	HEADER_ID_EX	AUT_HEADER32_EX
#endif

	/* Use the extended headed if our host address can be determined. */

	data_header = HEADER_ID;		/* Assume the worst */
	if (auditon(A_GETKAUDIT, (caddr_t)&audit_info,
	    sizeof (audit_info)) == 0) {
		int	have_valid_addr;

		if (host_info->at_type == AU_IPv6)
			have_valid_addr = IN6_IS_ADDR_UNSPECIFIED(
			    (in6_addr_t *)host_info->at_addr) ? 0 : 1;
		else
			have_valid_addr = (host_info->at_addr[0] ==
			    htonl(INADDR_ANY)) ? 0 : 1;

		if (have_valid_addr) {
			data_header = HEADER_ID_EX;
			byte_count += sizeof (int32_t) + host_info->at_type;
		}
	}

	/*
	 * Build the header
	 */
	buffer = malloc((size_t)byte_count);
	(void) gettimeofday(&now, NULL);
	version = TOKEN_VERSION;
	e_mod = 0;
	adr_start(&adr, buffer);
	adr_char(&adr, &data_header, 1);
	adr_int32(&adr, (int32_t *)&byte_count, 1);
	adr_char(&adr, &version, 1);
	adr_ushort(&adr, &e_type, 1);
	adr_ushort(&adr, &e_mod, 1);
	if (data_header == HEADER_ID_EX) {
		adr_int32(&adr, (int32_t *)&host_info->at_type, 1);
		adr_char(&adr, (char *)&host_info->at_addr[0],
		    (int)host_info->at_type);
	}
#ifdef _LP64
	adr_int64(&adr, (int64_t *)&now, 2);
#else
	adr_int32(&adr, (int32_t *)&now, 2);
#endif
	/*
	 * Tack on the data, and free the tokens.
	 * We're not supposed to know how adr works, but ...
	 */
	while (dchain != (token_t *)0) {
		(void) memcpy(adr.adr_now, dchain->tt_data, dchain->tt_size);
		adr.adr_now += dchain->tt_size;
		record = dchain;
		dchain = dchain->tt_next;
		free(record->tt_data);
		free(record);
	}
	/*
	 * Send it down to the system
	 */
	v = audit((caddr_t)buffer, byte_count);
	free(buffer);
	(void) mutex_unlock(&mutex_au_d);
	return (v);
}