xref: /illumos-gate/usr/src/lib/libbsm/common/au_open.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
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 
53 static token_t	**au_d;
54 static int	au_d_length = 0;	/* current table length */
55 static int	au_d_required_length = AU_TABLE_LENGTH; /* new table length */
56 static mutex_t  mutex_au_d = DEFAULTMUTEX;
57 
58 int
59 au_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 
110 int
111 au_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  */
139 int
140 au_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