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