xref: /illumos-gate/usr/src/lib/libbsm/common/audit_event.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
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  * 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 extern int _mutex_lock(mutex_t *);
71 extern int _mutex_unlock(mutex_t *);
72 
73 
74 void
75 setauevent()
76 {
77 	_mutex_lock(&mutex_eventfile);
78 	if (au_event_file) {
79 		(void) fseek(au_event_file, 0L, 0);
80 	}
81 	_mutex_unlock(&mutex_eventfile);
82 }
83 
84 
85 void
86 endauevent()
87 {
88 	_mutex_lock(&mutex_eventfile);
89 	if (au_event_file) {
90 		(void) fclose(au_event_file);
91 		au_event_file = (FILE *)0;
92 	}
93 	_mutex_unlock(&mutex_eventfile);
94 }
95 
96 au_event_ent_t *
97 getauevent()
98 {
99 	static au_event_ent_t au_event_entry;
100 	static char	ename[AU_EVENT_NAME_MAX];
101 	static char	edesc[AU_EVENT_DESC_MAX];
102 
103 	/* initialize au_event_entry structure */
104 	au_event_entry.ae_name = ename;
105 	au_event_entry.ae_desc = edesc;
106 
107 	return (getauevent_r(&au_event_entry));
108 }
109 
110 au_event_ent_t *
111 getauevent_r(au_event_entry)
112 	au_event_ent_t *au_event_entry;
113 {
114 	int	i, error = 0, found = 0;
115 	char	*s, input[AU_EVENT_LINE_MAX];
116 	char	trim_buf[AU_EVENT_NAME_MAX+1];
117 
118 	/* open audit event file if it isn't already */
119 	_mutex_lock(&mutex_eventfile);
120 	if (!au_event_file)
121 		if (!(au_event_file = fopen(au_event_fname, "rF"))) {
122 			_mutex_unlock(&mutex_eventfile);
123 			return ((au_event_ent_t *)0);
124 		}
125 
126 	while (fgets(input, AU_EVENT_LINE_MAX, au_event_file)) {
127 		if (input[0] != '#') {
128 			s = input + strspn(input, " \t\r\n");
129 			if ((*s == '\0') || (*s == '#')) {
130 				continue;
131 			}
132 			found = 1;
133 			s = input;
134 
135 			/* parse number */
136 			i = strcspn(s, ":");
137 			s[i] = '\0';
138 			(void) sscanf(s, "%hd", &au_event_entry->ae_number);
139 			s = &s[i+1];
140 
141 			/* parse event name */
142 			i = strcspn(s, ":");
143 			s[i] = '\0';
144 			(void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s",
145 			    trim_buf);
146 			(void) strncpy(au_event_entry->ae_name, trim_buf,
147 				AU_EVENT_NAME_MAX);
148 			s = &s[i+1];
149 
150 			/* parse event description */
151 			i = strcspn(s, ":");
152 			s[i] = '\0';
153 			(void) strncpy(au_event_entry->ae_desc, s,
154 				AU_EVENT_DESC_MAX);
155 			s = &s[i+1];
156 
157 			/* parse class */
158 			i = strcspn(s, "\n\0");
159 			s[i] = '\0';
160 			(void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s",
161 			    trim_buf);
162 			au_event_entry->ae_class = flagstohex(trim_buf);
163 			if (cacheauclass_failure == 1) {
164 				error = 1;
165 				cacheauclass_failure = 0;
166 			}
167 
168 			break;
169 		}
170 	}
171 	_mutex_unlock(&mutex_eventfile);
172 
173 	if (!error && found) {
174 		return (au_event_entry);
175 	} else {
176 		return ((au_event_ent_t *)0);
177 	}
178 }
179 
180 
181 au_event_ent_t *
182 #ifdef __STDC__
183 getauevnam(char *name)
184 #else
185 getauevnam(name)
186 	char *name;
187 #endif
188 {
189 	static au_event_ent_t au_event_entry;
190 	static char	ename[AU_EVENT_NAME_MAX];
191 	static char	edesc[AU_EVENT_DESC_MAX];
192 
193 	/* initialize au_event_entry structure */
194 	au_event_entry.ae_name = ename;
195 	au_event_entry.ae_desc = edesc;
196 
197 	return (getauevnam_r(&au_event_entry, name));
198 }
199 
200 au_event_ent_t *
201 #ifdef __STDC__
202 getauevnam_r(au_event_ent_t *e, char *name)
203 #else
204 getauevnam_r(e, name)
205 	au_event_ent_t &e;
206 	char *name;
207 #endif
208 {
209 	setauevent();
210 	while (getauevent_r(e) != NULL) {
211 		if (strcmp(e->ae_name, name) == 0) {
212 			endauevent();
213 			return (e);
214 		}
215 	}
216 	endauevent();
217 	return ((au_event_ent_t *)NULL);
218 }
219 
220 au_event_ent_t *
221 #ifdef __STDC__
222 getauevnum_r(au_event_ent_t *e, au_event_t event_number)
223 #else
224 getauevnum_r(e, event_number)
225 	au_event_ent_t *e;
226 	au_event_t event_number;
227 #endif
228 {
229 	setauevent();
230 	while (getauevent_r(e) != NULL) {
231 		if (e->ae_number == event_number) {
232 			endauevent();
233 			return (e);
234 		}
235 	}
236 	endauevent();
237 	return ((au_event_ent_t *)NULL);
238 }
239 
240 au_event_ent_t *
241 #ifdef __STDC__
242 getauevnum(au_event_t event_number)
243 #else
244 getauevnum(event_number)
245 	au_event_t event_number;
246 #endif
247 {
248 	static au_event_ent_t e;
249 	static char	ename[AU_EVENT_NAME_MAX];
250 	static char	edesc[AU_EVENT_DESC_MAX];
251 
252 	/* initialize au_event_entry structure */
253 	e.ae_name = ename;
254 	e.ae_desc = edesc;
255 
256 	return (getauevnum_r(&e, event_number));
257 }
258 
259 au_event_t
260 #ifdef __STDC__
261 getauevnonam(char *event_name)
262 #else
263 getauevnonam(event_name)
264 	char	*event_name;
265 #endif
266 {
267 	au_event_ent_t e;
268 	char ename[AU_EVENT_NAME_MAX];
269 	char edesc[AU_EVENT_DESC_MAX];
270 
271 	/* initialize au_event_entry structure */
272 	e.ae_name = ename;
273 	e.ae_desc = edesc;
274 
275 	if (getauevnam_r(&e, event_name) == (au_event_ent_t *)0) {
276 		return (-1);
277 	}
278 	return (e.ae_number);
279 }
280 
281 /*
282  * cacheauevent:
283  *	Read the entire audit_event file into memory.
284  *	Set a pointer to the requested entry in the cache
285  *	or a pointer to an invalid entry if the event number
286  *	is not known.
287  *
288  *	Return < 0, if error.
289  *	Return   0, if event number not in cache.
290  *	Return   1, if event number is in cache.
291  */
292 
293 int
294 #ifdef __STDC__
295 cacheauevent(au_event_ent_t **result, au_event_t event_number)
296 #else
297 cacheauevent(result, event_number)
298 	au_event_ent_t **result; /* set this pointer to an entry in the cache */
299 	au_event_t event_number; /* request this event number */
300 #endif
301 {
302 	static ushort_t	max; /* the highest event number in the file */
303 	static ushort_t	min; /* the lowest event number in the file */
304 	static int	invalid; /* 1+index of the highest event number */
305 	static au_event_ent_t **index_tbl;
306 	static au_event_ent_t **p_tbl;
307 	static int	called_once = 0;
308 
309 	char	line[AU_EVENT_LINE_MAX];
310 	int	lines = 0;
311 	FILE	*fp;
312 	au_event_ent_t *p_event;
313 	int	i, size;
314 	int	hit = 0;
315 	char	*s;
316 
317 	_mutex_lock(&mutex_eventcache);
318 	if (called_once == 0) {
319 
320 		/* Count number of lines in the events file */
321 		if ((fp = fopen(au_event_fname, "rF")) == NULL) {
322 			_mutex_unlock(&mutex_eventcache);
323 			return (-1);
324 		}
325 		while (fgets(line, AU_EVENT_LINE_MAX, fp) != NULL) {
326 			s = line + strspn(line, " \t\r\n");
327 			if ((*s == '\0') || (*s == '#')) {
328 				continue;
329 			}
330 			lines++;
331 		}
332 		(void) fclose(fp);
333 		size = lines;
334 
335 		/*
336 		 * Make an array in which each element in an entry in the
337 		 * events file.  Make the next to last element an invalid
338 		 * event.  Make the last element a NULL pointer.
339 		 */
340 
341 		p_tbl = calloc(lines + 1, sizeof (au_event_ent_t));
342 		if (p_tbl == NULL) {
343 			_mutex_unlock(&mutex_eventcache);
344 			return (-2);
345 		}
346 		lines = 0;
347 		max = 0;
348 		min = 65535;
349 		setauevent();
350 		while ((p_event = getauevent()) != NULL) {
351 			p_tbl[lines] = (au_event_ent_t *)
352 				malloc(sizeof (au_event_ent_t));
353 			if (p_tbl[lines] == NULL) {
354 				_mutex_unlock(&mutex_eventcache);
355 				return (-3);
356 			}
357 			p_tbl[lines]->ae_number = p_event->ae_number;
358 			p_tbl[lines]->ae_name   = strdup(p_event->ae_name);
359 			p_tbl[lines]->ae_desc   = strdup(p_event->ae_desc);
360 			p_tbl[lines]->ae_class  = p_event->ae_class;
361 #ifdef DEBUG2
362 			printevent(p_tbl[lines]);
363 #endif
364 			if ((ushort_t)p_event->ae_number > max) {
365 				max = p_event->ae_number;
366 			}
367 			if ((ushort_t)p_event->ae_number < min) {
368 				min = p_event->ae_number;
369 			}
370 			lines++;
371 		}
372 		endauevent();
373 		invalid = lines;
374 		p_tbl[invalid] = (au_event_ent_t *)
375 			malloc(sizeof (au_event_ent_t));
376 		if (p_tbl[invalid] == NULL) {
377 			_mutex_unlock(&mutex_eventcache);
378 			return (-4);
379 		}
380 		p_tbl[invalid]->ae_number = -1;
381 		p_tbl[invalid]->ae_name   = "invalid event number";
382 		p_tbl[invalid]->ae_desc   = p_tbl[invalid]->ae_name;
383 		p_tbl[invalid]->ae_class  = (au_class_t)-1;
384 
385 #ifdef DEBUG2
386 		for (i = 0; i < size; i++) {
387 			printf("%d:%s:%s:%d\n", p_tbl[i]->ae_number,
388 				p_tbl[i]->ae_name, p_tbl[i]->ae_desc,
389 				p_tbl[i]->ae_class);
390 		}
391 #endif
392 
393 		/* get space for the index_tbl */
394 		index_tbl = calloc(max+1, sizeof (au_event_ent_t *));
395 		if (index_tbl == NULL) {
396 			_mutex_unlock(&mutex_eventcache);
397 			return (-5);
398 		}
399 
400 		/* intialize the index_tbl to the invalid event number */
401 		for (i = 0; (ushort_t)i < max; i++) {
402 			index_tbl[i] = p_tbl[invalid];
403 		}
404 
405 		/* point each index_tbl element at the corresponding event */
406 		for (i = 0; i < size; i++) {
407 			index_tbl[(ushort_t)p_tbl[i]->ae_number] = p_tbl[i];
408 		}
409 
410 		called_once = 1;
411 
412 	}
413 
414 	if ((ushort_t)event_number > max || (ushort_t)event_number < min) {
415 		*result = index_tbl[invalid];
416 	} else {
417 		*result = index_tbl[(ushort_t)event_number];
418 		hit = 1;
419 	}
420 	_mutex_unlock(&mutex_eventcache);
421 	return (hit);
422 }
423 
424 
425 static au_class_t
426 flagstohex(char *flags)
427 {
428 	au_class_ent_t *p_class;
429 	au_class_t	hex = 0;
430 	char	*comma = ",";
431 	char	*s;
432 	char	*last;
433 
434 	s = strtok_r(flags, comma, &last);
435 	while (s != NULL) {
436 		if ((cacheauclassnam(&p_class, s)) < 0) {
437 			cacheauclass_failure = 1;
438 			return ((au_class_t)-1);
439 		}
440 		hex |= p_class->ac_class;
441 		s = strtok_r(NULL, comma, &last);
442 	}
443 	return (hex);
444 }
445 
446 
447 #ifdef DEBUG2
448 void
449 printevent(p_event)
450 au_event_ent_t *p_event;
451 {
452 	printf("%d:%s:%s:%d\n", p_event->ae_number, p_event->ae_name,
453 		p_event->ae_desc, p_event->ae_class);
454 	fflush(stdout);
455 }
456 
457 
458 #endif
459