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 
43 static int alloc_map();
44 static int load_map();
45 static int realloc_map();
46 
47 typedef 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 
52 static event_map_t *event_map;	/* the map */
53 static uint_t alloc_count;	/* number of entries currently allocated */
54 static uint_t event_count;	/* number of entries in map */
55 static mutex_t mutex_au_preselect = DEFAULTMUTEX;
56 
57 extern int _mutex_lock(mutex_t *);
58 extern 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  */
72 int
73 #ifdef __STDC__
74 au_preselect(au_event_t au_event, au_mask_t *au_mask_p, int sorf, int flag)
75 #else
76 au_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  */
141 static int
142 alloc_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  */
157 static int
158 load_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  */
182 static int
183 realloc_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