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