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