2 * Copyright (c) 2004 Apple Computer, Inc.
3 * Copyright (c) 2005 SPARTA, Inc.
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
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>
42 #include <compat/queue.h>
45 #include <bsm/audit_internal.h>
46 #include <bsm/libbsm.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.
72 au_free_token(token_t
*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().
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
103 if (!LIST_EMPTY(&audit_free_q
)) {
104 rec
= LIST_FIRST(&audit_free_q
);
106 LIST_REMOVE(rec
, au_rec_q
);
109 pthread_mutex_unlock(&mutex
);
113 * Create a new au_record_t if no descriptors are available.
115 rec
= malloc (sizeof(au_record_t
));
119 rec
->data
= malloc (MAX_AUDIT_RECORD_SIZE
* sizeof(u_char
));
120 if (rec
->data
== NULL
) {
126 pthread_mutex_lock(&mutex
);
128 if (audit_rec_count
== MAX_AUDIT_RECORDS
) {
129 pthread_mutex_unlock(&mutex
);
133 /* XXX We need to increase size of MAX_AUDIT_RECORDS */
137 rec
->desc
= audit_rec_count
;
138 open_desc_table
[audit_rec_count
] = rec
;
141 pthread_mutex_unlock(&mutex
);
145 memset(rec
->data
, 0, MAX_AUDIT_RECORD_SIZE
);
147 TAILQ_INIT(&rec
->token_q
);
155 * Store the token with the record descriptor.
157 * Don't permit writing more to the buffer than would let the trailer be
161 au_write(int d
, token_t
*tok
)
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)) {
174 return (-1); /* Invalid descriptor */
177 if (rec
->len
+ tok
->len
+ AUDIT_TRAILER_SIZE
> MAX_AUDIT_RECORD_SIZE
) {
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 */
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.
204 au_assemble(au_record_t
*rec
, short event
)
206 token_t
*header
, *tok
, *trailer
;
211 tot_rec_size
= rec
->len
+ AUDIT_HEADER_SIZE
+ AUDIT_TRAILER_SIZE
;
212 header
= au_to_header32(tot_rec_size
, event
, 0);
216 trailer
= au_to_trailer(tot_rec_size
);
217 if (trailer
== NULL
) {
219 au_free_token(header
);
224 TAILQ_INSERT_HEAD(&rec
->token_q
, header
, tokens
);
225 TAILQ_INSERT_TAIL(&rec
->token_q
, trailer
, tokens
);
227 rec
->len
= tot_rec_size
;
230 TAILQ_FOREACH(tok
, &rec
->token_q
, tokens
) {
231 memcpy(dptr
, tok
->t_data
, tok
->len
);
239 * Given a record that is no longer of interest, tear it down and convert to a
243 au_teardown(au_record_t
*rec
)
247 /* Free the token list */
248 while ((tok
= TAILQ_FIRST(&rec
->token_q
)) != NULL
) {
249 TAILQ_REMOVE(&rec
->token_q
, tok
, tokens
);
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
)
277 rec
= open_desc_table
[d
];
278 if ((rec
== NULL
) || (rec
->used
== 0)) {
280 return (-1); /* Invalid descriptor */
283 if (keep
== AU_TO_NO_WRITE
) {
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
295 fprintf(stderr
, "au_close failed");
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.
310 /* Call the kernel interface to audit */
311 retval
= audit(rec
->data
, rec
->len
);
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
)
331 rec
= open_desc_table
[d
];
332 if ((rec
== NULL
) || (rec
->used
== 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
);
350 if (au_assemble(rec
, event
) < 0) {
351 /* XXXRW: See au_close() comment. */
356 memcpy(buffer
, rec
->data
, rec
->len
);
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
) {
379 memcpy(buffer
, tok
->t_data
, tok
->len
);