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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Interfaces to audit_class(5)  (/etc/security/audit_class)
     29  */
     30 
     31 #include <stdlib.h>
     32 #include <stdio.h>
     33 #include <limits.h>
     34 #include <sys/types.h>
     35 #include <bsm/audit.h>
     36 #include <bsm/libbsm.h>
     37 #include <string.h>
     38 #include <synch.h>
     39 
     40 static char	au_class_fname[PATH_MAX] = AUDITCLASSFILE;
     41 static FILE	*au_class_file = NULL;
     42 static mutex_t	mutex_classfile = DEFAULTMUTEX;
     43 static mutex_t	mutex_classcache = DEFAULTMUTEX;
     44 
     45 void
     46 setauclass()
     47 {
     48 	(void) mutex_lock(&mutex_classfile);
     49 	if (au_class_file) {
     50 		(void) fseek(au_class_file, 0L, 0);
     51 	}
     52 	(void) mutex_unlock(&mutex_classfile);
     53 }
     54 
     55 
     56 void
     57 endauclass()
     58 {
     59 	(void) mutex_lock(&mutex_classfile);
     60 	if (au_class_file) {
     61 		(void) fclose(au_class_file);
     62 		au_class_file = NULL;
     63 	}
     64 	(void) mutex_unlock(&mutex_classfile);
     65 }
     66 
     67 /*
     68  * getauclassent():
     69  *	This is not MT-safe because of the static variables.
     70  */
     71 au_class_ent_t *
     72 getauclassent()
     73 {
     74 	static au_class_ent_t e;
     75 	static char	cname[AU_CLASS_NAME_MAX];
     76 	static char	cdesc[AU_CLASS_DESC_MAX];
     77 
     78 	e.ac_name = cname;
     79 	e.ac_desc = cdesc;
     80 
     81 	return (getauclassent_r(&e));
     82 }
     83 
     84 /*
     85  * getauclassent_r
     86  *	This is MT-safe if each thread passes in its own pointer
     87  *	to the space where the class entry is returned.  Becareful
     88  *	to also allocate space from the cname and cdesc pointers
     89  *	in the au_class_ent structure.
     90  */
     91 au_class_ent_t *
     92 getauclassent_r(au_class_ent_t *au_class_entry)
     93 {
     94 	int	i, error = 0, found = 0;
     95 	char	*s, input[256];
     96 	unsigned long v;
     97 
     98 	if (au_class_entry == (au_class_ent_t *)NULL ||
     99 	    au_class_entry->ac_name == (char *)NULL ||
    100 	    au_class_entry->ac_desc == (char *)NULL) {
    101 		return ((au_class_ent_t *)NULL);
    102 	}
    103 
    104 	/* open audit class file if it isn't already */
    105 	(void) mutex_lock(&mutex_classfile);
    106 	if (!au_class_file) {
    107 		if (!(au_class_file = fopen(au_class_fname, "rF"))) {
    108 			(void) mutex_unlock(&mutex_classfile);
    109 			return ((au_class_ent_t *)0);
    110 		}
    111 	}
    112 
    113 	while (fgets(input, 256, au_class_file)) {
    114 		if (input[0] != '#') {
    115 			s = input + strspn(input, " \t\r\n");
    116 			if ((*s == '\0') || (*s == '#')) {
    117 				continue;
    118 			}
    119 			found = 1;
    120 			s = input;
    121 
    122 			/* parse bitfield */
    123 			i = strcspn(s, ":");
    124 			s[i] = '\0';
    125 			if (strncmp(s, "0x", 2) == 0) {
    126 				(void) sscanf(&s[2], "%lx", &v);
    127 			} else {
    128 				(void) sscanf(s, "%lu", &v);
    129 			}
    130 			au_class_entry->ac_class = v;
    131 			s = &s[i+1];
    132 
    133 			/* parse class name */
    134 			i = strcspn(s, ":");
    135 			s[i] = '\0';
    136 			(void) strncpy(au_class_entry->ac_name, s,
    137 			    AU_CLASS_NAME_MAX);
    138 			s = &s[i+1];
    139 
    140 			/* parse class description */
    141 			i = strcspn(s, "\n\0");
    142 			s[i] = '\0';
    143 			(void) strncpy(au_class_entry->ac_desc, s,
    144 			    AU_CLASS_DESC_MAX);
    145 
    146 			break;
    147 		}
    148 	}
    149 
    150 	(void) mutex_unlock(&mutex_classfile);
    151 
    152 	if (!error && found) {
    153 		return (au_class_entry);
    154 	} else {
    155 		return ((au_class_ent_t *)0);
    156 	}
    157 }
    158 
    159 
    160 au_class_ent_t *
    161 getauclassnam(char *name)
    162 {
    163 	static au_class_ent_t e;
    164 	static char	cname[AU_CLASS_NAME_MAX];
    165 	static char	cdesc[AU_CLASS_DESC_MAX];
    166 
    167 	e.ac_name = cname;
    168 	e.ac_desc = cdesc;
    169 
    170 	return (getauclassnam_r(&e, name));
    171 }
    172 
    173 au_class_ent_t *
    174 getauclassnam_r(au_class_ent_t *e, char *name)
    175 {
    176 	while (getauclassent_r(e) != NULL) {
    177 		if (strcmp(e->ac_name, name) == 0) {
    178 			return (e);
    179 		}
    180 	}
    181 	return ((au_class_ent_t *)NULL);
    182 }
    183 
    184 
    185 /*
    186  * xcacheauclass:
    187  *	Read the entire audit_class file into memory.
    188  *	Return a pointer to the requested entry in the cache
    189  *	or a pointer to an invalid entry if the the class
    190  *	requested is not known.
    191  *
    192  *	Return < 0, do not set result pointer, if error.
    193  *	Return   0, set result pointer to invalid entry, if class not in cache.
    194  *	Return   1, set result pointer to a valid entry, if class is in cache.
    195  */
    196 static int
    197 xcacheauclass(au_class_ent_t **result, char *class_name, au_class_t class_no,
    198     int flags)
    199 {
    200 	static int	invalid;
    201 	static au_class_ent_t **class_tbl;
    202 	static int	called_once;
    203 	static int	lines = 0;
    204 
    205 	char		line[256];
    206 	FILE		*fp;
    207 	au_class_ent_t	*p_class;
    208 	int		i;
    209 	int		hit = 0;
    210 	char		*s;
    211 
    212 	(void) mutex_lock(&mutex_classcache);
    213 	if (called_once == 0) {
    214 
    215 		/* Count number of lines in the class file */
    216 		if ((fp = fopen(au_class_fname, "rF")) == NULL) {
    217 			(void) mutex_unlock(&mutex_classcache);
    218 			return (-1);
    219 		}
    220 		while (fgets(line, 256, fp) != NULL) {
    221 			s = line + strspn(line, " \t\r\n");
    222 			if ((*s == '\0') || (*s == '#')) {
    223 				continue;
    224 			}
    225 			lines++;
    226 		}
    227 		(void) fclose(fp);
    228 		class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1,
    229 		    sizeof (au_class_ent_t));
    230 		if (class_tbl == NULL) {
    231 			(void) mutex_unlock(&mutex_classcache);
    232 			return (-2);
    233 		}
    234 
    235 		lines = 0;
    236 		setauclass();
    237 		/*
    238 		 * This call to getauclassent is protected by
    239 		 * mutex_classcache, so we don't need to use the thread-
    240 		 * safe version (getauclassent_r).
    241 		 */
    242 		while ((p_class = getauclassent()) != NULL) {
    243 			class_tbl[lines] = (au_class_ent_t *)
    244 			    malloc(sizeof (au_class_ent_t));
    245 			if (class_tbl[lines] == NULL) {
    246 				(void) mutex_unlock(&mutex_classcache);
    247 				return (-3);
    248 			}
    249 			class_tbl[lines]->ac_name = strdup(p_class->ac_name);
    250 			class_tbl[lines]->ac_class = p_class->ac_class;
    251 			class_tbl[lines]->ac_desc = strdup(p_class->ac_desc);
    252 #ifdef DEBUG2
    253 			printclass(class_tbl[lines]);
    254 #endif
    255 			lines++;
    256 		}
    257 		endauclass();
    258 		invalid = lines;
    259 		class_tbl[invalid] = (au_class_ent_t *)
    260 		    malloc(sizeof (au_class_ent_t));
    261 		if (class_tbl[invalid] == NULL) {
    262 			(void) mutex_unlock(&mutex_classcache);
    263 			return (-4);
    264 		}
    265 		class_tbl[invalid]->ac_name = "invalid class";
    266 		class_tbl[invalid]->ac_class = 0;
    267 		class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name;
    268 
    269 		called_once = 1;
    270 
    271 #ifdef DEBUG2
    272 		for (i = 0; i <= lines; i++) {
    273 			printclass(class_tbl[i]);
    274 		}
    275 #endif
    276 
    277 	} /* END if called_once */
    278 	*result = class_tbl[invalid];
    279 	if (flags & AU_CACHE_NAME) {
    280 		for (i = 0; i < lines; i++) {
    281 			if (strcmp(class_name, class_tbl[i]->ac_name) == 0) {
    282 				*result = class_tbl[i];
    283 				hit = 1;
    284 				break;
    285 			}
    286 		}
    287 	} else if (flags & AU_CACHE_NUMBER) {
    288 		for (i = 0; i < lines; i++) {
    289 			if (class_no == class_tbl[i]->ac_class) {
    290 				*result = class_tbl[i];
    291 				hit = 1;
    292 				break;
    293 			}
    294 		}
    295 	}
    296 	(void) mutex_unlock(&mutex_classcache);
    297 	return (hit);
    298 }
    299 
    300 
    301 int
    302 cacheauclass(au_class_ent_t **result, au_class_t class_no)
    303 {
    304 	return (xcacheauclass(result, "", class_no, AU_CACHE_NUMBER));
    305 }
    306 
    307 
    308 int
    309 cacheauclassnam(au_class_ent_t **result, char *class_name)
    310 {
    311 	return (xcacheauclass(result, class_name, (au_class_t)0,
    312 	    AU_CACHE_NAME));
    313 }
    314 
    315 
    316 #ifdef DEBUG2
    317 void
    318 printclass(p_c)
    319 au_class_ent_t *p_c;
    320 {
    321 	printf("%x:%s:%s\n", p_c->ac_class, p_c->ac_name, p_c->ac_desc);
    322 	fflush(stdout);
    323 }
    324 
    325 
    326 #endif
    327