turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / openbsm / libbsm / bsm_audit.c
blob2f6df41ecbdd158e91f8257b04e02850116d4024
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc.
3 * Copyright (c) 2005 SPARTA, Inc.
4 * All rights reserved.
6 * This code was developed in part by Robert N. M. Watson, Senior Principal
7 * Scientist, SPARTA, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_audit.c#28 $
36 #include <sys/types.h>
38 #include <config/config.h>
39 #ifdef HAVE_FULL_QUEUE_H
40 #include <sys/queue.h>
41 #else
42 #include <compat/queue.h>
43 #endif
45 #include <bsm/audit_internal.h>
46 #include <bsm/libbsm.h>
48 #include <errno.h>
49 #include <pthread.h>
50 #include <stdlib.h>
51 #include <string.h>
53 /* array of used descriptors */
54 static au_record_t *open_desc_table[MAX_AUDIT_RECORDS];
56 /* The current number of active record descriptors */
57 static int audit_rec_count = 0;
60 * Records that can be recycled are maintained in the list given below. The
61 * maximum number of elements that can be present in this list is bounded by
62 * MAX_AUDIT_RECORDS. Memory allocated for these records are never freed.
64 static LIST_HEAD(, au_record) audit_free_q;
66 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
69 * This call frees a token_t and its internal data.
71 void
72 au_free_token(token_t *tok)
75 if (tok != NULL) {
76 if (tok->t_data)
77 free(tok->t_data);
78 free(tok);
83 * This call reserves memory for the audit record. Memory must be guaranteed
84 * before any auditable event can be generated. The au_record_t structure
85 * maintains a reference to the memory allocated above and also the list of
86 * tokens associated with this record. Descriptors are recyled once the
87 * records are added to the audit trail following au_close().
89 int
90 au_open(void)
92 au_record_t *rec = NULL;
94 pthread_mutex_lock(&mutex);
96 if (audit_rec_count == 0)
97 LIST_INIT(&audit_free_q);
100 * Find an unused descriptor, remove it from the free list, mark as
101 * used.
103 if (!LIST_EMPTY(&audit_free_q)) {
104 rec = LIST_FIRST(&audit_free_q);
105 rec->used = 1;
106 LIST_REMOVE(rec, au_rec_q);
109 pthread_mutex_unlock(&mutex);
111 if (rec == NULL) {
113 * Create a new au_record_t if no descriptors are available.
115 rec = malloc (sizeof(au_record_t));
116 if (rec == NULL)
117 return (-1);
119 rec->data = malloc (MAX_AUDIT_RECORD_SIZE * sizeof(u_char));
120 if (rec->data == NULL) {
121 free(rec);
122 errno = ENOMEM;
123 return (-1);
126 pthread_mutex_lock(&mutex);
128 if (audit_rec_count == MAX_AUDIT_RECORDS) {
129 pthread_mutex_unlock(&mutex);
130 free(rec->data);
131 free(rec);
133 /* XXX We need to increase size of MAX_AUDIT_RECORDS */
134 errno = ENOMEM;
135 return (-1);
137 rec->desc = audit_rec_count;
138 open_desc_table[audit_rec_count] = rec;
139 audit_rec_count++;
141 pthread_mutex_unlock(&mutex);
145 memset(rec->data, 0, MAX_AUDIT_RECORD_SIZE);
147 TAILQ_INIT(&rec->token_q);
148 rec->len = 0;
149 rec->used = 1;
151 return (rec->desc);
155 * Store the token with the record descriptor.
157 * Don't permit writing more to the buffer than would let the trailer be
158 * appended later.
161 au_write(int d, token_t *tok)
163 au_record_t *rec;
165 if (tok == NULL) {
166 errno = EINVAL;
167 return (-1); /* Invalid Token */
170 /* Write the token to the record descriptor */
171 rec = open_desc_table[d];
172 if ((rec == NULL) || (rec->used == 0)) {
173 errno = EINVAL;
174 return (-1); /* Invalid descriptor */
177 if (rec->len + tok->len + AUDIT_TRAILER_SIZE > MAX_AUDIT_RECORD_SIZE) {
178 errno = ENOMEM;
179 return (-1);
182 /* Add the token to the tail */
184 * XXX Not locking here -- we should not be writing to
185 * XXX the same descriptor from different threads
187 TAILQ_INSERT_TAIL(&rec->token_q, tok, tokens);
189 rec->len += tok->len; /* grow record length by token size bytes */
191 /* Token should not be available after this call */
192 tok = NULL;
193 return (0); /* Success */
197 * Assemble an audit record out of its tokens, including allocating header and
198 * trailer tokens. Does not free the token chain, which must be done by the
199 * caller if desirable.
201 * XXX: Assumes there is sufficient space for the header and trailer.
203 static int
204 au_assemble(au_record_t *rec, short event)
206 token_t *header, *tok, *trailer;
207 size_t tot_rec_size;
208 u_char *dptr;
209 int error;
211 tot_rec_size = rec->len + AUDIT_HEADER_SIZE + AUDIT_TRAILER_SIZE;
212 header = au_to_header32(tot_rec_size, event, 0);
213 if (header == NULL)
214 return (-1);
216 trailer = au_to_trailer(tot_rec_size);
217 if (trailer == NULL) {
218 error = errno;
219 au_free_token(header);
220 errno = error;
221 return (-1);
224 TAILQ_INSERT_HEAD(&rec->token_q, header, tokens);
225 TAILQ_INSERT_TAIL(&rec->token_q, trailer, tokens);
227 rec->len = tot_rec_size;
228 dptr = rec->data;
230 TAILQ_FOREACH(tok, &rec->token_q, tokens) {
231 memcpy(dptr, tok->t_data, tok->len);
232 dptr += tok->len;
235 return (0);
239 * Given a record that is no longer of interest, tear it down and convert to a
240 * free record.
242 static void
243 au_teardown(au_record_t *rec)
245 token_t *tok;
247 /* Free the token list */
248 while ((tok = TAILQ_FIRST(&rec->token_q)) != NULL) {
249 TAILQ_REMOVE(&rec->token_q, tok, tokens);
250 free(tok->t_data);
251 free(tok);
254 rec->used = 0;
255 rec->len = 0;
257 pthread_mutex_lock(&mutex);
259 /* Add the record to the freelist tail */
260 LIST_INSERT_HEAD(&audit_free_q, rec, au_rec_q);
262 pthread_mutex_unlock(&mutex);
265 #ifdef HAVE_AUDIT_SYSCALLS
267 * Add the header token, identify any missing tokens. Write out the tokens to
268 * the record memory and finally, call audit.
271 au_close(int d, int keep, short event)
273 au_record_t *rec;
274 size_t tot_rec_size;
275 int retval = 0;
277 rec = open_desc_table[d];
278 if ((rec == NULL) || (rec->used == 0)) {
279 errno = EINVAL;
280 return (-1); /* Invalid descriptor */
283 if (keep == AU_TO_NO_WRITE) {
284 retval = 0;
285 goto cleanup;
288 tot_rec_size = rec->len + AUDIT_HEADER_SIZE + AUDIT_TRAILER_SIZE;
290 if (tot_rec_size > MAX_AUDIT_RECORD_SIZE) {
292 * XXXRW: Since au_write() is supposed to prevent this, spew
293 * an error here.
295 fprintf(stderr, "au_close failed");
296 errno = ENOMEM;
297 retval = -1;
298 goto cleanup;
301 if (au_assemble(rec, event) < 0) {
303 * XXXRW: This is also not supposed to happen, but might if we
304 * are unable to allocate header and trailer memory.
306 retval = -1;
307 goto cleanup;
310 /* Call the kernel interface to audit */
311 retval = audit(rec->data, rec->len);
313 cleanup:
314 /* CLEANUP */
315 au_teardown(rec);
316 return (retval);
318 #endif /* HAVE_AUDIT_SYSCALLS */
321 * au_close(), except onto an in-memory buffer. Buffer size as an argument,
322 * record size returned via same argument on success.
325 au_close_buffer(int d, short event, u_char *buffer, size_t *buflen)
327 size_t tot_rec_size;
328 au_record_t *rec;
329 int retval;
331 rec = open_desc_table[d];
332 if ((rec == NULL) || (rec->used == 0)) {
333 errno = EINVAL;
334 return (-1);
337 retval = 0;
338 tot_rec_size = rec->len + AUDIT_HEADER_SIZE + AUDIT_TRAILER_SIZE;
339 if ((tot_rec_size > MAX_AUDIT_RECORD_SIZE) ||
340 (tot_rec_size > *buflen)) {
342 * XXXRW: See au_close() comment.
344 fprintf(stderr, "au_close_buffer failed %zd", tot_rec_size);
345 errno = ENOMEM;
346 retval = -1;
347 goto cleanup;
350 if (au_assemble(rec, event) < 0) {
351 /* XXXRW: See au_close() comment. */
352 retval = -1;
353 goto cleanup;
356 memcpy(buffer, rec->data, rec->len);
357 *buflen = rec->len;
359 cleanup:
360 au_teardown(rec);
361 return (retval);
365 * au_close_token() returns the byte format of a token_t. This won't
366 * generally be used by applications, but is quite useful for writing test
367 * tools. Will free the token on either success or failure.
370 au_close_token(token_t *tok, u_char *buffer, size_t *buflen)
373 if (tok->len > *buflen) {
374 au_free_token(tok);
375 errno = ENOMEM;
376 return (EINVAL);
379 memcpy(buffer, tok->t_data, tok->len);
380 *buflen = tok->len;
381 au_free_token(tok);
382 return (0);