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 {
1027c478bd9Sstevel@tonic-gate int i, error = 0, found = 0;
1037c478bd9Sstevel@tonic-gate 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 ||
1077c478bd9Sstevel@tonic-gate au_class_entry->ac_name == (char *)NULL ||
1087c478bd9Sstevel@tonic-gate 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 *)
2517c478bd9Sstevel@tonic-gate 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 *)
2677c478bd9Sstevel@tonic-gate 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,
3187c478bd9Sstevel@tonic-gate AU_CACHE_NAME));
3197c478bd9Sstevel@tonic-gate }
320