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