1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <sys/param.h>
27#include <sys/time.h>
28#include <sys/types.h>
29#include <stdlib.h>
30#include <string.h>
31#include <bsm/audit.h>
32#include <bsm/libbsm.h>
33#include <bsm/audit_record.h>
34#include <synch.h>
35
36
37/*
38 * Open an audit record = find a free descriptor and pass it back.
39 * The descriptors are in a "fixed" length array which is extended
40 * whenever it gets full.
41 *
42 *  Since the expected frequency of copies is expected to be low,
43 *  and since realloc loses data if it fails to expand the buffer,
44 *  calloc() is used rather than realloc().
45 */
46
47/*
48 * AU_TABLE_MAX must be a integer multiple of AU_TABLE_LENGTH
49 */
50#define	AU_TABLE_LENGTH	16
51#define	AU_TABLE_MAX	256
52
53static token_t	**au_d;
54static int	au_d_length = 0;	/* current table length */
55static int	au_d_required_length = AU_TABLE_LENGTH; /* new table length */
56static mutex_t  mutex_au_d = DEFAULTMUTEX;
57
58int
59au_open(void)
60{
61	int d;			/* descriptor */
62	token_t	**au_d_new;
63
64	(void) mutex_lock(&mutex_au_d);
65
66	if (au_d_required_length > au_d_length) {
67		au_d_new = (token_t **)calloc(au_d_required_length,
68		    sizeof (au_d));
69
70		if (au_d_new == NULL) {
71			au_d_required_length = au_d_length;
72			(void) mutex_unlock(&mutex_au_d);
73			return (-1);
74		}
75		if (au_d_length > 0) {
76			(void) memcpy(au_d_new, au_d, au_d_length *
77			    sizeof (au_d));
78			free(au_d);
79		}
80		au_d = au_d_new;
81		au_d_length = au_d_required_length;
82	}
83	for (d = 0; d < au_d_length; d++) {
84		if (au_d[d] == (token_t *)0) {
85			au_d[d] = (token_t *)&au_d;
86			(void) mutex_unlock(&mutex_au_d);
87			return (d);
88		}
89	}
90	/*
91	 * table full; make more room.
92	 * AU_TABLE_MAX limits recursion.
93	 * Logic here expects AU_TABLE_MAX to be multiple of AU_TABLE_LENGTH
94	 */
95	if (au_d_length >= AU_TABLE_MAX) {
96		(void) mutex_unlock(&mutex_au_d);
97		return (-1);
98	}
99	au_d_required_length += AU_TABLE_LENGTH;
100	(void) mutex_unlock(&mutex_au_d);
101
102	return (au_open());
103}
104
105/*
106 * Write to an audit descriptor.
107 * Add the mbuf to the descriptor chain and free the chain passed in.
108 */
109
110int
111au_write(int d, token_t *m)
112{
113	token_t *mp;
114
115	if (d < 0)
116		return (-1);
117	if (m == (token_t *)0)
118		return (-1);
119	(void) mutex_lock(&mutex_au_d);
120	if ((d >= au_d_length) || (au_d[d] == (token_t *)0)) {
121		(void) mutex_unlock(&mutex_au_d);
122		return (-1);
123	} else if (au_d[d] == (token_t *)&au_d) {
124		au_d[d] = m;
125		(void) mutex_unlock(&mutex_au_d);
126		return (0);
127	}
128	for (mp = au_d[d]; mp->tt_next != (token_t *)0; mp = mp->tt_next)
129		;
130	mp->tt_next = m;
131	(void) mutex_unlock(&mutex_au_d);
132	return (0);
133}
134
135/*
136 * Close an audit descriptor.
137 * Use the second parameter to indicate if it should be written or not.
138 */
139int
140au_close(int d, int right, au_event_t e_type)
141{
142	au_emod_t e_mod;
143	struct timeval now;	/* current time */
144	adr_t adr;		/* adr header */
145	auditinfo_addr_t	audit_info;
146	au_tid_addr_t	*host_info = &audit_info.ai_termid;
147	token_t *dchain;	/* mbuf chain which is the tokens */
148	token_t *record;	/* mbuf chain which is the record */
149	char data_header;	/* token type */
150	char version;		/* token version */
151	char *buffer;		/* to build record into */
152	int  byte_count;	/* bytes in the record */
153	int   v;
154
155	(void) mutex_lock(&mutex_au_d);
156	if (d < 0 || d >= au_d_length ||
157	    ((dchain = au_d[d]) == (token_t *)0)) {
158		(void) mutex_unlock(&mutex_au_d);
159		return (-1);
160	}
161
162	au_d[d] = (token_t *)0;
163
164	if (dchain == (token_t *)&au_d) {
165		(void) mutex_unlock(&mutex_au_d);
166		return (0);
167	}
168	/*
169	 * If not to be written toss the record
170	 */
171	if (!right) {
172		while (dchain != (token_t *)0) {
173			record = dchain;
174			dchain = dchain->tt_next;
175			free(record->tt_data);
176			free(record);
177		}
178		(void) mutex_unlock(&mutex_au_d);
179		return (0);
180	}
181
182	/*
183	 * Count up the bytes used in the record.
184	 */
185	byte_count = sizeof (char) * 2 + sizeof (short) * 2 +
186	    sizeof (int32_t) + sizeof (struct timeval);
187
188	for (record = dchain; record != (token_t *)0;
189	    record = record->tt_next) {
190		byte_count += record->tt_size;
191	}
192
193#ifdef _LP64
194#define	HEADER_ID	AUT_HEADER64
195#define	HEADER_ID_EX	AUT_HEADER64_EX
196#else
197#define	HEADER_ID	AUT_HEADER32
198#define	HEADER_ID_EX	AUT_HEADER32_EX
199#endif
200
201	/* Use the extended headed if our host address can be determined. */
202
203	data_header = HEADER_ID;		/* Assume the worst */
204	if (auditon(A_GETKAUDIT, (caddr_t)&audit_info,
205	    sizeof (audit_info)) == 0) {
206		int	have_valid_addr;
207
208		if (host_info->at_type == AU_IPv6)
209			have_valid_addr = IN6_IS_ADDR_UNSPECIFIED(
210			    (in6_addr_t *)host_info->at_addr) ? 0 : 1;
211		else
212			have_valid_addr = (host_info->at_addr[0] ==
213			    htonl(INADDR_ANY)) ? 0 : 1;
214
215		if (have_valid_addr) {
216			data_header = HEADER_ID_EX;
217			byte_count += sizeof (int32_t) + host_info->at_type;
218		}
219	}
220
221	/*
222	 * Build the header
223	 */
224	if ((buffer = malloc((size_t)byte_count)) == NULL) {
225		/* free the token chain */
226		while (dchain != (token_t *)0) {
227			record = dchain;
228			dchain = dchain->tt_next;
229			free(record->tt_data);
230			free(record);
231		}
232		(void) mutex_unlock(&mutex_au_d);
233		return (-1);
234	}
235	(void) gettimeofday(&now, NULL);
236	version = TOKEN_VERSION;
237	e_mod = 0;
238	adr_start(&adr, buffer);
239	adr_char(&adr, &data_header, 1);
240	adr_int32(&adr, (int32_t *)&byte_count, 1);
241	adr_char(&adr, &version, 1);
242	adr_ushort(&adr, &e_type, 1);
243	adr_ushort(&adr, &e_mod, 1);
244	if (data_header == HEADER_ID_EX) {
245		adr_int32(&adr, (int32_t *)&host_info->at_type, 1);
246		adr_char(&adr, (char *)&host_info->at_addr[0],
247		    (int)host_info->at_type);
248	}
249#ifdef _LP64
250	adr_int64(&adr, (int64_t *)&now, 2);
251#else
252	adr_int32(&adr, (int32_t *)&now, 2);
253#endif
254	/*
255	 * Tack on the data, and free the tokens.
256	 * We're not supposed to know how adr works, but ...
257	 */
258	while (dchain != (token_t *)0) {
259		(void) memcpy(adr.adr_now, dchain->tt_data, dchain->tt_size);
260		adr.adr_now += dchain->tt_size;
261		record = dchain;
262		dchain = dchain->tt_next;
263		free(record->tt_data);
264		free(record);
265	}
266	/*
267	 * Send it down to the system
268	 */
269	v = audit((caddr_t)buffer, byte_count);
270	free(buffer);
271	(void) mutex_unlock(&mutex_au_d);
272	return (v);
273}
274