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 | O_CLOEXEC);
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