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 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
160 err4:
161 closedir(dir);
162 for (i = 0; i < MAXVECTORS; i++)
163 free(node->perms[i]);
164 err3:
165 free(node->name);
166 err2:
167 free(node->perms);
168 err1:
169 free(node);
170 return NULL;
171 }
172
selinux_flush_class_cache(void)173 void 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
string_to_security_class(const char * s)196 security_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
mode_to_security_class(mode_t m)213 security_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
string_to_av_perm(security_class_t tclass,const char * s)234 access_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
security_class_to_string(security_class_t tclass)251 const 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
security_av_perm_to_string(security_class_t tclass,access_vector_t av)264 const 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
security_av_string(security_class_t tclass,access_vector_t av,char ** res)282 int 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, "}");
324 out:
325 return rc;
326 }
327
print_access_vector(security_class_t tclass,access_vector_t av)328 void 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