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