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 
22 struct discover_class_node {
23 	char *name;
24 	security_class_t value;
25 	char **perms;
26 
27 	struct discover_class_node *next;
28 };
29 
30 static struct discover_class_node *discover_class_cache = NULL;
31 
get_class_cache_entry_name(const char * s)32 static 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 
get_class_cache_entry_value(security_class_t c)41 static 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 
discover_class(const char * s)50 static 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 
148 err4:
149 	closedir(dir);
150 	for (i=0; i<MAXVECTORS; i++)
151 		free(node->perms[i]);
152 err3:
153 	free(node->name);
154 err2:
155 	free(node->perms);
156 err1:
157 	free(node);
158 	return NULL;
159 }
160 
flush_class_cache(void)161 hidden void flush_class_cache(void)
162 {
163 	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
164 	size_t i;
165 
166 	while (cur != NULL) {
167 		free(cur->name);
168 
169 		for (i = 0; i < MAXVECTORS; i++)
170 			free(cur->perms[i]);
171 
172 		free(cur->perms);
173 
174 		prev = cur;
175 		cur = cur->next;
176 
177 		free(prev);
178 	}
179 
180 	discover_class_cache = NULL;
181 }
182 
string_to_security_class(const char * s)183 security_class_t string_to_security_class(const char *s)
184 {
185 	struct discover_class_node *node;
186 
187 	node = get_class_cache_entry_name(s);
188 	if (node == NULL) {
189 		node = discover_class(s);
190 
191 		if (node == NULL) {
192 			errno = EINVAL;
193 			return 0;
194 		}
195 	}
196 
197 	return map_class(node->value);
198 }
199 
mode_to_security_class(mode_t m)200 security_class_t mode_to_security_class(mode_t m) {
201 
202 	if (S_ISREG(m))
203 		return string_to_security_class("file");
204 	if (S_ISDIR(m))
205 		return string_to_security_class("dir");
206 	if (S_ISCHR(m))
207 		return string_to_security_class("chr_file");
208 	if (S_ISBLK(m))
209 		return string_to_security_class("blk_file");
210 	if (S_ISFIFO(m))
211 		return string_to_security_class("fifo_file");
212 	if (S_ISLNK(m))
213 		return string_to_security_class("lnk_file");
214 	if (S_ISSOCK(m))
215 		return string_to_security_class("sock_file");
216 
217 	errno=EINVAL;
218 	return 0;
219 }
220 
string_to_av_perm(security_class_t tclass,const char * s)221 access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
222 {
223 	struct discover_class_node *node;
224 	security_class_t kclass = unmap_class(tclass);
225 
226 	node = get_class_cache_entry_value(kclass);
227 	if (node != NULL) {
228 		size_t i;
229 		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
230 			if (strcmp(node->perms[i],s) == 0)
231 				return map_perm(tclass, 1<<i);
232 	}
233 
234 	errno = EINVAL;
235 	return 0;
236 }
237 
security_class_to_string(security_class_t tclass)238 const char *security_class_to_string(security_class_t tclass)
239 {
240 	struct discover_class_node *node;
241 
242 	tclass = unmap_class(tclass);
243 
244 	node = get_class_cache_entry_value(tclass);
245 	if (node == NULL)
246 		return NULL;
247 	else
248 		return node->name;
249 }
250 
security_av_perm_to_string(security_class_t tclass,access_vector_t av)251 const char *security_av_perm_to_string(security_class_t tclass,
252 				       access_vector_t av)
253 {
254 	struct discover_class_node *node;
255 	size_t i;
256 
257 	av = unmap_perm(tclass, av);
258 	tclass = unmap_class(tclass);
259 
260 	node = get_class_cache_entry_value(tclass);
261 	if (av && node)
262 		for (i = 0; i<MAXVECTORS; i++)
263 			if ((1<<i) & av)
264 				return node->perms[i];
265 
266 	return NULL;
267 }
268 
security_av_string(security_class_t tclass,access_vector_t av,char ** res)269 int security_av_string(security_class_t tclass, access_vector_t av, char **res)
270 {
271 	unsigned int i = 0;
272 	size_t len = 5;
273 	access_vector_t tmp = av;
274 	int rc = 0;
275 	const char *str;
276 	char *ptr;
277 
278 	/* first pass computes the required length */
279 	while (tmp) {
280 		if (tmp & 1) {
281 			str = security_av_perm_to_string(tclass, av & (1<<i));
282 			if (str)
283 				len += strlen(str) + 1;
284 			else {
285 				rc = -1;
286 				errno = EINVAL;
287 				goto out;
288 			}
289 		}
290 		tmp >>= 1;
291 		i++;
292 	}
293 
294 	*res = malloc(len);
295 	if (!*res) {
296 		rc = -1;
297 		goto out;
298 	}
299 
300 	/* second pass constructs the string */
301 	i = 0;
302 	tmp = av;
303 	ptr = *res;
304 
305 	if (!av) {
306 		sprintf(ptr, "null");
307 		goto out;
308 	}
309 
310 	ptr += sprintf(ptr, "{ ");
311 	while (tmp) {
312 		if (tmp & 1)
313 			ptr += sprintf(ptr, "%s ", security_av_perm_to_string(
314 					       tclass, av & (1<<i)));
315 		tmp >>= 1;
316 		i++;
317 	}
318 	sprintf(ptr, "}");
319 out:
320 	return rc;
321 }
322 
print_access_vector(security_class_t tclass,access_vector_t av)323 void print_access_vector(security_class_t tclass, access_vector_t av)
324 {
325 	const char *permstr;
326 	access_vector_t bit = 1;
327 
328 	if (av == 0) {
329 		printf(" null");
330 		return;
331 	}
332 
333 	printf(" {");
334 
335 	while (av) {
336 		if (av & bit) {
337 			permstr = security_av_perm_to_string(tclass, bit);
338 			if (!permstr)
339 				break;
340 			printf(" %s", permstr);
341 			av &= ~bit;
342 		}
343 		bit <<= 1;
344 	}
345 
346 	if (av)
347 		printf(" 0x%x", av);
348 	printf(" }");
349 }
350