xref: /illumos-gate/usr/src/lib/libbsm/common/au_open.c (revision 922d2c76afbee21520ffa2088c4e60dcb80d3945)
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 2008 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 static token_t	**au_d;
57 static int	au_d_length = 0;	/* current table length */
58 static int	au_d_required_length = AU_TABLE_LENGTH; /* new table length */
59 static mutex_t  mutex_au_d = DEFAULTMUTEX;
60 
61 int
62 #ifdef __STDC__
63 au_open(void)
64 #else
65 au_open()
66 #endif
67 {
68 	int d;			/* descriptor */
69 	token_t	**au_d_new;
70 
71 	(void) mutex_lock(&mutex_au_d);
72 
73 	if (au_d_required_length > au_d_length) {
74 		au_d_new = (token_t **)calloc(au_d_required_length,
75 		    sizeof (au_d));
76 
77 		if (au_d_new == NULL) {
78 			au_d_required_length = au_d_length;
79 			(void) mutex_unlock(&mutex_au_d);
80 			return (-1);
81 		}
82 		if (au_d_length > 0) {
83 			(void) memcpy(au_d_new, au_d, au_d_length *
84 			    sizeof (au_d));
85 			free(au_d);
86 		}
87 		au_d = au_d_new;
88 		au_d_length = au_d_required_length;
89 	}
90 	for (d = 0; d < au_d_length; d++) {
91 		if (au_d[d] == (token_t *)0) {
92 			au_d[d] = (token_t *)&au_d;
93 			(void) mutex_unlock(&mutex_au_d);
94 			return (d);
95 		}
96 	}
97 	/*
98 	 * table full; make more room.
99 	 * AU_TABLE_MAX limits recursion.
100 	 * Logic here expects AU_TABLE_MAX to be multiple of AU_TABLE_LENGTH
101 	 */
102 	if (au_d_length >= AU_TABLE_MAX) {
103 		(void) mutex_unlock(&mutex_au_d);
104 		return (-1);
105 	}
106 	au_d_required_length += AU_TABLE_LENGTH;
107 	(void) mutex_unlock(&mutex_au_d);
108 
109 	return (au_open());
110 }
111 
112 /*
113  * Write to an audit descriptor.
114  * Add the mbuf to the descriptor chain and free the chain passed in.
115  */
116 
117 int
118 #ifdef __STDC__
119 au_write(int d, token_t *m)
120 #else
121 au_write(d, m)
122 	int d;
123 	token_t *m;
124 #endif
125 {
126 	token_t *mp;
127 
128 	if (d < 0)
129 		return (-1);
130 	if (m == (token_t *)0)
131 		return (-1);
132 	(void) mutex_lock(&mutex_au_d);
133 	if ((d >= au_d_length) || (au_d[d] == (token_t *)0)) {
134 		(void) mutex_unlock(&mutex_au_d);
135 		return (-1);
136 	} else if (au_d[d] == (token_t *)&au_d) {
137 		au_d[d] = m;
138 		(void) mutex_unlock(&mutex_au_d);
139 		return (0);
140 	}
141 	for (mp = au_d[d]; mp->tt_next != (token_t *)0; mp = mp->tt_next)
142 		;
143 	mp->tt_next = m;
144 	(void) mutex_unlock(&mutex_au_d);
145 	return (0);
146 }
147 
148 /*
149  * Close an audit descriptor.
150  * Use the second parameter to indicate if it should be written or not.
151  */
152 int
153 #ifdef __STDC__
154 au_close(int d, int right, short e_type)
155 #else
156 au_close(d, right, e_type)
157 	int d;
158 	int right;
159 	short e_type;
160 #endif
161 {
162 	short e_mod;
163 	struct timeval now;	/* current time */
164 	adr_t adr;		/* adr header */
165 	auditinfo_addr_t	audit_info;
166 	au_tid_addr_t	*host_info = &audit_info.ai_termid;
167 	token_t *dchain;	/* mbuf chain which is the tokens */
168 	token_t *record;	/* mbuf chain which is the record */
169 	char data_header;	/* token type */
170 	char version;		/* token version */
171 	char *buffer;		/* to build record into */
172 	int  byte_count;	/* bytes in the record */
173 	int   v;
174 
175 	(void) mutex_lock(&mutex_au_d);
176 	if (d < 0 || d >= au_d_length ||
177 	    ((dchain = au_d[d]) == (token_t *)0)) {
178 		(void) mutex_unlock(&mutex_au_d);
179 		return (-1);
180 	}
181 
182 	au_d[d] = (token_t *)0;
183 
184 	if (dchain == (token_t *)&au_d) {
185 		(void) mutex_unlock(&mutex_au_d);
186 		return (0);
187 	}
188 	/*
189 	 * If not to be written toss the record
190 	 */
191 	if (!right) {
192 		while (dchain != (token_t *)0) {
193 			record = dchain;
194 			dchain = dchain->tt_next;
195 			free(record->tt_data);
196 			free(record);
197 		}
198 		(void) mutex_unlock(&mutex_au_d);
199 		return (0);
200 	}
201 
202 	/*
203 	 * Count up the bytes used in the record.
204 	 */
205 	byte_count = sizeof (char) * 2 + sizeof (short) * 2 +
206 			sizeof (int32_t) + sizeof (struct timeval);
207 
208 	for (record = dchain; record != (token_t *)0;
209 		record = record->tt_next) {
210 			byte_count += record->tt_size;
211 	}
212 
213 #ifdef _LP64
214 #define	HEADER_ID	AUT_HEADER64
215 #define	HEADER_ID_EX	AUT_HEADER64_EX
216 #else
217 #define	HEADER_ID	AUT_HEADER32
218 #define	HEADER_ID_EX	AUT_HEADER32_EX
219 #endif
220 
221 	/* Use the extended headed if our host address can be determined. */
222 
223 	data_header = HEADER_ID;		/* Assume the worst */
224 	if (auditon(A_GETKAUDIT, (caddr_t)&audit_info,
225 	    sizeof (audit_info)) == 0) {
226 		int	have_valid_addr;
227 
228 		if (host_info->at_type == AU_IPv6)
229 			have_valid_addr = IN6_IS_ADDR_UNSPECIFIED(
230 			    (in6_addr_t *)host_info->at_addr) ? 0 : 1;
231 		else
232 			have_valid_addr = (host_info->at_addr[0] ==
233 			    htonl(INADDR_ANY)) ? 0 : 1;
234 
235 		if (have_valid_addr) {
236 			data_header = HEADER_ID_EX;
237 			byte_count += sizeof (int32_t) + host_info->at_type;
238 		}
239 	}
240 
241 	/*
242 	 * Build the header
243 	 */
244 	buffer = malloc((size_t)byte_count);
245 	(void) gettimeofday(&now, NULL);
246 	version = TOKEN_VERSION;
247 	e_mod = 0;
248 	adr_start(&adr, buffer);
249 	adr_char(&adr, &data_header, 1);
250 	adr_int32(&adr, (int32_t *)&byte_count, 1);
251 	adr_char(&adr, &version, 1);
252 	adr_short(&adr, &e_type, 1);
253 	adr_short(&adr, &e_mod, 1);
254 	if (data_header == HEADER_ID_EX) {
255 		adr_int32(&adr, (int32_t *)&host_info->at_type, 1);
256 		adr_char(&adr, (char *)&host_info->at_addr[0],
257 		    (int)host_info->at_type);
258 	}
259 #ifdef _LP64
260 	adr_int64(&adr, (int64_t *)&now, 2);
261 #else
262 	adr_int32(&adr, (int32_t *)&now, 2);
263 #endif
264 	/*
265 	 * Tack on the data, and free the tokens.
266 	 * We're not supposed to know how adr works, but ...
267 	 */
268 	while (dchain != (token_t *)0) {
269 		(void) memcpy(adr.adr_now, dchain->tt_data, dchain->tt_size);
270 		adr.adr_now += dchain->tt_size;
271 		record = dchain;
272 		dchain = dchain->tt_next;
273 		free(record->tt_data);
274 		free(record);
275 	}
276 	/*
277 	 * Send it down to the system
278 	 */
279 	v = audit((caddr_t)buffer, byte_count);
280 	free(buffer);
281 	(void) mutex_unlock(&mutex_au_d);
282 	return (v);
283 }
284