1 /*
2 * Author: Karl MacMillan <[email protected]>
3 *
4 * Modified:
5 * Dan Walsh <[email protected]> - Added security_load_booleans().
6 */
7
8 #ifndef DISABLE_BOOL
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <dirent.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdio_ext.h>
18 #include <unistd.h>
19 #include <fnmatch.h>
20 #include <limits.h>
21 #include <ctype.h>
22 #include <errno.h>
23
24 #include "selinux_internal.h"
25 #include "policy.h"
26
27 #define SELINUX_BOOL_DIR "/booleans/"
28
filename_select(const struct dirent * d)29 static int filename_select(const struct dirent *d)
30 {
31 if (d->d_name[0] == '.'
32 && (d->d_name[1] == '\0'
33 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
34 return 0;
35 return 1;
36 }
37
security_get_boolean_names(char *** names,int * len)38 int security_get_boolean_names(char ***names, int *len)
39 {
40 char path[PATH_MAX];
41 int i, rc;
42 struct dirent **namelist;
43 char **n;
44
45 if (!len || names == NULL) {
46 errno = EINVAL;
47 return -1;
48 }
49 if (!selinux_mnt) {
50 errno = ENOENT;
51 return -1;
52 }
53
54 snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
55 *len = scandir(path, &namelist, &filename_select, alphasort);
56 if (*len < 0) {
57 return -1;
58 }
59 if (*len == 0) {
60 free(namelist);
61 errno = ENOENT;
62 return -1;
63 }
64
65 n = (char **)malloc(sizeof(char *) * *len);
66 if (!n) {
67 rc = -1;
68 goto bad;
69 }
70
71 for (i = 0; i < *len; i++) {
72 n[i] = strdup(namelist[i]->d_name);
73 if (!n[i]) {
74 rc = -1;
75 goto bad_freen;
76 }
77 }
78 rc = 0;
79 *names = n;
80 out:
81 for (i = 0; i < *len; i++) {
82 free(namelist[i]);
83 }
84 free(namelist);
85 return rc;
86 bad_freen:
87 if (i > 0) {
88 while (i >= 1)
89 free(n[--i]);
90 }
91 free(n);
92 bad:
93 goto out;
94 }
95
selinux_boolean_sub(const char * name)96 char *selinux_boolean_sub(const char *name)
97 {
98 char *sub = NULL;
99 char *line_buf = NULL;
100 size_t line_len;
101 FILE *cfg;
102
103 if (!name)
104 return NULL;
105
106 cfg = fopen(selinux_booleans_subs_path(), "re");
107 if (!cfg)
108 goto out;
109
110 while (getline(&line_buf, &line_len, cfg) != -1) {
111 char *ptr;
112 char *src = line_buf;
113 char *dst;
114 while (*src && isspace((unsigned char)*src))
115 src++;
116 if (!*src)
117 continue;
118 if (src[0] == '#')
119 continue;
120
121 ptr = src;
122 while (*ptr && !isspace((unsigned char)*ptr))
123 ptr++;
124 *ptr++ = '\0';
125 if (strcmp(src, name) != 0)
126 continue;
127
128 dst = ptr;
129 while (*dst && isspace((unsigned char)*dst))
130 dst++;
131 if (!*dst)
132 continue;
133 ptr = dst;
134 while (*ptr && !isspace((unsigned char)*ptr))
135 ptr++;
136 *ptr = '\0';
137
138 if (!strchr(dst, '/'))
139 sub = strdup(dst);
140
141 break;
142 }
143 free(line_buf);
144 fclose(cfg);
145 out:
146 if (!sub)
147 sub = strdup(name);
148 return sub;
149 }
150
bool_open(const char * name,int flag)151 static int bool_open(const char *name, int flag) {
152 char *fname = NULL;
153 char *alt_name = NULL;
154 size_t len;
155 int fd = -1;
156 int ret;
157 char *ptr;
158
159 if (!name || strchr(name, '/')) {
160 errno = EINVAL;
161 return -1;
162 }
163
164 /* note the 'sizeof' gets us enough room for the '\0' */
165 len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
166 fname = malloc(sizeof(char) * len);
167 if (!fname)
168 return -1;
169
170 ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
171 if (ret < 0 || (size_t)ret >= len)
172 goto out;
173
174 fd = open(fname, flag);
175 if (fd >= 0 || errno != ENOENT)
176 goto out;
177
178 alt_name = selinux_boolean_sub(name);
179 if (!alt_name)
180 goto out;
181
182 /* note the 'sizeof' gets us enough room for the '\0' */
183 len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
184 ptr = realloc(fname, len);
185 if (!ptr)
186 goto out;
187 fname = ptr;
188
189 ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name);
190 if (ret < 0 || (size_t)ret >= len)
191 goto out;
192
193 fd = open(fname, flag);
194 out:
195 free(fname);
196 free(alt_name);
197
198 return fd;
199 }
200
201 #define STRBUF_SIZE 3
get_bool_value(const char * name,char ** buf)202 static int get_bool_value(const char *name, char **buf)
203 {
204 int fd, len;
205 int errno_tmp;
206
207 if (!selinux_mnt) {
208 errno = ENOENT;
209 return -1;
210 }
211
212 *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
213 if (!*buf)
214 return -1;
215
216 (*buf)[STRBUF_SIZE] = 0;
217
218 fd = bool_open(name, O_RDONLY | O_CLOEXEC);
219 if (fd < 0)
220 goto out_err;
221
222 len = read(fd, *buf, STRBUF_SIZE);
223 errno_tmp = errno;
224 close(fd);
225 errno = errno_tmp;
226 if (len != STRBUF_SIZE)
227 goto out_err;
228
229 return 0;
230 out_err:
231 free(*buf);
232 return -1;
233 }
234
security_get_boolean_pending(const char * name)235 int security_get_boolean_pending(const char *name)
236 {
237 char *buf;
238 int val;
239
240 if (get_bool_value(name, &buf))
241 return -1;
242
243 if (atoi(&buf[1]))
244 val = 1;
245 else
246 val = 0;
247 free(buf);
248 return val;
249 }
250
security_get_boolean_active(const char * name)251 int security_get_boolean_active(const char *name)
252 {
253 char *buf;
254 int val;
255
256 if (get_bool_value(name, &buf))
257 return -1;
258
259 buf[1] = '\0';
260 if (atoi(buf))
261 val = 1;
262 else
263 val = 0;
264 free(buf);
265 return val;
266 }
267
security_set_boolean(const char * name,int value)268 int security_set_boolean(const char *name, int value)
269 {
270 int fd, ret;
271 char buf[2];
272
273 if (!selinux_mnt) {
274 errno = ENOENT;
275 return -1;
276 }
277 if (value < 0 || value > 1) {
278 errno = EINVAL;
279 return -1;
280 }
281
282 fd = bool_open(name, O_WRONLY | O_CLOEXEC);
283 if (fd < 0)
284 return -1;
285
286 if (value)
287 buf[0] = '1';
288 else
289 buf[0] = '0';
290 buf[1] = '\0';
291
292 ret = write(fd, buf, 2);
293 close(fd);
294
295 if (ret > 0)
296 return 0;
297 else
298 return -1;
299 }
300
security_commit_booleans(void)301 int security_commit_booleans(void)
302 {
303 int fd, ret;
304 char buf[2];
305 char path[PATH_MAX];
306
307 if (!selinux_mnt) {
308 errno = ENOENT;
309 return -1;
310 }
311
312 snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
313 fd = open(path, O_WRONLY | O_CLOEXEC);
314 if (fd < 0)
315 return -1;
316
317 buf[0] = '1';
318 buf[1] = '\0';
319
320 ret = write(fd, buf, 2);
321 close(fd);
322
323 if (ret > 0)
324 return 0;
325 else
326 return -1;
327 }
328
rollback(SELboolean * boollist,int end)329 static void rollback(SELboolean * boollist, int end)
330 {
331 int i;
332
333 for (i = 0; i < end; i++)
334 security_set_boolean(boollist[i].name,
335 security_get_boolean_active(boollist[i].
336 name));
337 }
338
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)339 int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
340 int permanent)
341 {
342
343 size_t i;
344 for (i = 0; i < boolcnt; i++) {
345 boollist[i].value = !!boollist[i].value;
346 if (security_set_boolean(boollist[i].name, boollist[i].value)) {
347 rollback(boollist, i);
348 return -1;
349 }
350 }
351
352 /* OK, let's do the commit */
353 if (security_commit_booleans()) {
354 return -1;
355 }
356
357 /* Return error as flag no longer used */
358 if (permanent)
359 return -1;
360
361 return 0;
362 }
363
364 /* This function is deprecated */
security_load_booleans(char * path)365 int security_load_booleans(char *path __attribute__((unused)))
366 {
367 return -1;
368 }
369 #else
370
371 #include <stdlib.h>
372 #include "selinux_internal.h"
373
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)374 int security_set_boolean_list(size_t boolcnt __attribute__((unused)),
375 SELboolean * boollist __attribute__((unused)),
376 int permanent __attribute__((unused)))
377 {
378 return -1;
379 }
380
security_load_booleans(char * path)381 int security_load_booleans(char *path __attribute__((unused)))
382 {
383 return -1;
384 }
385
security_get_boolean_names(char *** names,int * len)386 int security_get_boolean_names(char ***names __attribute__((unused)),
387 int *len __attribute__((unused)))
388 {
389 return -1;
390 }
391
security_get_boolean_pending(const char * name)392 int security_get_boolean_pending(const char *name __attribute__((unused)))
393 {
394 return -1;
395 }
396
security_get_boolean_active(const char * name)397 int security_get_boolean_active(const char *name __attribute__((unused)))
398 {
399 return -1;
400 }
401
security_set_boolean(const char * name,int value)402 int security_set_boolean(const char *name __attribute__((unused)),
403 int value __attribute__((unused)))
404 {
405 return -1;
406 }
407
security_commit_booleans(void)408 int security_commit_booleans(void)
409 {
410 return -1;
411 }
412
selinux_boolean_sub(const char * name)413 char *selinux_boolean_sub(const char *name __attribute__((unused)))
414 {
415 return NULL;
416 }
417 #endif
418
419