au_preselect.c revision 4893:0177e932e294
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
22
23/*
24 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*
29 * au_preselect.c
30 */
31
32#include <sys/types.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <bsm/audit.h>
36#include <bsm/libbsm.h>
37#include <synch.h>
38
39#define	ALLOC_INIT (600)	/* initially allocate ALLOC_INIT map entries */
40#define	ALLOC_INCR (100)	/* if more map entries are needed, realloc */
41				/* in ALLOC_INCR increments */
42
43static int alloc_map();
44static int load_map();
45static int realloc_map();
46
47typedef struct event_map {
48	au_event_t event;	/* audit event number */
49	au_class_t class;	/* audit event class mask */
50} event_map_t;
51
52static event_map_t *event_map;	/* the map */
53static uint_t alloc_count;	/* number of entries currently allocated */
54static uint_t event_count;	/* number of entries in map */
55static mutex_t mutex_au_preselect = DEFAULTMUTEX;
56
57extern int _mutex_lock(mutex_t *);
58extern int _mutex_unlock(mutex_t *);
59
60/*
61 * au_preselect:
62 *
63 * Keep a dynamic array of event<-->class mappings.
64 * Refresh the map when the value of flag is non-zero.
65 * Return:
66 *	1: The event is preselected.
67 *	0: The event is not preselected.
68 *	-1: There was an error:
69 *		Couldn't allocate memory.
70 *		Couldn't find event.
71 */
72int
73#ifdef __STDC__
74au_preselect(au_event_t au_event, au_mask_t *au_mask_p, int sorf, int flag)
75#else
76au_preselect(au_event, au_mask_p, sorf, flag)
77	au_event_t au_event;	/* event */
78	au_mask_t *au_mask_p;	/* preselection mask */
79	int sorf;		/* success or failure */
80	int flag;		/* re-read flag */
81#endif /* __STDC__ */
82{
83	static char been_here_before;  /* we cache the map */
84	register int i;
85	register au_class_t comp_class;
86
87	_mutex_lock(&mutex_au_preselect);
88	if (!been_here_before) {
89		if (alloc_map() == -1) {
90			_mutex_unlock(&mutex_au_preselect);
91			return (-1);
92		}
93
94		if (load_map() == -1) {
95			_mutex_unlock(&mutex_au_preselect);
96			return (-1);
97		}
98
99		been_here_before = 1;
100	}
101
102	/*
103	 * Don't use the cache. Re-read the audit_event(5) db every time
104	 */
105	if (flag == AU_PRS_REREAD) {
106		if (load_map() == -1) {
107			_mutex_unlock(&mutex_au_preselect);
108			return (-1);
109		}
110	}
111
112	/* Determine what portion of the preselection mask to check. */
113	if (sorf == AU_PRS_SUCCESS)
114		comp_class = au_mask_p->am_success;
115	else if (sorf == AU_PRS_FAILURE)
116		comp_class = au_mask_p->am_failure;
117	else
118		comp_class = au_mask_p->am_success | au_mask_p->am_failure;
119
120	for (i = 0; i < event_count; i++) {
121		if (event_map[i].event == au_event) {
122			if (event_map[i].class & comp_class) {
123				_mutex_unlock(&mutex_au_preselect);
124				return (1);
125			} else {
126				_mutex_unlock(&mutex_au_preselect);
127				return (0);
128			}
129		}
130	}
131
132	_mutex_unlock(&mutex_au_preselect);
133	return (-1);	/* could not find event in the table */
134}
135
136/*
137 * Initially allocate about as many map entries as are there
138 * are audit events shipped with the system. For sites
139 * that don't add audit events, this should be enough.
140 */
141static int
142alloc_map()
143{
144	if ((event_map = (event_map_t *)
145	    calloc(ALLOC_INIT, (size_t)sizeof (event_map_t))) ==
146	    (event_map_t *)NULL)
147		return (-1);
148	else
149		alloc_count = ALLOC_INIT;
150
151	return (0);
152}
153
154/*
155 * load the event<->class map into memory
156 */
157static int
158load_map()
159{
160	register au_event_ent_t *evp;
161
162	event_count = 0;
163	setauevent();
164	while ((evp = getauevent()) != (au_event_ent_t *)NULL) {
165		if (event_count > alloc_count)
166			if (realloc_map() == -1) {
167				endauevent();
168				return (-1);
169			}
170		event_map[event_count].event = evp->ae_number;
171		event_map[event_count].class = evp->ae_class;
172		++event_count;
173	}
174	endauevent();
175
176	return (0);
177}
178
179/*
180 * realloc the event map in ALLOC_INCR increments
181 */
182static int
183realloc_map()
184{
185	register size_t rsize;
186	rsize = sizeof (event_map_t) * (alloc_count + ALLOC_INCR);
187
188	if ((event_map = (event_map_t *)
189	    realloc(event_map, rsize)) == (event_map_t *)NULL)
190		return (-1);
191
192	return (0);
193}
194