xref: /onnv-gate/usr/src/lib/libbsm/common/audit_class.c (revision 12435:8eac922eb3e5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
216812Sraf 
220Sstevel@tonic-gate /*
2312326Sgww@eng.sun.com  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Interfaces to audit_class(5)  (/etc/security/audit_class)
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <limits.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <bsm/audit.h>
350Sstevel@tonic-gate #include <bsm/libbsm.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <synch.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate static char	au_class_fname[PATH_MAX] = AUDITCLASSFILE;
400Sstevel@tonic-gate static FILE	*au_class_file = NULL;
410Sstevel@tonic-gate static mutex_t	mutex_classfile = DEFAULTMUTEX;
420Sstevel@tonic-gate static mutex_t	mutex_classcache = DEFAULTMUTEX;
430Sstevel@tonic-gate 
4411706SJan.Friedel@Sun.COM #ifdef DEBUG2
4511706SJan.Friedel@Sun.COM void
printclass(au_class_ent_t * p_c)4611706SJan.Friedel@Sun.COM printclass(au_class_ent_t *p_c)
4711706SJan.Friedel@Sun.COM {
4811706SJan.Friedel@Sun.COM 	(void) printf("%x:%s:%s\n", p_c->ac_class, p_c->ac_name, p_c->ac_desc);
4911706SJan.Friedel@Sun.COM 	(void) fflush(stdout);
5011706SJan.Friedel@Sun.COM }
5111706SJan.Friedel@Sun.COM #endif
5211706SJan.Friedel@Sun.COM 
530Sstevel@tonic-gate void
setauclass()540Sstevel@tonic-gate setauclass()
550Sstevel@tonic-gate {
566812Sraf 	(void) mutex_lock(&mutex_classfile);
570Sstevel@tonic-gate 	if (au_class_file) {
580Sstevel@tonic-gate 		(void) fseek(au_class_file, 0L, 0);
590Sstevel@tonic-gate 	}
606812Sraf 	(void) mutex_unlock(&mutex_classfile);
610Sstevel@tonic-gate }
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 
640Sstevel@tonic-gate void
endauclass()650Sstevel@tonic-gate endauclass()
660Sstevel@tonic-gate {
676812Sraf 	(void) mutex_lock(&mutex_classfile);
680Sstevel@tonic-gate 	if (au_class_file) {
690Sstevel@tonic-gate 		(void) fclose(au_class_file);
700Sstevel@tonic-gate 		au_class_file = NULL;
710Sstevel@tonic-gate 	}
726812Sraf 	(void) mutex_unlock(&mutex_classfile);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * getauclassent():
770Sstevel@tonic-gate  *	This is not MT-safe because of the static variables.
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate au_class_ent_t *
getauclassent()800Sstevel@tonic-gate getauclassent()
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	static au_class_ent_t e;
830Sstevel@tonic-gate 	static char	cname[AU_CLASS_NAME_MAX];
840Sstevel@tonic-gate 	static char	cdesc[AU_CLASS_DESC_MAX];
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	e.ac_name = cname;
870Sstevel@tonic-gate 	e.ac_desc = cdesc;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	return (getauclassent_r(&e));
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * getauclassent_r
940Sstevel@tonic-gate  *	This is MT-safe if each thread passes in its own pointer
950Sstevel@tonic-gate  *	to the space where the class entry is returned.  Becareful
960Sstevel@tonic-gate  *	to also allocate space from the cname and cdesc pointers
970Sstevel@tonic-gate  *	in the au_class_ent structure.
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate au_class_ent_t *
getauclassent_r(au_class_ent_t * au_class_entry)1008743SMarek.Pospisil@Sun.COM getauclassent_r(au_class_ent_t *au_class_entry)
1010Sstevel@tonic-gate {
102*12435SJan.Friedel@Sun.COM 	int		i, error = 0, found = 0;
103*12435SJan.Friedel@Sun.COM 	char		*s, input[256];
104*12435SJan.Friedel@Sun.COM 	au_class_t	v;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	if (au_class_entry == (au_class_ent_t *)NULL ||
1078743SMarek.Pospisil@Sun.COM 	    au_class_entry->ac_name == (char *)NULL ||
1088743SMarek.Pospisil@Sun.COM 	    au_class_entry->ac_desc == (char *)NULL) {
109*12435SJan.Friedel@Sun.COM 		return (NULL);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* open audit class file if it isn't already */
1136812Sraf 	(void) mutex_lock(&mutex_classfile);
1140Sstevel@tonic-gate 	if (!au_class_file) {
1151914Scasper 		if (!(au_class_file = fopen(au_class_fname, "rF"))) {
1166812Sraf 			(void) mutex_unlock(&mutex_classfile);
117*12435SJan.Friedel@Sun.COM 			return (NULL);
1180Sstevel@tonic-gate 		}
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	while (fgets(input, 256, au_class_file)) {
1220Sstevel@tonic-gate 		if (input[0] != '#') {
1230Sstevel@tonic-gate 			s = input + strspn(input, " \t\r\n");
1240Sstevel@tonic-gate 			if ((*s == '\0') || (*s == '#')) {
1250Sstevel@tonic-gate 				continue;
1260Sstevel@tonic-gate 			}
1270Sstevel@tonic-gate 			found = 1;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 			/* parse bitfield */
1300Sstevel@tonic-gate 			i = strcspn(s, ":");
1310Sstevel@tonic-gate 			s[i] = '\0';
1320Sstevel@tonic-gate 			if (strncmp(s, "0x", 2) == 0) {
133*12435SJan.Friedel@Sun.COM 				(void) sscanf(&s[2], "%x", &v);
1340Sstevel@tonic-gate 			} else {
135*12435SJan.Friedel@Sun.COM 				(void) sscanf(s, "%u", &v);
1360Sstevel@tonic-gate 			}
1370Sstevel@tonic-gate 			au_class_entry->ac_class = v;
1380Sstevel@tonic-gate 			s = &s[i+1];
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 			/* parse class name */
1410Sstevel@tonic-gate 			i = strcspn(s, ":");
1420Sstevel@tonic-gate 			s[i] = '\0';
1430Sstevel@tonic-gate 			(void) strncpy(au_class_entry->ac_name, s,
1440Sstevel@tonic-gate 			    AU_CLASS_NAME_MAX);
1450Sstevel@tonic-gate 			s = &s[i+1];
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 			/* parse class description */
1480Sstevel@tonic-gate 			i = strcspn(s, "\n\0");
1490Sstevel@tonic-gate 			s[i] = '\0';
1500Sstevel@tonic-gate 			(void) strncpy(au_class_entry->ac_desc, s,
1510Sstevel@tonic-gate 			    AU_CLASS_DESC_MAX);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 			break;
1540Sstevel@tonic-gate 		}
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 
1576812Sraf 	(void) mutex_unlock(&mutex_classfile);
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	if (!error && found) {
1600Sstevel@tonic-gate 		return (au_class_entry);
1610Sstevel@tonic-gate 	} else {
162*12435SJan.Friedel@Sun.COM 		return (NULL);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate au_class_ent_t *
getauclassnam(char * name)1680Sstevel@tonic-gate getauclassnam(char *name)
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	static au_class_ent_t e;
1710Sstevel@tonic-gate 	static char	cname[AU_CLASS_NAME_MAX];
1720Sstevel@tonic-gate 	static char	cdesc[AU_CLASS_DESC_MAX];
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	e.ac_name = cname;
1750Sstevel@tonic-gate 	e.ac_desc = cdesc;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	return (getauclassnam_r(&e, name));
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate au_class_ent_t *
getauclassnam_r(au_class_ent_t * e,char * name)1810Sstevel@tonic-gate getauclassnam_r(au_class_ent_t *e, char *name)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate 	while (getauclassent_r(e) != NULL) {
18412326Sgww@eng.sun.com 		if (strncmp(e->ac_name, name, AU_CLASS_NAME_MAX) == 0) {
1850Sstevel@tonic-gate 			return (e);
1860Sstevel@tonic-gate 		}
1870Sstevel@tonic-gate 	}
188*12435SJan.Friedel@Sun.COM 	return (NULL);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * xcacheauclass:
1940Sstevel@tonic-gate  *	Read the entire audit_class file into memory.
1950Sstevel@tonic-gate  *	Return a pointer to the requested entry in the cache
1960Sstevel@tonic-gate  *	or a pointer to an invalid entry if the the class
1970Sstevel@tonic-gate  *	requested is not known.
1980Sstevel@tonic-gate  *
1990Sstevel@tonic-gate  *	Return < 0, do not set result pointer, if error.
2000Sstevel@tonic-gate  *	Return   0, set result pointer to invalid entry, if class not in cache.
2010Sstevel@tonic-gate  *	Return   1, set result pointer to a valid entry, if class is in cache.
2020Sstevel@tonic-gate  */
2030Sstevel@tonic-gate static int
xcacheauclass(au_class_ent_t ** result,char * class_name,au_class_t class_no,int flags)2048743SMarek.Pospisil@Sun.COM xcacheauclass(au_class_ent_t **result, char *class_name, au_class_t class_no,
2058743SMarek.Pospisil@Sun.COM     int flags)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate 	static int	invalid;
2080Sstevel@tonic-gate 	static au_class_ent_t **class_tbl;
2090Sstevel@tonic-gate 	static int	called_once;
2100Sstevel@tonic-gate 	static int	lines = 0;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	char		line[256];
2130Sstevel@tonic-gate 	FILE		*fp;
2140Sstevel@tonic-gate 	au_class_ent_t	*p_class;
2150Sstevel@tonic-gate 	int		i;
2160Sstevel@tonic-gate 	int		hit = 0;
2170Sstevel@tonic-gate 	char		*s;
2180Sstevel@tonic-gate 
2196812Sraf 	(void) mutex_lock(&mutex_classcache);
2200Sstevel@tonic-gate 	if (called_once == 0) {
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		/* Count number of lines in the class file */
2231914Scasper 		if ((fp = fopen(au_class_fname, "rF")) == NULL) {
2246812Sraf 			(void) mutex_unlock(&mutex_classcache);
2250Sstevel@tonic-gate 			return (-1);
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 		while (fgets(line, 256, fp) != NULL) {
2280Sstevel@tonic-gate 			s = line + strspn(line, " \t\r\n");
2290Sstevel@tonic-gate 			if ((*s == '\0') || (*s == '#')) {
2300Sstevel@tonic-gate 				continue;
2310Sstevel@tonic-gate 			}
2320Sstevel@tonic-gate 			lines++;
2330Sstevel@tonic-gate 		}
2340Sstevel@tonic-gate 		(void) fclose(fp);
2350Sstevel@tonic-gate 		class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1,
236*12435SJan.Friedel@Sun.COM 		    sizeof (class_tbl));
2370Sstevel@tonic-gate 		if (class_tbl == NULL) {
2386812Sraf 			(void) mutex_unlock(&mutex_classcache);
2390Sstevel@tonic-gate 			return (-2);
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		lines = 0;
2430Sstevel@tonic-gate 		setauclass();
2440Sstevel@tonic-gate 		/*
2450Sstevel@tonic-gate 		 * This call to getauclassent is protected by
2460Sstevel@tonic-gate 		 * mutex_classcache, so we don't need to use the thread-
2470Sstevel@tonic-gate 		 * safe version (getauclassent_r).
2480Sstevel@tonic-gate 		 */
2490Sstevel@tonic-gate 		while ((p_class = getauclassent()) != NULL) {
2500Sstevel@tonic-gate 			class_tbl[lines] = (au_class_ent_t *)
2518743SMarek.Pospisil@Sun.COM 			    malloc(sizeof (au_class_ent_t));
2520Sstevel@tonic-gate 			if (class_tbl[lines] == NULL) {
2536812Sraf 				(void) mutex_unlock(&mutex_classcache);
2540Sstevel@tonic-gate 				return (-3);
2550Sstevel@tonic-gate 			}
2560Sstevel@tonic-gate 			class_tbl[lines]->ac_name = strdup(p_class->ac_name);
2570Sstevel@tonic-gate 			class_tbl[lines]->ac_class = p_class->ac_class;
2580Sstevel@tonic-gate 			class_tbl[lines]->ac_desc = strdup(p_class->ac_desc);
2590Sstevel@tonic-gate #ifdef DEBUG2
2600Sstevel@tonic-gate 			printclass(class_tbl[lines]);
2610Sstevel@tonic-gate #endif
2620Sstevel@tonic-gate 			lines++;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 		endauclass();
2650Sstevel@tonic-gate 		invalid = lines;
2660Sstevel@tonic-gate 		class_tbl[invalid] = (au_class_ent_t *)
2678743SMarek.Pospisil@Sun.COM 		    malloc(sizeof (au_class_ent_t));
2680Sstevel@tonic-gate 		if (class_tbl[invalid] == NULL) {
2696812Sraf 			(void) mutex_unlock(&mutex_classcache);
2700Sstevel@tonic-gate 			return (-4);
2710Sstevel@tonic-gate 		}
2720Sstevel@tonic-gate 		class_tbl[invalid]->ac_name = "invalid class";
2730Sstevel@tonic-gate 		class_tbl[invalid]->ac_class = 0;
2740Sstevel@tonic-gate 		class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 		called_once = 1;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate #ifdef DEBUG2
2790Sstevel@tonic-gate 		for (i = 0; i <= lines; i++) {
2800Sstevel@tonic-gate 			printclass(class_tbl[i]);
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate #endif
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	} /* END if called_once */
2850Sstevel@tonic-gate 	*result = class_tbl[invalid];
2860Sstevel@tonic-gate 	if (flags & AU_CACHE_NAME) {
2870Sstevel@tonic-gate 		for (i = 0; i < lines; i++) {
28812326Sgww@eng.sun.com 			if (strncmp(class_name, class_tbl[i]->ac_name,
28912326Sgww@eng.sun.com 			    AU_CLASS_NAME_MAX) == 0) {
2900Sstevel@tonic-gate 				*result = class_tbl[i];
2910Sstevel@tonic-gate 				hit = 1;
2920Sstevel@tonic-gate 				break;
2930Sstevel@tonic-gate 			}
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 	} else if (flags & AU_CACHE_NUMBER) {
2960Sstevel@tonic-gate 		for (i = 0; i < lines; i++) {
2970Sstevel@tonic-gate 			if (class_no == class_tbl[i]->ac_class) {
2980Sstevel@tonic-gate 				*result = class_tbl[i];
2990Sstevel@tonic-gate 				hit = 1;
3000Sstevel@tonic-gate 				break;
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 	}
3046812Sraf 	(void) mutex_unlock(&mutex_classcache);
3050Sstevel@tonic-gate 	return (hit);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate int
cacheauclass(au_class_ent_t ** result,au_class_t class_no)3090Sstevel@tonic-gate cacheauclass(au_class_ent_t **result, au_class_t class_no)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	return (xcacheauclass(result, "", class_no, AU_CACHE_NUMBER));
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate int
cacheauclassnam(au_class_ent_t ** result,char * class_name)3150Sstevel@tonic-gate cacheauclassnam(au_class_ent_t **result, char *class_name)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	return (xcacheauclass(result, class_name, (au_class_t)0,
3188743SMarek.Pospisil@Sun.COM 	    AU_CACHE_NAME));
3190Sstevel@tonic-gate }
320