147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * String representation support for classes and permissions.
347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/stat.h>
547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <dirent.h>
647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <fcntl.h>
747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <limits.h>
847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <unistd.h>
947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <errno.h>
1047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stddef.h>
1147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdio.h>
1247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdlib.h>
1347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <string.h>
1447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdint.h>
1547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <ctype.h>
1647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "selinux_internal.h"
1747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "policy.h"
1847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "mapping.h"
1947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
2147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#define MAXVECTORS 8*sizeof(access_vector_t)
2347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic pthread_once_t once = PTHREAD_ONCE_INIT;
2547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstruct discover_class_node {
2747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *name;
2847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	security_class_t value;
2947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char **perms;
3047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *next;
3247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner};
3347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct discover_class_node *discover_class_cache = NULL;
3547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct discover_class_node * get_class_cache_entry_name(const char *s)
3747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
3847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node = discover_class_cache;
3947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
4147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return node;
4347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
4447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct discover_class_node * get_class_cache_entry_value(security_class_t c)
4647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
4747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node = discover_class_cache;
4847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (; node != NULL && c != node->value; node = node->next);
5047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return node;
5247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
5347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct discover_class_node * discover_class(const char *s)
5547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
5647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int fd, ret;
5747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char path[PATH_MAX];
5847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char buf[20];
5947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	DIR *dir;
6047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct dirent *dentry;
6147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t i;
6247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node;
6447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!selinux_mnt) {
6647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = ENOENT;
6747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return NULL;
6847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
6947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* allocate a node */
7147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node = malloc(sizeof(struct discover_class_node));
7247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node == NULL)
7347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return NULL;
7447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* allocate array for perms */
7647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node->perms = calloc(MAXVECTORS,sizeof(char*));
7747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node->perms == NULL)
7847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err1;
7947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* load up the name */
8147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node->name = strdup(s);
8247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node->name == NULL)
8347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err2;
8447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* load up class index */
8647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
8747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fd = open(path, O_RDONLY);
8847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (fd < 0)
8947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err3;
9047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memset(buf, 0, sizeof(buf));
9247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	ret = read(fd, buf, sizeof(buf) - 1);
9347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	close(fd);
9447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (ret < 0)
9547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err3;
9647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (sscanf(buf, "%hu", &node->value) != 1)
9847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err3;
9947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* load up permission indicies */
10147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
10247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	dir = opendir(path);
10347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (dir == NULL)
10447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err3;
10547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	dentry = readdir(dir);
10747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (dentry != NULL) {
10847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned int value;
10947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct stat m;
11047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
11247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (stat(path,&m) < 0)
11347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err4;
11447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (m.st_mode & S_IFDIR) {
11647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			dentry = readdir(dir);
11747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			continue;
11847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
11947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		fd = open(path, O_RDONLY);
12147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (fd < 0)
12247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err4;
12347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		memset(buf, 0, sizeof(buf));
12547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		ret = read(fd, buf, sizeof(buf) - 1);
12647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		close(fd);
12747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (ret < 0)
12847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err4;
12947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (sscanf(buf, "%u", &value) != 1)
13147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err4;
13247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		node->perms[value-1] = strdup(dentry->d_name);
13447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (node->perms[value-1] == NULL)
13547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err4;
13647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		dentry = readdir(dir);
13847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
13947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	closedir(dir);
14047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node->next = discover_class_cache;
14247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	discover_class_cache = node;
14347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return node;
14547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr4:
14747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	closedir(dir);
14847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i=0; i<MAXVECTORS; i++)
14947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(node->perms[i]);
15047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr3:
15147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(node->name);
15247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr2:
15347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(node->perms);
15447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr1:
15547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(node);
15647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return NULL;
15747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
15847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid flush_class_cache(void)
16047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
16147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
16247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t i;
16347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (cur != NULL) {
16547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(cur->name);
16647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0 ; i<MAXVECTORS ; i++)
16847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			free(cur->perms[i]);
16947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(cur->perms);
17147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		prev = cur;
17347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		cur = cur->next;
17447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(prev);
17647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
17747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	discover_class_cache = NULL;
17947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
18047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnersecurity_class_t string_to_security_class(const char *s)
18247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
18347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node;
18447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node = get_class_cache_entry_name(s);
18647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node == NULL) {
18747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		node = discover_class(s);
18847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (node == NULL) {
19047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			errno = EINVAL;
19147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return 0;
19247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
19347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
19447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return map_class(node->value);
19647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
19747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turneraccess_vector_t string_to_av_perm(security_class_t tclass, const char *s)
19947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
20047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node;
20147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	security_class_t kclass = unmap_class(tclass);
20247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
20347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node = get_class_cache_entry_value(kclass);
20447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node != NULL) {
20547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		size_t i;
20647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
20747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (strcmp(node->perms[i],s) == 0)
20847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				return map_perm(tclass, 1<<i);
20947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
21047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	errno = EINVAL;
21247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
21347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
21447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerconst char *security_class_to_string(security_class_t tclass)
21647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
21747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node;
21847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	tclass = unmap_class(tclass);
22047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node = get_class_cache_entry_value(tclass);
22247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (node)
22347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return node->name;
22447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return NULL;
22547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
22647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerconst char *security_av_perm_to_string(security_class_t tclass,
22847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				       access_vector_t av)
22947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
23047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct discover_class_node *node;
23147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t i;
23247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	av = unmap_perm(tclass, av);
23447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	tclass = unmap_class(tclass);
23547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	node = get_class_cache_entry_value(tclass);
23747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (av && node)
23847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i = 0; i<MAXVECTORS; i++)
23947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if ((1<<i) & av)
24047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				return node->perms[i];
24147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return NULL;
24347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
24447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint security_av_string(security_class_t tclass, access_vector_t av, char **res)
24647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
24747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int i = 0;
24847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t len = 5;
24947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	access_vector_t tmp = av;
25047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc = 0;
25147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *str;
25247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *ptr;
25347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* first pass computes the required length */
25547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (tmp) {
25647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (tmp & 1) {
25747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			str = security_av_perm_to_string(tclass, av & (1<<i));
25847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (str)
25947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				len += strlen(str) + 1;
26047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			else {
26147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rc = -1;
26247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				errno = EINVAL;
26347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto out;
26447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
26547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
26647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		tmp >>= 1;
26747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		i++;
26847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
26947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	*res = malloc(len);
27147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!*res) {
27247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = -1;
27347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto out;
27447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
27547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* second pass constructs the string */
27747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	i = 0;
27847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	tmp = av;
27947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	ptr = *res;
28047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!av) {
28247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		sprintf(ptr, "null");
28347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto out;
28447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
28547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	ptr += sprintf(ptr, "{ ");
28747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (tmp) {
28847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (tmp & 1)
28947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			ptr += sprintf(ptr, "%s ", security_av_perm_to_string(
29047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					       tclass, av & (1<<i)));
29147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		tmp >>= 1;
29247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		i++;
29347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
29447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	sprintf(ptr, "}");
29547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerout:
29647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return rc;
29747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
298