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