1/*
2 * String representation support for classes and permissions.
3 */
4#include <sys/stat.h>
5#include <dirent.h>
6#include <fcntl.h>
7#include <limits.h>
8#include <unistd.h>
9#include <errno.h>
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <stdint.h>
15#include <ctype.h>
16#include "selinux_internal.h"
17#include "policy.h"
18#include "mapping.h"
19
20#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
21
22#define MAXVECTORS 8*sizeof(access_vector_t)
23
24static pthread_once_t once = PTHREAD_ONCE_INIT;
25
26struct discover_class_node {
27	char *name;
28	security_class_t value;
29	char **perms;
30
31	struct discover_class_node *next;
32};
33
34static struct discover_class_node *discover_class_cache = NULL;
35
36static struct discover_class_node * get_class_cache_entry_name(const char *s)
37{
38	struct discover_class_node *node = discover_class_cache;
39
40	for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
41
42	return node;
43}
44
45static struct discover_class_node * get_class_cache_entry_value(security_class_t c)
46{
47	struct discover_class_node *node = discover_class_cache;
48
49	for (; node != NULL && c != node->value; node = node->next);
50
51	return node;
52}
53
54static struct discover_class_node * discover_class(const char *s)
55{
56	int fd, ret;
57	char path[PATH_MAX];
58	char buf[20];
59	DIR *dir;
60	struct dirent *dentry;
61	size_t i;
62
63	struct discover_class_node *node;
64
65	if (!selinux_mnt) {
66		errno = ENOENT;
67		return NULL;
68	}
69
70	/* allocate a node */
71	node = malloc(sizeof(struct discover_class_node));
72	if (node == NULL)
73		return NULL;
74
75	/* allocate array for perms */
76	node->perms = calloc(MAXVECTORS,sizeof(char*));
77	if (node->perms == NULL)
78		goto err1;
79
80	/* load up the name */
81	node->name = strdup(s);
82	if (node->name == NULL)
83		goto err2;
84
85	/* load up class index */
86	snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
87	fd = open(path, O_RDONLY);
88	if (fd < 0)
89		goto err3;
90
91	memset(buf, 0, sizeof(buf));
92	ret = read(fd, buf, sizeof(buf) - 1);
93	close(fd);
94	if (ret < 0)
95		goto err3;
96
97	if (sscanf(buf, "%hu", &node->value) != 1)
98		goto err3;
99
100	/* load up permission indicies */
101	snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
102	dir = opendir(path);
103	if (dir == NULL)
104		goto err3;
105
106	dentry = readdir(dir);
107	while (dentry != NULL) {
108		unsigned int value;
109		struct stat m;
110
111		snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
112		if (stat(path,&m) < 0)
113			goto err4;
114
115		if (m.st_mode & S_IFDIR) {
116			dentry = readdir(dir);
117			continue;
118		}
119
120		fd = open(path, O_RDONLY);
121		if (fd < 0)
122			goto err4;
123
124		memset(buf, 0, sizeof(buf));
125		ret = read(fd, buf, sizeof(buf) - 1);
126		close(fd);
127		if (ret < 0)
128			goto err4;
129
130		if (sscanf(buf, "%u", &value) != 1)
131			goto err4;
132
133		node->perms[value-1] = strdup(dentry->d_name);
134		if (node->perms[value-1] == NULL)
135			goto err4;
136
137		dentry = readdir(dir);
138	}
139	closedir(dir);
140
141	node->next = discover_class_cache;
142	discover_class_cache = node;
143
144	return node;
145
146err4:
147	closedir(dir);
148	for (i=0; i<MAXVECTORS; i++)
149		free(node->perms[i]);
150err3:
151	free(node->name);
152err2:
153	free(node->perms);
154err1:
155	free(node);
156	return NULL;
157}
158
159void flush_class_cache(void)
160{
161	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
162	size_t i;
163
164	while (cur != NULL) {
165		free(cur->name);
166
167		for (i=0 ; i<MAXVECTORS ; i++)
168			free(cur->perms[i]);
169
170		free(cur->perms);
171
172		prev = cur;
173		cur = cur->next;
174
175		free(prev);
176	}
177
178	discover_class_cache = NULL;
179}
180
181security_class_t string_to_security_class(const char *s)
182{
183	struct discover_class_node *node;
184
185	node = get_class_cache_entry_name(s);
186	if (node == NULL) {
187		node = discover_class(s);
188
189		if (node == NULL) {
190			errno = EINVAL;
191			return 0;
192		}
193	}
194
195	return map_class(node->value);
196}
197
198access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
199{
200	struct discover_class_node *node;
201	security_class_t kclass = unmap_class(tclass);
202
203	node = get_class_cache_entry_value(kclass);
204	if (node != NULL) {
205		size_t i;
206		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
207			if (strcmp(node->perms[i],s) == 0)
208				return map_perm(tclass, 1<<i);
209	}
210
211	errno = EINVAL;
212	return 0;
213}
214
215const char *security_class_to_string(security_class_t tclass)
216{
217	struct discover_class_node *node;
218
219	tclass = unmap_class(tclass);
220
221	node = get_class_cache_entry_value(tclass);
222	if (node)
223		return node->name;
224	return NULL;
225}
226
227const char *security_av_perm_to_string(security_class_t tclass,
228				       access_vector_t av)
229{
230	struct discover_class_node *node;
231	size_t i;
232
233	av = unmap_perm(tclass, av);
234	tclass = unmap_class(tclass);
235
236	node = get_class_cache_entry_value(tclass);
237	if (av && node)
238		for (i = 0; i<MAXVECTORS; i++)
239			if ((1<<i) & av)
240				return node->perms[i];
241
242	return NULL;
243}
244
245int security_av_string(security_class_t tclass, access_vector_t av, char **res)
246{
247	unsigned int i = 0;
248	size_t len = 5;
249	access_vector_t tmp = av;
250	int rc = 0;
251	const char *str;
252	char *ptr;
253
254	/* first pass computes the required length */
255	while (tmp) {
256		if (tmp & 1) {
257			str = security_av_perm_to_string(tclass, av & (1<<i));
258			if (str)
259				len += strlen(str) + 1;
260			else {
261				rc = -1;
262				errno = EINVAL;
263				goto out;
264			}
265		}
266		tmp >>= 1;
267		i++;
268	}
269
270	*res = malloc(len);
271	if (!*res) {
272		rc = -1;
273		goto out;
274	}
275
276	/* second pass constructs the string */
277	i = 0;
278	tmp = av;
279	ptr = *res;
280
281	if (!av) {
282		sprintf(ptr, "null");
283		goto out;
284	}
285
286	ptr += sprintf(ptr, "{ ");
287	while (tmp) {
288		if (tmp & 1)
289			ptr += sprintf(ptr, "%s ", security_av_perm_to_string(
290					       tclass, av & (1<<i)));
291		tmp >>= 1;
292		i++;
293	}
294	sprintf(ptr, "}");
295out:
296	return rc;
297}
298