16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * String representation support for classes and permissions.
36cd6a6acSopenharmony_ci */
46cd6a6acSopenharmony_ci#include <sys/stat.h>
56cd6a6acSopenharmony_ci#include <dirent.h>
66cd6a6acSopenharmony_ci#include <fcntl.h>
76cd6a6acSopenharmony_ci#include <limits.h>
86cd6a6acSopenharmony_ci#include <unistd.h>
96cd6a6acSopenharmony_ci#include <errno.h>
106cd6a6acSopenharmony_ci#include <stddef.h>
116cd6a6acSopenharmony_ci#include <stdio.h>
126cd6a6acSopenharmony_ci#include <stdlib.h>
136cd6a6acSopenharmony_ci#include <string.h>
146cd6a6acSopenharmony_ci#include <stdint.h>
156cd6a6acSopenharmony_ci#include <ctype.h>
166cd6a6acSopenharmony_ci#include "selinux_internal.h"
176cd6a6acSopenharmony_ci#include "policy.h"
186cd6a6acSopenharmony_ci#include "mapping.h"
196cd6a6acSopenharmony_ci
206cd6a6acSopenharmony_ci#define MAXVECTORS 8*sizeof(access_vector_t)
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_cistruct discover_class_node {
236cd6a6acSopenharmony_ci	char *name;
246cd6a6acSopenharmony_ci	security_class_t value;
256cd6a6acSopenharmony_ci	char **perms;
266cd6a6acSopenharmony_ci
276cd6a6acSopenharmony_ci	struct discover_class_node *next;
286cd6a6acSopenharmony_ci};
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_cistatic struct discover_class_node *discover_class_cache = NULL;
316cd6a6acSopenharmony_ci
326cd6a6acSopenharmony_cistatic struct discover_class_node * get_class_cache_entry_name(const char *s)
336cd6a6acSopenharmony_ci{
346cd6a6acSopenharmony_ci	struct discover_class_node *node = discover_class_cache;
356cd6a6acSopenharmony_ci
366cd6a6acSopenharmony_ci	for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
376cd6a6acSopenharmony_ci
386cd6a6acSopenharmony_ci	return node;
396cd6a6acSopenharmony_ci}
406cd6a6acSopenharmony_ci
416cd6a6acSopenharmony_cistatic struct discover_class_node * get_class_cache_entry_value(security_class_t c)
426cd6a6acSopenharmony_ci{
436cd6a6acSopenharmony_ci	struct discover_class_node *node = discover_class_cache;
446cd6a6acSopenharmony_ci
456cd6a6acSopenharmony_ci	for (; node != NULL && c != node->value; node = node->next);
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	return node;
486cd6a6acSopenharmony_ci}
496cd6a6acSopenharmony_ci
506cd6a6acSopenharmony_cistatic struct discover_class_node * discover_class(const char *s)
516cd6a6acSopenharmony_ci{
526cd6a6acSopenharmony_ci	int fd, ret;
536cd6a6acSopenharmony_ci	char path[PATH_MAX];
546cd6a6acSopenharmony_ci	char buf[20];
556cd6a6acSopenharmony_ci	DIR *dir;
566cd6a6acSopenharmony_ci	struct dirent *dentry;
576cd6a6acSopenharmony_ci	size_t i;
586cd6a6acSopenharmony_ci
596cd6a6acSopenharmony_ci	struct discover_class_node *node;
606cd6a6acSopenharmony_ci
616cd6a6acSopenharmony_ci	if (!selinux_mnt) {
626cd6a6acSopenharmony_ci		errno = ENOENT;
636cd6a6acSopenharmony_ci		return NULL;
646cd6a6acSopenharmony_ci	}
656cd6a6acSopenharmony_ci
666cd6a6acSopenharmony_ci	if (strchr(s, '/') != NULL)
676cd6a6acSopenharmony_ci		return NULL;
686cd6a6acSopenharmony_ci
696cd6a6acSopenharmony_ci	/* allocate a node */
706cd6a6acSopenharmony_ci	node = malloc(sizeof(struct discover_class_node));
716cd6a6acSopenharmony_ci	if (node == NULL)
726cd6a6acSopenharmony_ci		return NULL;
736cd6a6acSopenharmony_ci
746cd6a6acSopenharmony_ci	/* allocate array for perms */
756cd6a6acSopenharmony_ci	node->perms = calloc(MAXVECTORS,sizeof(char*));
766cd6a6acSopenharmony_ci	if (node->perms == NULL)
776cd6a6acSopenharmony_ci		goto err1;
786cd6a6acSopenharmony_ci
796cd6a6acSopenharmony_ci	/* load up the name */
806cd6a6acSopenharmony_ci	node->name = strdup(s);
816cd6a6acSopenharmony_ci	if (node->name == NULL)
826cd6a6acSopenharmony_ci		goto err2;
836cd6a6acSopenharmony_ci
846cd6a6acSopenharmony_ci	/* load up class index */
856cd6a6acSopenharmony_ci	ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
866cd6a6acSopenharmony_ci	if (ret < 0 || (size_t)ret >= sizeof path)
876cd6a6acSopenharmony_ci		goto err3;
886cd6a6acSopenharmony_ci
896cd6a6acSopenharmony_ci	fd = open(path, O_RDONLY | O_CLOEXEC);
906cd6a6acSopenharmony_ci	if (fd < 0)
916cd6a6acSopenharmony_ci		goto err3;
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_ci	memset(buf, 0, sizeof(buf));
946cd6a6acSopenharmony_ci	ret = read(fd, buf, sizeof(buf) - 1);
956cd6a6acSopenharmony_ci	close(fd);
966cd6a6acSopenharmony_ci	if (ret < 0)
976cd6a6acSopenharmony_ci		goto err3;
986cd6a6acSopenharmony_ci
996cd6a6acSopenharmony_ci	if (sscanf(buf, "%hu", &node->value) != 1)
1006cd6a6acSopenharmony_ci		goto err3;
1016cd6a6acSopenharmony_ci
1026cd6a6acSopenharmony_ci	/* load up permission indices */
1036cd6a6acSopenharmony_ci	ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
1046cd6a6acSopenharmony_ci	if (ret < 0 || (size_t)ret >= sizeof path)
1056cd6a6acSopenharmony_ci		goto err3;
1066cd6a6acSopenharmony_ci
1076cd6a6acSopenharmony_ci	dir = opendir(path);
1086cd6a6acSopenharmony_ci	if (dir == NULL)
1096cd6a6acSopenharmony_ci		goto err3;
1106cd6a6acSopenharmony_ci
1116cd6a6acSopenharmony_ci	dentry = readdir(dir);
1126cd6a6acSopenharmony_ci	while (dentry != NULL) {
1136cd6a6acSopenharmony_ci		unsigned int value;
1146cd6a6acSopenharmony_ci		struct stat m;
1156cd6a6acSopenharmony_ci
1166cd6a6acSopenharmony_ci		ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
1176cd6a6acSopenharmony_ci		if (ret < 0 || (size_t)ret >= sizeof path)
1186cd6a6acSopenharmony_ci			goto err4;
1196cd6a6acSopenharmony_ci
1206cd6a6acSopenharmony_ci		fd = open(path, O_RDONLY | O_CLOEXEC);
1216cd6a6acSopenharmony_ci		if (fd < 0)
1226cd6a6acSopenharmony_ci			goto err4;
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ci		if (fstat(fd, &m) < 0) {
1256cd6a6acSopenharmony_ci			close(fd);
1266cd6a6acSopenharmony_ci			goto err4;
1276cd6a6acSopenharmony_ci		}
1286cd6a6acSopenharmony_ci
1296cd6a6acSopenharmony_ci		if (m.st_mode & S_IFDIR) {
1306cd6a6acSopenharmony_ci			close(fd);
1316cd6a6acSopenharmony_ci			dentry = readdir(dir);
1326cd6a6acSopenharmony_ci			continue;
1336cd6a6acSopenharmony_ci		}
1346cd6a6acSopenharmony_ci
1356cd6a6acSopenharmony_ci		memset(buf, 0, sizeof(buf));
1366cd6a6acSopenharmony_ci		ret = read(fd, buf, sizeof(buf) - 1);
1376cd6a6acSopenharmony_ci		close(fd);
1386cd6a6acSopenharmony_ci		if (ret < 0)
1396cd6a6acSopenharmony_ci			goto err4;
1406cd6a6acSopenharmony_ci
1416cd6a6acSopenharmony_ci		if (sscanf(buf, "%u", &value) != 1)
1426cd6a6acSopenharmony_ci			goto err4;
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci		if (value == 0 || value > MAXVECTORS)
1456cd6a6acSopenharmony_ci			goto err4;
1466cd6a6acSopenharmony_ci
1476cd6a6acSopenharmony_ci		node->perms[value-1] = strdup(dentry->d_name);
1486cd6a6acSopenharmony_ci		if (node->perms[value-1] == NULL)
1496cd6a6acSopenharmony_ci			goto err4;
1506cd6a6acSopenharmony_ci
1516cd6a6acSopenharmony_ci		dentry = readdir(dir);
1526cd6a6acSopenharmony_ci	}
1536cd6a6acSopenharmony_ci	closedir(dir);
1546cd6a6acSopenharmony_ci
1556cd6a6acSopenharmony_ci	node->next = discover_class_cache;
1566cd6a6acSopenharmony_ci	discover_class_cache = node;
1576cd6a6acSopenharmony_ci
1586cd6a6acSopenharmony_ci	return node;
1596cd6a6acSopenharmony_ci
1606cd6a6acSopenharmony_cierr4:
1616cd6a6acSopenharmony_ci	closedir(dir);
1626cd6a6acSopenharmony_ci	for (i = 0; i < MAXVECTORS; i++)
1636cd6a6acSopenharmony_ci		free(node->perms[i]);
1646cd6a6acSopenharmony_cierr3:
1656cd6a6acSopenharmony_ci	free(node->name);
1666cd6a6acSopenharmony_cierr2:
1676cd6a6acSopenharmony_ci	free(node->perms);
1686cd6a6acSopenharmony_cierr1:
1696cd6a6acSopenharmony_ci	free(node);
1706cd6a6acSopenharmony_ci	return NULL;
1716cd6a6acSopenharmony_ci}
1726cd6a6acSopenharmony_ci
1736cd6a6acSopenharmony_civoid selinux_flush_class_cache(void)
1746cd6a6acSopenharmony_ci{
1756cd6a6acSopenharmony_ci	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
1766cd6a6acSopenharmony_ci	size_t i;
1776cd6a6acSopenharmony_ci
1786cd6a6acSopenharmony_ci	while (cur != NULL) {
1796cd6a6acSopenharmony_ci		free(cur->name);
1806cd6a6acSopenharmony_ci
1816cd6a6acSopenharmony_ci		for (i = 0; i < MAXVECTORS; i++)
1826cd6a6acSopenharmony_ci			free(cur->perms[i]);
1836cd6a6acSopenharmony_ci
1846cd6a6acSopenharmony_ci		free(cur->perms);
1856cd6a6acSopenharmony_ci
1866cd6a6acSopenharmony_ci		prev = cur;
1876cd6a6acSopenharmony_ci		cur = cur->next;
1886cd6a6acSopenharmony_ci
1896cd6a6acSopenharmony_ci		free(prev);
1906cd6a6acSopenharmony_ci	}
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci	discover_class_cache = NULL;
1936cd6a6acSopenharmony_ci}
1946cd6a6acSopenharmony_ci
1956cd6a6acSopenharmony_ci
1966cd6a6acSopenharmony_cisecurity_class_t string_to_security_class(const char *s)
1976cd6a6acSopenharmony_ci{
1986cd6a6acSopenharmony_ci	struct discover_class_node *node;
1996cd6a6acSopenharmony_ci
2006cd6a6acSopenharmony_ci	node = get_class_cache_entry_name(s);
2016cd6a6acSopenharmony_ci	if (node == NULL) {
2026cd6a6acSopenharmony_ci		node = discover_class(s);
2036cd6a6acSopenharmony_ci
2046cd6a6acSopenharmony_ci		if (node == NULL) {
2056cd6a6acSopenharmony_ci			errno = EINVAL;
2066cd6a6acSopenharmony_ci			return 0;
2076cd6a6acSopenharmony_ci		}
2086cd6a6acSopenharmony_ci	}
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci	return map_class(node->value);
2116cd6a6acSopenharmony_ci}
2126cd6a6acSopenharmony_ci
2136cd6a6acSopenharmony_cisecurity_class_t mode_to_security_class(mode_t m) {
2146cd6a6acSopenharmony_ci
2156cd6a6acSopenharmony_ci	if (S_ISREG(m))
2166cd6a6acSopenharmony_ci		return string_to_security_class("file");
2176cd6a6acSopenharmony_ci	if (S_ISDIR(m))
2186cd6a6acSopenharmony_ci		return string_to_security_class("dir");
2196cd6a6acSopenharmony_ci	if (S_ISCHR(m))
2206cd6a6acSopenharmony_ci		return string_to_security_class("chr_file");
2216cd6a6acSopenharmony_ci	if (S_ISBLK(m))
2226cd6a6acSopenharmony_ci		return string_to_security_class("blk_file");
2236cd6a6acSopenharmony_ci	if (S_ISFIFO(m))
2246cd6a6acSopenharmony_ci		return string_to_security_class("fifo_file");
2256cd6a6acSopenharmony_ci	if (S_ISLNK(m))
2266cd6a6acSopenharmony_ci		return string_to_security_class("lnk_file");
2276cd6a6acSopenharmony_ci	if (S_ISSOCK(m))
2286cd6a6acSopenharmony_ci		return string_to_security_class("sock_file");
2296cd6a6acSopenharmony_ci
2306cd6a6acSopenharmony_ci	errno = EINVAL;
2316cd6a6acSopenharmony_ci	return 0;
2326cd6a6acSopenharmony_ci}
2336cd6a6acSopenharmony_ci
2346cd6a6acSopenharmony_ciaccess_vector_t string_to_av_perm(security_class_t tclass, const char *s)
2356cd6a6acSopenharmony_ci{
2366cd6a6acSopenharmony_ci	struct discover_class_node *node;
2376cd6a6acSopenharmony_ci	security_class_t kclass = unmap_class(tclass);
2386cd6a6acSopenharmony_ci
2396cd6a6acSopenharmony_ci	node = get_class_cache_entry_value(kclass);
2406cd6a6acSopenharmony_ci	if (node != NULL) {
2416cd6a6acSopenharmony_ci		size_t i;
2426cd6a6acSopenharmony_ci		for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++)
2436cd6a6acSopenharmony_ci			if (strcmp(node->perms[i],s) == 0)
2446cd6a6acSopenharmony_ci				return map_perm(tclass, UINT32_C(1)<<i);
2456cd6a6acSopenharmony_ci	}
2466cd6a6acSopenharmony_ci
2476cd6a6acSopenharmony_ci	errno = EINVAL;
2486cd6a6acSopenharmony_ci	return 0;
2496cd6a6acSopenharmony_ci}
2506cd6a6acSopenharmony_ci
2516cd6a6acSopenharmony_ciconst char *security_class_to_string(security_class_t tclass)
2526cd6a6acSopenharmony_ci{
2536cd6a6acSopenharmony_ci	struct discover_class_node *node;
2546cd6a6acSopenharmony_ci
2556cd6a6acSopenharmony_ci	tclass = unmap_class(tclass);
2566cd6a6acSopenharmony_ci
2576cd6a6acSopenharmony_ci	node = get_class_cache_entry_value(tclass);
2586cd6a6acSopenharmony_ci	if (node == NULL)
2596cd6a6acSopenharmony_ci		return NULL;
2606cd6a6acSopenharmony_ci	else
2616cd6a6acSopenharmony_ci		return node->name;
2626cd6a6acSopenharmony_ci}
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ciconst char *security_av_perm_to_string(security_class_t tclass,
2656cd6a6acSopenharmony_ci				       access_vector_t av)
2666cd6a6acSopenharmony_ci{
2676cd6a6acSopenharmony_ci	struct discover_class_node *node;
2686cd6a6acSopenharmony_ci	size_t i;
2696cd6a6acSopenharmony_ci
2706cd6a6acSopenharmony_ci	av = unmap_perm(tclass, av);
2716cd6a6acSopenharmony_ci	tclass = unmap_class(tclass);
2726cd6a6acSopenharmony_ci
2736cd6a6acSopenharmony_ci	node = get_class_cache_entry_value(tclass);
2746cd6a6acSopenharmony_ci	if (av && node)
2756cd6a6acSopenharmony_ci		for (i = 0; i<MAXVECTORS; i++)
2766cd6a6acSopenharmony_ci			if ((UINT32_C(1)<<i) & av)
2776cd6a6acSopenharmony_ci				return node->perms[i];
2786cd6a6acSopenharmony_ci
2796cd6a6acSopenharmony_ci	return NULL;
2806cd6a6acSopenharmony_ci}
2816cd6a6acSopenharmony_ci
2826cd6a6acSopenharmony_ciint security_av_string(security_class_t tclass, access_vector_t av, char **res)
2836cd6a6acSopenharmony_ci{
2846cd6a6acSopenharmony_ci	unsigned int i;
2856cd6a6acSopenharmony_ci	size_t len = 5;
2866cd6a6acSopenharmony_ci	access_vector_t tmp = av;
2876cd6a6acSopenharmony_ci	int rc = 0;
2886cd6a6acSopenharmony_ci	const char *str;
2896cd6a6acSopenharmony_ci	char *ptr;
2906cd6a6acSopenharmony_ci
2916cd6a6acSopenharmony_ci	/* first pass computes the required length */
2926cd6a6acSopenharmony_ci	for (i = 0; tmp; tmp >>= 1, i++) {
2936cd6a6acSopenharmony_ci		if (tmp & 1) {
2946cd6a6acSopenharmony_ci			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
2956cd6a6acSopenharmony_ci			if (str)
2966cd6a6acSopenharmony_ci				len += strlen(str) + 1;
2976cd6a6acSopenharmony_ci		}
2986cd6a6acSopenharmony_ci	}
2996cd6a6acSopenharmony_ci
3006cd6a6acSopenharmony_ci	*res = malloc(len);
3016cd6a6acSopenharmony_ci	if (!*res) {
3026cd6a6acSopenharmony_ci		rc = -1;
3036cd6a6acSopenharmony_ci		goto out;
3046cd6a6acSopenharmony_ci	}
3056cd6a6acSopenharmony_ci
3066cd6a6acSopenharmony_ci	/* second pass constructs the string */
3076cd6a6acSopenharmony_ci	tmp = av;
3086cd6a6acSopenharmony_ci	ptr = *res;
3096cd6a6acSopenharmony_ci
3106cd6a6acSopenharmony_ci	if (!av) {
3116cd6a6acSopenharmony_ci		sprintf(ptr, "null");
3126cd6a6acSopenharmony_ci		goto out;
3136cd6a6acSopenharmony_ci	}
3146cd6a6acSopenharmony_ci
3156cd6a6acSopenharmony_ci	ptr += sprintf(ptr, "{ ");
3166cd6a6acSopenharmony_ci	for (i = 0; tmp; tmp >>= 1, i++) {
3176cd6a6acSopenharmony_ci		if (tmp & 1) {
3186cd6a6acSopenharmony_ci			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
3196cd6a6acSopenharmony_ci			if (str)
3206cd6a6acSopenharmony_ci				ptr += sprintf(ptr, "%s ", str);
3216cd6a6acSopenharmony_ci		}
3226cd6a6acSopenharmony_ci	}
3236cd6a6acSopenharmony_ci	sprintf(ptr, "}");
3246cd6a6acSopenharmony_ciout:
3256cd6a6acSopenharmony_ci	return rc;
3266cd6a6acSopenharmony_ci}
3276cd6a6acSopenharmony_ci
3286cd6a6acSopenharmony_civoid print_access_vector(security_class_t tclass, access_vector_t av)
3296cd6a6acSopenharmony_ci{
3306cd6a6acSopenharmony_ci	const char *permstr;
3316cd6a6acSopenharmony_ci	access_vector_t bit = 1;
3326cd6a6acSopenharmony_ci
3336cd6a6acSopenharmony_ci	if (av == 0) {
3346cd6a6acSopenharmony_ci		printf(" null");
3356cd6a6acSopenharmony_ci		return;
3366cd6a6acSopenharmony_ci	}
3376cd6a6acSopenharmony_ci
3386cd6a6acSopenharmony_ci	printf(" {");
3396cd6a6acSopenharmony_ci
3406cd6a6acSopenharmony_ci	while (av) {
3416cd6a6acSopenharmony_ci		if (av & bit) {
3426cd6a6acSopenharmony_ci			permstr = security_av_perm_to_string(tclass, bit);
3436cd6a6acSopenharmony_ci			if (!permstr)
3446cd6a6acSopenharmony_ci				break;
3456cd6a6acSopenharmony_ci			printf(" %s", permstr);
3466cd6a6acSopenharmony_ci			av &= ~bit;
3476cd6a6acSopenharmony_ci		}
3486cd6a6acSopenharmony_ci		bit <<= 1;
3496cd6a6acSopenharmony_ci	}
3506cd6a6acSopenharmony_ci
3516cd6a6acSopenharmony_ci	if (av)
3526cd6a6acSopenharmony_ci		printf(" 0x%x", av);
3536cd6a6acSopenharmony_ci	printf(" }");
3546cd6a6acSopenharmony_ci}
355