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 MAXVECTORS 8*sizeof(access_vector_t)
21
22struct discover_class_node {
23	char *name;
24	security_class_t value;
25	char **perms;
26
27	struct discover_class_node *next;
28};
29
30static struct discover_class_node *discover_class_cache = NULL;
31
32static struct discover_class_node * get_class_cache_entry_name(const char *s)
33{
34	struct discover_class_node *node = discover_class_cache;
35
36	for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
37
38	return node;
39}
40
41static struct discover_class_node * get_class_cache_entry_value(security_class_t c)
42{
43	struct discover_class_node *node = discover_class_cache;
44
45	for (; node != NULL && c != node->value; node = node->next);
46
47	return node;
48}
49
50static struct discover_class_node * discover_class(const char *s)
51{
52	int fd, ret;
53	char path[PATH_MAX];
54	char buf[20];
55	DIR *dir;
56	struct dirent *dentry;
57	size_t i;
58
59	struct discover_class_node *node;
60
61	if (!selinux_mnt) {
62		errno = ENOENT;
63		return NULL;
64	}
65
66	if (strchr(s, '/') != NULL)
67		return NULL;
68
69	/* allocate a node */
70	node = malloc(sizeof(struct discover_class_node));
71	if (node == NULL)
72		return NULL;
73
74	/* allocate array for perms */
75	node->perms = calloc(MAXVECTORS,sizeof(char*));
76	if (node->perms == NULL)
77		goto err1;
78
79	/* load up the name */
80	node->name = strdup(s);
81	if (node->name == NULL)
82		goto err2;
83
84	/* load up class index */
85	ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
86	if (ret < 0 || (size_t)ret >= sizeof path)
87		goto err3;
88
89	fd = open(path, O_RDONLY | O_CLOEXEC);
90	if (fd < 0)
91		goto err3;
92
93	memset(buf, 0, sizeof(buf));
94	ret = read(fd, buf, sizeof(buf) - 1);
95	close(fd);
96	if (ret < 0)
97		goto err3;
98
99	if (sscanf(buf, "%hu", &node->value) != 1)
100		goto err3;
101
102	/* load up permission indices */
103	ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
104	if (ret < 0 || (size_t)ret >= sizeof path)
105		goto err3;
106
107	dir = opendir(path);
108	if (dir == NULL)
109		goto err3;
110
111	dentry = readdir(dir);
112	while (dentry != NULL) {
113		unsigned int value;
114		struct stat m;
115
116		ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
117		if (ret < 0 || (size_t)ret >= sizeof path)
118			goto err4;
119
120		fd = open(path, O_RDONLY | O_CLOEXEC);
121		if (fd < 0)
122			goto err4;
123
124		if (fstat(fd, &m) < 0) {
125			close(fd);
126			goto err4;
127		}
128
129		if (m.st_mode & S_IFDIR) {
130			close(fd);
131			dentry = readdir(dir);
132			continue;
133		}
134
135		memset(buf, 0, sizeof(buf));
136		ret = read(fd, buf, sizeof(buf) - 1);
137		close(fd);
138		if (ret < 0)
139			goto err4;
140
141		if (sscanf(buf, "%u", &value) != 1)
142			goto err4;
143
144		if (value == 0 || value > MAXVECTORS)
145			goto err4;
146
147		node->perms[value-1] = strdup(dentry->d_name);
148		if (node->perms[value-1] == NULL)
149			goto err4;
150
151		dentry = readdir(dir);
152	}
153	closedir(dir);
154
155	node->next = discover_class_cache;
156	discover_class_cache = node;
157
158	return node;
159
160err4:
161	closedir(dir);
162	for (i = 0; i < MAXVECTORS; i++)
163		free(node->perms[i]);
164err3:
165	free(node->name);
166err2:
167	free(node->perms);
168err1:
169	free(node);
170	return NULL;
171}
172
173void selinux_flush_class_cache(void)
174{
175	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
176	size_t i;
177
178	while (cur != NULL) {
179		free(cur->name);
180
181		for (i = 0; i < MAXVECTORS; i++)
182			free(cur->perms[i]);
183
184		free(cur->perms);
185
186		prev = cur;
187		cur = cur->next;
188
189		free(prev);
190	}
191
192	discover_class_cache = NULL;
193}
194
195
196security_class_t string_to_security_class(const char *s)
197{
198	struct discover_class_node *node;
199
200	node = get_class_cache_entry_name(s);
201	if (node == NULL) {
202		node = discover_class(s);
203
204		if (node == NULL) {
205			errno = EINVAL;
206			return 0;
207		}
208	}
209
210	return map_class(node->value);
211}
212
213security_class_t mode_to_security_class(mode_t m) {
214
215	if (S_ISREG(m))
216		return string_to_security_class("file");
217	if (S_ISDIR(m))
218		return string_to_security_class("dir");
219	if (S_ISCHR(m))
220		return string_to_security_class("chr_file");
221	if (S_ISBLK(m))
222		return string_to_security_class("blk_file");
223	if (S_ISFIFO(m))
224		return string_to_security_class("fifo_file");
225	if (S_ISLNK(m))
226		return string_to_security_class("lnk_file");
227	if (S_ISSOCK(m))
228		return string_to_security_class("sock_file");
229
230	errno = EINVAL;
231	return 0;
232}
233
234access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
235{
236	struct discover_class_node *node;
237	security_class_t kclass = unmap_class(tclass);
238
239	node = get_class_cache_entry_value(kclass);
240	if (node != NULL) {
241		size_t i;
242		for (i = 0; i < MAXVECTORS && node->perms[i] != NULL; i++)
243			if (strcmp(node->perms[i],s) == 0)
244				return map_perm(tclass, UINT32_C(1)<<i);
245	}
246
247	errno = EINVAL;
248	return 0;
249}
250
251const char *security_class_to_string(security_class_t tclass)
252{
253	struct discover_class_node *node;
254
255	tclass = unmap_class(tclass);
256
257	node = get_class_cache_entry_value(tclass);
258	if (node == NULL)
259		return NULL;
260	else
261		return node->name;
262}
263
264const char *security_av_perm_to_string(security_class_t tclass,
265				       access_vector_t av)
266{
267	struct discover_class_node *node;
268	size_t i;
269
270	av = unmap_perm(tclass, av);
271	tclass = unmap_class(tclass);
272
273	node = get_class_cache_entry_value(tclass);
274	if (av && node)
275		for (i = 0; i<MAXVECTORS; i++)
276			if ((UINT32_C(1)<<i) & av)
277				return node->perms[i];
278
279	return NULL;
280}
281
282int security_av_string(security_class_t tclass, access_vector_t av, char **res)
283{
284	unsigned int i;
285	size_t len = 5;
286	access_vector_t tmp = av;
287	int rc = 0;
288	const char *str;
289	char *ptr;
290
291	/* first pass computes the required length */
292	for (i = 0; tmp; tmp >>= 1, i++) {
293		if (tmp & 1) {
294			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
295			if (str)
296				len += strlen(str) + 1;
297		}
298	}
299
300	*res = malloc(len);
301	if (!*res) {
302		rc = -1;
303		goto out;
304	}
305
306	/* second pass constructs the string */
307	tmp = av;
308	ptr = *res;
309
310	if (!av) {
311		sprintf(ptr, "null");
312		goto out;
313	}
314
315	ptr += sprintf(ptr, "{ ");
316	for (i = 0; tmp; tmp >>= 1, i++) {
317		if (tmp & 1) {
318			str = security_av_perm_to_string(tclass, av & (UINT32_C(1)<<i));
319			if (str)
320				ptr += sprintf(ptr, "%s ", str);
321		}
322	}
323	sprintf(ptr, "}");
324out:
325	return rc;
326}
327
328void print_access_vector(security_class_t tclass, access_vector_t av)
329{
330	const char *permstr;
331	access_vector_t bit = 1;
332
333	if (av == 0) {
334		printf(" null");
335		return;
336	}
337
338	printf(" {");
339
340	while (av) {
341		if (av & bit) {
342			permstr = security_av_perm_to_string(tclass, bit);
343			if (!permstr)
344				break;
345			printf(" %s", permstr);
346			av &= ~bit;
347		}
348		bit <<= 1;
349	}
350
351	if (av)
352		printf(" 0x%x", av);
353	printf(" }");
354}
355