OpenSolaris_b135/lib/libbsm/common/audit_class.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Interfaces to audit_class(5)  (/etc/security/audit_class)
 */

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <sys/types.h>
#include <bsm/audit.h>
#include <bsm/libbsm.h>
#include <string.h>
#include <synch.h>

static char	au_class_fname[PATH_MAX] = AUDITCLASSFILE;
static FILE	*au_class_file = NULL;
static mutex_t	mutex_classfile = DEFAULTMUTEX;
static mutex_t	mutex_classcache = DEFAULTMUTEX;

#ifdef DEBUG2
void
printclass(au_class_ent_t *p_c)
{
	(void) printf("%x:%s:%s\n", p_c->ac_class, p_c->ac_name, p_c->ac_desc);
	(void) fflush(stdout);
}
#endif

void
setauclass()
{
	(void) mutex_lock(&mutex_classfile);
	if (au_class_file) {
		(void) fseek(au_class_file, 0L, 0);
	}
	(void) mutex_unlock(&mutex_classfile);
}


void
endauclass()
{
	(void) mutex_lock(&mutex_classfile);
	if (au_class_file) {
		(void) fclose(au_class_file);
		au_class_file = NULL;
	}
	(void) mutex_unlock(&mutex_classfile);
}

/*
 * getauclassent():
 *	This is not MT-safe because of the static variables.
 */
au_class_ent_t *
getauclassent()
{
	static au_class_ent_t e;
	static char	cname[AU_CLASS_NAME_MAX];
	static char	cdesc[AU_CLASS_DESC_MAX];

	e.ac_name = cname;
	e.ac_desc = cdesc;

	return (getauclassent_r(&e));
}

/*
 * getauclassent_r
 *	This is MT-safe if each thread passes in its own pointer
 *	to the space where the class entry is returned.  Becareful
 *	to also allocate space from the cname and cdesc pointers
 *	in the au_class_ent structure.
 */
au_class_ent_t *
getauclassent_r(au_class_ent_t *au_class_entry)
{
	int	i, error = 0, found = 0;
	char	*s, input[256];
	unsigned long v;

	if (au_class_entry == (au_class_ent_t *)NULL ||
	    au_class_entry->ac_name == (char *)NULL ||
	    au_class_entry->ac_desc == (char *)NULL) {
		return ((au_class_ent_t *)NULL);
	}

	/* open audit class file if it isn't already */
	(void) mutex_lock(&mutex_classfile);
	if (!au_class_file) {
		if (!(au_class_file = fopen(au_class_fname, "rF"))) {
			(void) mutex_unlock(&mutex_classfile);
			return ((au_class_ent_t *)0);
		}
	}

	while (fgets(input, 256, au_class_file)) {
		if (input[0] != '#') {
			s = input + strspn(input, " \t\r\n");
			if ((*s == '\0') || (*s == '#')) {
				continue;
			}
			found = 1;
			s = input;

			/* parse bitfield */
			i = strcspn(s, ":");
			s[i] = '\0';
			if (strncmp(s, "0x", 2) == 0) {
				(void) sscanf(&s[2], "%lx", &v);
			} else {
				(void) sscanf(s, "%lu", &v);
			}
			au_class_entry->ac_class = v;
			s = &s[i+1];

			/* parse class name */
			i = strcspn(s, ":");
			s[i] = '\0';
			(void) strncpy(au_class_entry->ac_name, s,
			    AU_CLASS_NAME_MAX);
			s = &s[i+1];

			/* parse class description */
			i = strcspn(s, "\n\0");
			s[i] = '\0';
			(void) strncpy(au_class_entry->ac_desc, s,
			    AU_CLASS_DESC_MAX);

			break;
		}
	}

	(void) mutex_unlock(&mutex_classfile);

	if (!error && found) {
		return (au_class_entry);
	} else {
		return ((au_class_ent_t *)0);
	}
}


au_class_ent_t *
getauclassnam(char *name)
{
	static au_class_ent_t e;
	static char	cname[AU_CLASS_NAME_MAX];
	static char	cdesc[AU_CLASS_DESC_MAX];

	e.ac_name = cname;
	e.ac_desc = cdesc;

	return (getauclassnam_r(&e, name));
}

