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