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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * Interfaces to audit_event(5) (/etc/security/audit_event)
30 */
31
32 /*
33 * This routine is obsolete. I have removed its inclusion by removing
34 * the .o from the makefile. Please use cacheauevent() or any of the
35 * getauev* routines.
36 */
37
38 #include <sys/types.h>
39 #include <limits.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <bsm/audit.h>
44 #include <bsm/libbsm.h>
45 #include <synch.h>
46
47 /*
48 * Macros to produce a quoted string containing the value of a
49 * preprocessor macro. For example, if SIZE is defined to be 256,
50 * VAL2STR(SIZE) is "256". This is used to construct format
51 * strings for scanf-family functions below.
52 */
53 #define QUOTE(x) #x
54 #define VAL2STR(x) QUOTE(x)
55
56 static au_class_t flagstohex(char *);
57
58 static char au_event_fname[PATH_MAX] = AUDITEVENTFILE;
59 static FILE *au_event_file = (FILE *)0;
60 static mutex_t mutex_eventfile = DEFAULTMUTEX;
61 static mutex_t mutex_eventcache = DEFAULTMUTEX;
62 /*
63 * If an error occurs during the call to cacheauclassnam() inside
64 * flagstohex() any return value could be seen as a valid class mask so
65 * the following global variable, cacheauclass_failure, is set to indicate
66 * that an error has occurred.
67 */
68 static int cacheauclass_failure = 0;
69
70 #ifdef DEBUG2
71 void
printevent(au_event_ent_t * p_event)72 printevent(au_event_ent_t *p_event)
73 {
74 (void) printf("%d:%s:%s:%d\n", p_event->ae_number, p_event->ae_name,
75 p_event->ae_desc, p_event->ae_class);
76 (void) fflush(stdout);
77 }
78 #endif
79
80 void
setauevent()81 setauevent()
82 {
83 (void) mutex_lock(&mutex_eventfile);
84 if (au_event_file) {
85 (void) fseek(au_event_file, 0L, 0);
86 }
87 (void) mutex_unlock(&mutex_eventfile);
88 }
89
90 void
endauevent()91 endauevent()
92 {
93 (void) mutex_lock(&mutex_eventfile);
94 if (au_event_file) {
95 (void) fclose(au_event_file);
96 au_event_file = (FILE *)0;
97 }
98 (void) mutex_unlock(&mutex_eventfile);
99 }
100
101 au_event_ent_t *
getauevent()102 getauevent()
103 {
104 static au_event_ent_t au_event_entry;
105 static char ename[AU_EVENT_NAME_MAX];
106 static char edesc[AU_EVENT_DESC_MAX];
107
108 /* initialize au_event_entry structure */
109 au_event_entry.ae_name = ename;
110 au_event_entry.ae_desc = edesc;
111
112 return (getauevent_r(&au_event_entry));
113 }
114
115 au_event_ent_t *
getauevent_r(au_event_ent_t * au_event_entry)116 getauevent_r(au_event_ent_t *au_event_entry)
117 {
118 int i, error = 0, found = 0;
119 char *s, input[AU_EVENT_LINE_MAX];
120 char trim_buf[AU_EVENT_NAME_MAX+1];
121
122 /* open audit event file if it isn't already */
123 (void) mutex_lock(&mutex_eventfile);
124 if (!au_event_file)
125 if (!(au_event_file = fopen(au_event_fname, "rF"))) {
126 (void) mutex_unlock(&mutex_eventfile);
127 return (NULL);
128 }
129
130 while (fgets(input, AU_EVENT_LINE_MAX, au_event_file)) {
131 if (input[0] != '#') {
132 s = input + strspn(input, " \t\r\n");
133 if ((*s == '\0') || (*s == '#')) {
134 continue;
135 }
136 found = 1;
137 s = input;
138
139 /* parse number */
140 i = strcspn(s, ":");
141 s[i] = '\0';
142 (void) sscanf(s, "%hu", &au_event_entry->ae_number);
143 s = &s[i+1];
144
145 /* parse event name */
146 i = strcspn(s, ":");
147 s[i] = '\0';
148 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s",
149 trim_buf);
150 (void) strncpy(au_event_entry->ae_name, trim_buf,
151 AU_EVENT_NAME_MAX);
152 s = &s[i+1];
153
154 /* parse event description */
155 i = strcspn(s, ":");
156 s[i] = '\0';
157 (void) strncpy(au_event_entry->ae_desc, s,
158 AU_EVENT_DESC_MAX);
159 s = &s[i+1];
160
161 /* parse class */
162 i = strcspn(s, "\n\0");
163 s[i] = '\0';
164 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s",
165 trim_buf);
166 au_event_entry->ae_class = flagstohex(trim_buf);
167 if (cacheauclass_failure == 1) {
168 error = 1;
169 cacheauclass_failure = 0;
170 }
171
172 break;
173 }
174 }
175 (void) mutex_unlock(&mutex_eventfile);
176
177 if (!error && found) {
178 return (au_event_entry);
179 } else {
180 return (NULL);
181 }
182 }
183
184 au_event_ent_t *
getauevnam(char * name)185 getauevnam(char *name)
186 {
187 static au_event_ent_t au_event_entry;
188 static char ename[AU_EVENT_NAME_MAX];
189 static char edesc[AU_EVENT_DESC_MAX];
190
191 /* initialize au_event_entry structure */
192 au_event_entry.ae_name = ename;
193 au_event_entry.ae_desc = edesc;
194
195 return (getauevnam_r(&au_event_entry, name));
196 }
197
198 au_event_ent_t *
getauevnam_r(au_event_ent_t * e,char * name)199 getauevnam_r(au_event_ent_t *e, char *name)
200 {
201 setauevent();
202 while (getauevent_r(e) != NULL) {
203 if (strcmp(e->ae_name, name) == 0) {
204 endauevent();
205 return (e);
206 }
207 }
208 endauevent();
209 return (NULL);
210 }
211
212 au_event_ent_t *
getauevnum_r(au_event_ent_t * e,au_event_t event_number)213 getauevnum_r(au_event_ent_t *e, au_event_t event_number)
214 {
215 setauevent();
216 while (getauevent_r(e) != NULL) {
217 if (e->ae_number == event_number) {
218 endauevent();
219 return (e);
220 }
221 }
222 endauevent();
223 return (NULL);
224 }
225
226 au_event_ent_t *
getauevnum(au_event_t event_number)227 getauevnum(au_event_t event_number)
228 {
229 static au_event_ent_t e;
230 static char ename[AU_EVENT_NAME_MAX];
231 static char edesc[AU_EVENT_DESC_MAX];
232
233 /* initialize au_event_entry structure */
234 e.ae_name = ename;
235 e.ae_desc = edesc;
236
237 return (getauevnum_r(&e, event_number));
238 }
239
240 au_event_t
getauevnonam(char * event_name)241 getauevnonam(char *event_name)
242 {
243 au_event_ent_t e;
244 char ename[AU_EVENT_NAME_MAX];
245 char edesc[AU_EVENT_DESC_MAX];
246
247 /* initialize au_event_entry structure */
248 e.ae_name = ename;
249 e.ae_desc = edesc;
250
251 if (getauevnam_r(&e, event_name) == NULL) {
252 return (0);
253 }
254 return (e.ae_number);
255 }
256
257 /*
258 * cacheauevent:
259 * Read the entire audit_event file into memory.
260 * Set a pointer to the requested entry in the cache
261 * or a pointer to an invalid entry if the event number
262 * is not known.
263 *
264 * Return < 0, if error.
265 * Return 0, if event number not in cache.
266 * Return 1, if event number is in cache.
267 */
268 int
cacheauevent(au_event_ent_t ** result,au_event_t event_number)269 cacheauevent(au_event_ent_t **result, au_event_t event_number)
270 {
271 static au_event_t max; /* the highest event number in the file */
272 static au_event_t min; /* the lowest event number in the file */
273 static int invalid; /* 1+index of the highest event number */
274 static au_event_ent_t **index_tbl;
275 static au_event_ent_t **p_tbl;
276 static int called_once = 0;
277
278 char line[AU_EVENT_LINE_MAX];
279 int lines = 0;
280 FILE *fp;
281 au_event_ent_t *p_event;
282 int i, size;
283 int hit = 0;
284 char *s;
285
286 (void) mutex_lock(&mutex_eventcache);
287 if (called_once == 0) {
288
289 /* Count number of lines in the events file */
290 if ((fp = fopen(au_event_fname, "rF")) == NULL) {
291 (void) mutex_unlock(&mutex_eventcache);
292 return (-1);
293 }
294 while (fgets(line, AU_EVENT_LINE_MAX, fp) != NULL) {
295 s = line + strspn(line, " \t\r\n");
296 if ((*s == '\0') || (*s == '#')) {
297 continue;
298 }
299 lines++;
300 }
301 (void) fclose(fp);
302 size = lines;
303
304 /*
305 * Make an array in which each element in an entry in the
306 * events file. Make the next to last element an invalid
307 * event. Make the last element a NULL pointer.
308 */
309
310 p_tbl = calloc(lines + 1, sizeof (au_event_ent_t));
311 if (p_tbl == NULL) {
312 (void) mutex_unlock(&mutex_eventcache);
313 return (-2);
314 }
315 lines = 0;
316 max = 0;
317 min = 65535;
318 setauevent();
319 while ((p_event = getauevent()) != NULL) {
320 p_tbl[lines] = (au_event_ent_t *)
321 malloc(sizeof (au_event_ent_t));
322 if (p_tbl[lines] == NULL) {
323 (void) mutex_unlock(&mutex_eventcache);
324 return (-3);
325 }
326 p_tbl[lines]->ae_number = p_event->ae_number;
327 p_tbl[lines]->ae_name = strdup(p_event->ae_name);
328 p_tbl[lines]->ae_desc = strdup(p_event->ae_desc);
329 p_tbl[lines]->ae_class = p_event->ae_class;
330 #ifdef DEBUG2
331 printevent(p_tbl[lines]);
332 #endif
333 if (p_event->ae_number > max) {
334 max = p_event->ae_number;
335 }
336 if (p_event->ae_number < min) {
337 min = p_event->ae_number;
338 }
339 lines++;
340 }
341 endauevent();
342 invalid = lines;
343 p_tbl[invalid] = (au_event_ent_t *)
344 malloc(sizeof (au_event_ent_t));
345 if (p_tbl[invalid] == NULL) {
346 (void) mutex_unlock(&mutex_eventcache);
347 return (-4);
348 }
349 p_tbl[invalid]->ae_number = (au_event_t)-1;
350 p_tbl[invalid]->ae_name = "invalid event number";
351 p_tbl[invalid]->ae_desc = p_tbl[invalid]->ae_name;
352 p_tbl[invalid]->ae_class = (au_class_t)-1;
353
354 #ifdef DEBUG2
355 for (i = 0; i < size; i++) {
356 (void) printf("%d:%s:%s:%d\n", p_tbl[i]->ae_number,
357 p_tbl[i]->ae_name, p_tbl[i]->ae_desc,
358 p_tbl[i]->ae_class);
359 }
360 #endif
361
362 /* get space for the index_tbl */
363 index_tbl = calloc(max+1, sizeof (au_event_ent_t *));
364 if (index_tbl == NULL) {
365 (void) mutex_unlock(&mutex_eventcache);
366 return (-5);
367 }
368
369 /* intialize the index_tbl to the invalid event number */
370 for (i = 0; (au_event_t)i < max; i++) {
371 index_tbl[i] = p_tbl[invalid];
372 }
373
374 /* point each index_tbl element at the corresponding event */
375 for (i = 0; i < size; i++) {
376 index_tbl[p_tbl[i]->ae_number] = p_tbl[i];
377 }
378
379 called_once = 1;
380
381 }
382
383 if (event_number > max || event_number < min) {
384 *result = index_tbl[invalid];
385 } else {
386 *result = index_tbl[event_number];
387 hit = 1;
388 }
389 (void) mutex_unlock(&mutex_eventcache);
390 return (hit);
391 }
392
393 static au_class_t
flagstohex(char * flags)394 flagstohex(char *flags)
395 {
396 au_class_ent_t *p_class;
397 au_class_t hex = 0;
398 char *comma = ",";
399 char *s;
400 char *last;
401
402 s = strtok_r(flags, comma, &last);
403 while (s != NULL) {
404 if ((cacheauclassnam(&p_class, s)) < 0) {
405 cacheauclass_failure = 1;
406 return ((au_class_t)-1);
407 }
408 hex |= p_class->ac_class;
409 s = strtok_r(NULL, comma, &last);
410 }
411 return (hex);
412 }
413