au_class_ent_t *
getauclassnam_r(au_class_ent_t *e, char *name)
{
	while (getauclassent_r(e) != NULL) {
		if (strcmp(e->ac_name, name) == 0) {
			return (e);
		}
	}
	return ((au_class_ent_t *)NULL);
}


/*
 * xcacheauclass:
 *	Read the entire audit_class file into memory.
 *	Return a pointer to the requested entry in the cache
 *	or a pointer to an invalid entry if the the class
 *	requested is not known.
 *
 *	Return < 0, do not set result pointer, if error.
 *	Return   0, set result pointer to invalid entry, if class not in cache.
 *	Return   1, set result pointer to a valid entry, if class is in cache.
 */
static int
xcacheauclass(au_class_ent_t **result, char *class_name, au_class_t class_no,
    int flags)
{
	static int	invalid;
	static au_class_ent_t **class_tbl;
	static int	called_once;
	static int	lines = 0;

	char		line[256];
	FILE		*fp;
	au_class_ent_t	*p_class;
	int		i;
	int		hit = 0;
	char		*s;

	(void) mutex_lock(&mutex_classcache);
	if (called_once == 0) {

		/* Count number of lines in the class file */
		if ((fp = fopen(au_class_fname, "rF")) == NULL) {
			(void) mutex_unlock(&mutex_classcache);
			return (-1);
		}
		while (fgets(line, 256, fp) != NULL) {
			s = line + strspn(line, " \t\r\n");
			if ((*s == '\0') || (*s == '#')) {
				continue;
			}
			lines++;
		}
		(void) fclose(fp);
		class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1,
		    sizeof (au_class_ent_t));
		if (class_tbl == NULL) {
			(void) mutex_unlock(&mutex_classcache);
			return (-2);
		}

		lines = 0;
		setauclass();
		/*
		 * This call to getauclassent is protected by
		 * mutex_classcache, so we don't need to use the thread-
		 * safe version (getauclassent_r).
		 */
		while ((p_class = getauclassent()) != NULL) {
			class_tbl[lines] = (au_class_ent_t *)
			    malloc(sizeof (au_class_ent_t));
			if (class_tbl[lines] == NULL) {
				(void) mutex_unlock(&mutex_classcache);
				return (-3);
			}
			class_tbl[lines]->ac_name = strdup(p_class->ac_name);
			class_tbl[lines]->ac_class = p_class->ac_class;
			class_tbl[lines]->ac_desc = strdup(p_class->ac_desc);
#ifdef DEBUG2
			printclass(class_tbl[lines]);
#endif
			lines++;
		}
		endauclass();
		invalid = lines;
		class_tbl[invalid] = (au_class_ent_t *)
		    malloc(sizeof (au_class_ent_t));
		if (class_tbl[invalid] == NULL) {
			(void) mutex_unlock(&mutex_classcache);
			return (-4);
		}
		class_tbl[invalid]->ac_name = "invalid class";
		class_tbl[invalid]->ac_class = 0;
		class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name;

		called_once = 1;

#ifdef DEBUG2
		for (i = 0; i <= lines; i++) {
			printclass(class_tbl[i]);
		}
#endif

	} /* END if called_once */
	*result = class_tbl[invalid];
	if (flags & AU_CACHE_NAME) {
		for (i = 0; i < lines; i++) {
			if (strcmp(class_name, class_tbl[i]->ac_name) == 0) {
				*result = class_tbl[i];
				hit = 1;
				break;
			}
		}
	} else if (flags & AU_CACHE_NUMBER) {
		for (i = 0; i < lines; i++) {
			if (class_no == class_tbl[i]->ac_class) {
				*result = class_tbl[i];
				hit = 1;
				break;
			}
		}
	}
	(void) mutex_unlock(&mutex_classcache);
	return (hit);
}

int
cacheauclass(au_class_ent_t **result, au_class_t class_no)
{
	return (xcacheauclass(result, "", class_no, AU_CACHE_NUMBER));
}

int
cacheauclassnam(au_class_ent_t **result, char *class_name)
{
	return (xcacheauclass(result, class_name, (au_class_t)0,
	    AU_CACHE_NAME));
}