17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
23f8804e7fSgww  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Interfaces to audit_class(5)  (/etc/security/audit_class)
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <limits.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <bsm/audit.h>
357c478bd9Sstevel@tonic-gate #include <bsm/libbsm.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <synch.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate static char	au_class_fname[PATH_MAX] = AUDITCLASSFILE;
407c478bd9Sstevel@tonic-gate static FILE	*au_class_file = NULL;
417c478bd9Sstevel@tonic-gate static mutex_t	mutex_classfile = DEFAULTMUTEX;
427c478bd9Sstevel@tonic-gate static mutex_t	mutex_classcache = DEFAULTMUTEX;
437c478bd9Sstevel@tonic-gate 
44dfc7be02SJan Friedel #ifdef DEBUG2
45dfc7be02SJan Friedel void
printclass(au_class_ent_t * p_c)46dfc7be02SJan Friedel printclass(au_class_ent_t *p_c)
47dfc7be02SJan Friedel {
48dfc7be02SJan Friedel 	(void) printf("%x:%s:%s\n", p_c->ac_class, p_c->ac_name, p_c->ac_desc);
49dfc7be02SJan Friedel 	(void) fflush(stdout);
50dfc7be02SJan Friedel }
51dfc7be02SJan Friedel #endif
52dfc7be02SJan Friedel 
537c478bd9Sstevel@tonic-gate void
setauclass()547c478bd9Sstevel@tonic-gate setauclass()
557c478bd9Sstevel@tonic-gate {
567257d1b4Sraf 	(void) mutex_lock(&mutex_classfile);
577c478bd9Sstevel@tonic-gate 	if (au_class_file) {
587c478bd9Sstevel@tonic-gate 		(void) fseek(au_class_file, 0L, 0);
597c478bd9Sstevel@tonic-gate 	}
607257d1b4Sraf 	(void) mutex_unlock(&mutex_classfile);
617c478bd9Sstevel@tonic-gate }
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate void
endauclass()657c478bd9Sstevel@tonic-gate endauclass()
667c478bd9Sstevel@tonic-gate {
677257d1b4Sraf 	(void) mutex_lock(&mutex_classfile);
687c478bd9Sstevel@tonic-gate 	if (au_class_file) {
697c478bd9Sstevel@tonic-gate 		(void) fclose(au_class_file);
707c478bd9Sstevel@tonic-gate 		au_class_file = NULL;
717c478bd9Sstevel@tonic-gate 	}
727257d1b4Sraf 	(void) mutex_unlock(&mutex_classfile);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  * getauclassent():
777c478bd9Sstevel@tonic-gate  *	This is not MT-safe because of the static variables.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate au_class_ent_t *
getauclassent()807c478bd9Sstevel@tonic-gate getauclassent()
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate 	static au_class_ent_t e;
837c478bd9Sstevel@tonic-gate 	static char	cname[AU_CLASS_NAME_MAX];
847c478bd9Sstevel@tonic-gate 	static char	cdesc[AU_CLASS_DESC_MAX];
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	e.ac_name = cname;
877c478bd9Sstevel@tonic-gate 	e.ac_desc = cdesc;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	return (getauclassent_r(&e));
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * getauclassent_r
947c478bd9Sstevel@tonic-gate  *	This is MT-safe if each thread passes in its own pointer
957c478bd9Sstevel@tonic-gate  *	to the space where the class entry is returned.  Becareful
967c478bd9Sstevel@tonic-gate  *	to also allocate space from the cname and cdesc pointers
977c478bd9Sstevel@tonic-gate  *	in the au_class_ent structure.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate au_class_ent_t *
getauclassent_r(au_class_ent_t * au_class_entry)1005707ed5dSMarek Pospisil getauclassent_r(au_class_ent_t *au_class_entry)
1017c478bd9Sstevel@tonic-gate {
102*8ad93184SJan Friedel 	int		i, error = 0, found = 0;
103*8ad93184SJan Friedel 	char		*s, input[256];
104*8ad93184SJan Friedel 	au_class_t	v;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	if (au_class_entry == (au_class_ent_t *)NULL ||
1075707ed5dSMarek Pospisil 	    au_class_entry->ac_name == (char *)NULL ||
1085707ed5dSMarek Pospisil 	    au_class_entry->ac_desc == (char *)NULL) {
109*8ad93184SJan Friedel 		return (NULL);
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/* open audit class file if it isn't already */
1137257d1b4Sraf 	(void) mutex_lock(&mutex_classfile);
1147c478bd9Sstevel@tonic-gate 	if (!au_class_file) {
115004388ebScasper 		if (!(au_class_file = fopen(au_class_fname, "rF"))) {
1167257d1b4Sraf 			(void) mutex_unlock(&mutex_classfile);
117*8ad93184SJan Friedel 			return (NULL);
1187c478bd9Sstevel@tonic-gate 		}
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	while (fgets(input, 256, au_class_file)) {
1227c478bd9Sstevel@tonic-gate 		if (input[0] != '#') {
1237c478bd9Sstevel@tonic-gate 			s = input + strspn(input, " \t\r\n");
1247c478bd9Sstevel@tonic-gate 			if ((*s == '\0') || (*s == '#')) {
1257c478bd9Sstevel@tonic-gate 				continue;
1267c478bd9Sstevel@tonic-gate 			}
1277c478bd9Sstevel@tonic-gate 			found = 1;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 			/* parse bitfield */
1307c478bd9Sstevel@tonic-gate 			i = strcspn(s, ":");
1317c478bd9Sstevel@tonic-gate 			s[i] = '\0';
1327c478bd9Sstevel@tonic-gate 			if (strncmp(s, "0x", 2) == 0) {
133*8ad93184SJan Friedel 				(void) sscanf(&s[2], "%x", &v);
1347c478bd9Sstevel@tonic-gate 			} else {
135*8ad93184SJan Friedel 				(void) sscanf(s, "%u", &v);
1367c478bd9Sstevel@tonic-gate 			}
1377c478bd9Sstevel@tonic-gate 			au_class_entry->ac_class = v;
1387c478bd9Sstevel@tonic-gate 			s = &s[i+1];
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 			/* parse class name */
1417c478bd9Sstevel@tonic-gate 			i = strcspn(s, ":");
1427c478bd9Sstevel@tonic-gate 			s[i] = '\0';
1437c478bd9Sstevel@tonic-gate 			(void) strncpy(au_class_entry->ac_name, s,
1447c478bd9Sstevel@tonic-gate 			    AU_CLASS_NAME_MAX);
1457c478bd9Sstevel@tonic-gate 			s = &s[i+1];
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 			/* parse class description */
1487c478bd9Sstevel@tonic-gate 			i = strcspn(s, "\n\0");
1497c478bd9Sstevel@tonic-gate 			s[i] = '\0';
1507c478bd9Sstevel@tonic-gate 			(void) strncpy(au_class_entry->ac_desc, s,
1517c478bd9Sstevel@tonic-gate 			    AU_CLASS_DESC_MAX);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 			break;
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577257d1b4Sraf 	(void) mutex_unlock(&mutex_classfile);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (!error && found) {
1607c478bd9Sstevel@tonic-gate 		return (au_class_entry);
1617c478bd9Sstevel@tonic-gate 	} else {
162*8ad93184SJan Friedel 		return (NULL);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate au_class_ent_t *
getauclassnam(char * name)1687c478bd9Sstevel@tonic-gate getauclassnam(char *name)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	static au_class_ent_t e;
1717c478bd9Sstevel@tonic-gate 	static char	cname[AU_CLASS_NAME_MAX];
1727c478bd9Sstevel@tonic-gate 	static char	cdesc[AU_CLASS_DESC_MAX];
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	e.ac_name = cname;
1757c478bd9Sstevel@tonic-gate 	e.ac_desc = cdesc;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	return (getauclassnam_r(&e, name));
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate au_class_ent_t *
getauclassnam_r(au_class_ent_t * e,char * name)1817c478bd9Sstevel@tonic-gate getauclassnam_r(au_class_ent_t *e, char *name)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	while (getauclassent_r(e) != NULL) {
184f8804e7fSgww 		if (strncmp(e->ac_name, name, AU_CLASS_NAME_MAX) == 0) {
1857c478bd9Sstevel@tonic-gate 			return (e);
1867c478bd9Sstevel@tonic-gate 		}
1877c478bd9Sstevel@tonic-gate 	}
188*8ad93184SJan Friedel 	return (NULL);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate  * xcacheauclass:
1947c478bd9Sstevel@tonic-gate  *	Read the entire audit_class file into memory.
1957c478bd9Sstevel@tonic-gate  *	Return a pointer to the requested entry in the cache
1967c478bd9Sstevel@tonic-gate  *	or a pointer to an invalid entry if the the class
1977c478bd9Sstevel@tonic-gate  *	requested is not known.
1987c478bd9Sstevel@tonic-gate  *
1997c478bd9Sstevel@tonic-gate  *	Return < 0, do not set result pointer, if error.
2007c478bd9Sstevel@tonic-gate  *	Return   0, set result pointer to invalid entry, if class not in cache.
2017c478bd9Sstevel@tonic-gate  *	Return   1, set result pointer to a valid entry, if class is in cache.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate static int
xcacheauclass(au_class_ent_t ** result,char * class_name,au_class_t class_no,int flags)2045707ed5dSMarek Pospisil xcacheauclass(au_class_ent_t **result, char *class_name, au_class_t class_no,
2055707ed5dSMarek Pospisil     int flags)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	static int	invalid;
2087c478bd9Sstevel@tonic-gate 	static au_class_ent_t **class_tbl;
2097c478bd9Sstevel@tonic-gate 	static int	called_once;
2107c478bd9Sstevel@tonic-gate 	static int	lines = 0;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	char		line[256];
2137c478bd9Sstevel@tonic-gate 	FILE		*fp;
2147c478bd9Sstevel@tonic-gate 	au_class_ent_t	*p_class;
2157c478bd9Sstevel@tonic-gate 	int		i;
2167c478bd9Sstevel@tonic-gate 	int		hit = 0;
2177c478bd9Sstevel@tonic-gate 	char		*s;
2187c478bd9Sstevel@tonic-gate 
2197257d1b4Sraf 	(void) mutex_lock(&mutex_classcache);
2207c478bd9Sstevel@tonic-gate 	if (called_once == 0) {
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 		/* Count number of lines in the class file */
223004388ebScasper 		if ((fp = fopen(au_class_fname, "rF")) == NULL) {
2247257d1b4Sraf 			(void) mutex_unlock(&mutex_classcache);
2257c478bd9Sstevel@tonic-gate 			return (-1);
2267c478bd9Sstevel@tonic-gate 		}
2277c478bd9Sstevel@tonic-gate 		while (fgets(line, 256, fp) != NULL) {
2287c478bd9Sstevel@tonic-gate 			s = line + strspn(line, " \t\r\n");
2297c478bd9Sstevel@tonic-gate 			if ((*s == '\0') || (*s == '#')) {
2307c478bd9Sstevel@tonic-gate 				continue;
2317c478bd9Sstevel@tonic-gate 			}
2327c478bd9Sstevel@tonic-gate 			lines++;
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
2357c478bd9Sstevel@tonic-gate 		class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1,
236*8ad93184SJan Friedel 		    sizeof (class_tbl));
2377c478bd9Sstevel@tonic-gate 		if (class_tbl == NULL) {
2387257d1b4Sraf 			(void) mutex_unlock(&mutex_classcache);
2397c478bd9Sstevel@tonic-gate 			return (-2);
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		lines = 0;
2437c478bd9Sstevel@tonic-gate 		setauclass();
2447c478bd9Sstevel@tonic-gate 		/*
2457c478bd9Sstevel@tonic-gate 		 * This call to getauclassent is protected by
2467c478bd9Sstevel@tonic-gate 		 * mutex_classcache, so we don't need to use the thread-
2477c478bd9Sstevel@tonic-gate 		 * safe version (getauclassent_r).
2487c478bd9Sstevel@tonic-gate 		 */
2497c478bd9Sstevel@tonic-gate 		while ((p_class = getauclassent()) != NULL) {
2507c478bd9Sstevel@tonic-gate 			class_tbl[lines] = (au_class_ent_t *)
2515707ed5dSMarek Pospisil 			    malloc(sizeof (au_class_ent_t));
2527c478bd9Sstevel@tonic-gate 			if (class_tbl[lines] == NULL) {
2537257d1b4Sraf 				(void) mutex_unlock(&mutex_classcache);
2547c478bd9Sstevel@tonic-gate 				return (-3);
2557c478bd9Sstevel@tonic-gate 			}
2567c478bd9Sstevel@tonic-gate 			class_tbl[lines]->ac_name = strdup(p_class->ac_name);
2577c478bd9Sstevel@tonic-gate 			class_tbl[lines]->ac_class = p_class->ac_class;
2587c478bd9Sstevel@tonic-gate 			class_tbl[lines]->ac_desc = strdup(p_class->ac_desc);
2597c478bd9Sstevel@tonic-gate #ifdef DEBUG2
2607c478bd9Sstevel@tonic-gate 			printclass(class_tbl[lines]);
2617c478bd9Sstevel@tonic-gate #endif
2627c478bd9Sstevel@tonic-gate 			lines++;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		endauclass();
2657c478bd9Sstevel@tonic-gate 		invalid = lines;
2667c478bd9Sstevel@tonic-gate 		class_tbl[invalid] = (au_class_ent_t *)
2675707ed5dSMarek Pospisil 		    malloc(sizeof (au_class_ent_t));
2687c478bd9Sstevel@tonic-gate 		if (class_tbl[invalid] == NULL) {
2697257d1b4Sraf 			(void) mutex_unlock(&mutex_classcache);
2707c478bd9Sstevel@tonic-gate 			return (-4);
2717c478bd9Sstevel@tonic-gate 		}
2727c478bd9Sstevel@tonic-gate 		class_tbl[invalid]->ac_name = "invalid class";
2737c478bd9Sstevel@tonic-gate 		class_tbl[invalid]->ac_class = 0;
2747c478bd9Sstevel@tonic-gate 		class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		called_once = 1;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate #ifdef DEBUG2
2797c478bd9Sstevel@tonic-gate 		for (i = 0; i <= lines; i++) {
2807c478bd9Sstevel@tonic-gate 			printclass(class_tbl[i]);
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate #endif
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	} /* END if called_once */
2857c478bd9Sstevel@tonic-gate 	*result = class_tbl[invalid];
2867c478bd9Sstevel@tonic-gate 	if (flags & AU_CACHE_NAME) {
2877c478bd9Sstevel@tonic-gate 		for (i = 0; i < lines; i++) {
288f8804e7fSgww 			if (strncmp(class_name, class_tbl[i]->ac_name,
289f8804e7fSgww 			    AU_CLASS_NAME_MAX) == 0) {
2907c478bd9Sstevel@tonic-gate 				*result = class_tbl[i];
2917c478bd9Sstevel@tonic-gate 				hit = 1;
2927c478bd9Sstevel@tonic-gate 				break;
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 	} else if (flags & AU_CACHE_NUMBER) {
2967c478bd9Sstevel@tonic-gate 		for (i = 0; i < lines; i++) {
2977c478bd9Sstevel@tonic-gate 			if (class_no == class_tbl[i]->ac_class) {
2987c478bd9Sstevel@tonic-gate 				*result = class_tbl[i];
2997c478bd9Sstevel@tonic-gate 				hit = 1;
3007c478bd9Sstevel@tonic-gate 				break;
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 	}
3047257d1b4Sraf 	(void) mutex_unlock(&mutex_classcache);
3057c478bd9Sstevel@tonic-gate 	return (hit);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate int
cacheauclass(au_class_ent_t ** result,au_class_t class_no)3097c478bd9Sstevel@tonic-gate cacheauclass(au_class_ent_t **result, au_class_t class_no)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	return (xcacheauclass(result, "", class_no, AU_CACHE_NUMBER));
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate int
cacheauclassnam(au_class_ent_t ** result,char * class_name)3157c478bd9Sstevel@tonic-gate cacheauclassnam(au_class_ent_t **result, char *class_name)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	return (xcacheauclass(result, class_name, (au_class_t)0,
3185707ed5dSMarek Pospisil 	    AU_CACHE_NAME));
3197c478bd9Sstevel@tonic-gate }
320