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