stringrep.c revision 4c6822227821a2ac9bcf25da241b9f3c2218c3c8
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	/* allocate a node */
67	node = malloc(sizeof(struct discover_class_node));
68	if (node == NULL)
69		return NULL;
70
71	/* allocate array for perms */
72	node->perms = calloc(MAXVECTORS,sizeof(char*));
73	if (node->perms == NULL)
74		goto err1;
75
76	/* load up the name */
77	node->name = strdup(s);
78	if (node->name == NULL)
79		goto err2;
80
81	/* load up class index */
82	snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
83	fd = open(path, O_RDONLY);
84	if (fd < 0)
85		goto err3;
86
87	memset(buf, 0, sizeof(buf));
88	ret = read(fd, buf, sizeof(buf) - 1);
89	close(fd);
90	if (ret < 0)
91		goto err3;
92
93	if (sscanf(buf, "%hu", &node->value) != 1)
94		goto err3;
95
96	/* load up permission indicies */
97	snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
98	dir = opendir(path);
99	if (dir == NULL)
100		goto err3;
101
102	dentry = readdir(dir);
103	while (dentry != NULL) {
104		unsigned int value;
105		struct stat m;
106
107		snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
108		fd = open(path, O_RDONLY | O_CLOEXEC);
109		if (fd < 0)
110			goto err4;
111
112		if (fstat(fd, &m) < 0) {
113			close(fd);
114			goto err4;
115		}
116
117		if (m.st_mode & S_IFDIR) {
118			close(fd);
119			dentry = readdir(dir);
120			continue;
121		}
122
123		memset(buf, 0, sizeof(buf));
124		ret = read(fd, buf, sizeof(buf) - 1);
125		close(fd);
126		if (ret < 0)
127			goto err4;
128
129		if (sscanf(buf, "%u", &value) != 1)
130			goto err4;
131
132		if (value == 0 || value > MAXVECTORS)
133			goto err4;
134
135		node->perms[value-1] = strdup(dentry->d_name);
136		if (node->perms[value-1] == NULL)
137			goto err4;
138
139		dentry = readdir(dir);
140	}
141	closedir(dir);
142
143	node->next = discover_class_cache;
144	discover_class_cache = node;
145
146	return node;
147
148err4:
149	closedir(dir);
150	for (i=0; i<MAXVECTORS; i++)
151		free(node->perms[i]);
152err3:
153	free(node->name);
154err2:
155	free(node->perms);
156err1:
157	free(node);
158	return NULL;
159}
160
161security_class_t string_to_security_class(const char *s)
162{
163	struct discover_class_node *node;
164
165	node = get_class_cache_entry_name(s);
166	if (node == NULL) {
167		node = discover_class(s);
168
169		if (node == NULL) {
170			errno = EINVAL;
171			return 0;
172		}
173	}
174
175	return map_class(node->value);
176}
177
178access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
179{
180	struct discover_class_node *node;
181	security_class_t kclass = unmap_class(tclass);
182
183	node = get_class_cache_entry_value(kclass);
184	if (node != NULL) {
185		size_t i;
186		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
187			if (strcmp(node->perms[i],s) == 0)
188				return map_perm(tclass, 1<<i);
189	}
190
191	errno = EINVAL;
192	return 0;
193}
194
195const char *security_class_to_string(security_class_t tclass)
196{
197	struct discover_class_node *node;
198
199	tclass = unmap_class(tclass);
200
201	node = get_class_cache_entry_value(tclass);
202	if (node)
203		return node->name;
204	return NULL;
205}
206
207const char *security_av_perm_to_string(security_class_t tclass,
208				       access_vector_t av)
209{
210	struct discover_class_node *node;
211	size_t i;
212
213	av = unmap_perm(tclass, av);
214	tclass = unmap_class(tclass);
215
216	node = get_class_cache_entry_value(tclass);
217	if (av && node)
218		for (i = 0; i<MAXVECTORS; i++)
219			if ((1<<i) & av)
220				return node->perms[i];
221
222	return NULL;
223}
224
225int security_av_string(security_class_t tclass, access_vector_t av, char **res)
226{
227	unsigned int i = 0;
228	size_t len = 5;
229	access_vector_t tmp = av;
230	int rc = 0;
231	const char *str;
232	char *ptr;
233
234	/* first pass computes the required length */
235	while (tmp) {
236		if (tmp & 1) {
237			str = security_av_perm_to_string(tclass, av & (1<<i));
238			if (str)
239				len += strlen(str) + 1;
240			else {
241				rc = -1;
242				errno = EINVAL;
243				goto out;
244			}
245		}
246		tmp >>= 1;
247		i++;
248	}
249
250	*res = malloc(len);
251	if (!*res) {
252		rc = -1;
253		goto out;
254	}
255
256	/* second pass constructs the string */
257	i = 0;
258	tmp = av;
259	ptr = *res;
260
261	if (!av) {
262		sprintf(ptr, "null");
263		goto out;
264	}
265
266	ptr += sprintf(ptr, "{ ");
267	while (tmp) {
268		if (tmp & 1)
269			ptr += sprintf(ptr, "%s ", security_av_perm_to_string(
270					       tclass, av & (1<<i)));
271		tmp >>= 1;
272		i++;
273	}
274	sprintf(ptr, "}");
275out:
276	return rc;
277}
278