• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Author: Karl MacMillan <kmacmillan@tresys.com>
3  *
4  * Modified:
5  *   Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
6  */
7 
8 #ifndef DISABLE_BOOL
9 
10 #include <assert.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <dirent.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdio_ext.h>
19 #include <unistd.h>
20 #include <fnmatch.h>
21 #include <limits.h>
22 #include <ctype.h>
23 #include <errno.h>
24 
25 #include "selinux_internal.h"
26 #include "policy.h"
27 
28 #define SELINUX_BOOL_DIR "/booleans/"
29 
filename_select(const struct dirent * d)30 static int filename_select(const struct dirent *d)
31 {
32 	if (d->d_name[0] == '.'
33 	    && (d->d_name[1] == '\0'
34 		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
35 		return 0;
36 	return 1;
37 }
38 
security_get_boolean_names(char *** names,int * len)39 int security_get_boolean_names(char ***names, int *len)
40 {
41 	char path[PATH_MAX];
42 	int i, rc;
43 	struct dirent **namelist;
44 	char **n;
45 
46 	if (!len || names == NULL) {
47 		errno = EINVAL;
48 		return -1;
49 	}
50 	if (!selinux_mnt) {
51 		errno = ENOENT;
52 		return -1;
53 	}
54 
55 	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
56 	*len = scandir(path, &namelist, &filename_select, alphasort);
57 	if (*len <= 0) {
58 		errno = ENOENT;
59 		return -1;
60 	}
61 
62 	n = (char **)malloc(sizeof(char *) * *len);
63 	if (!n) {
64 		rc = -1;
65 		goto bad;
66 	}
67 
68 	for (i = 0; i < *len; i++) {
69 		n[i] = strdup(namelist[i]->d_name);
70 		if (!n[i]) {
71 			rc = -1;
72 			goto bad_freen;
73 		}
74 	}
75 	rc = 0;
76 	*names = n;
77       out:
78 	for (i = 0; i < *len; i++) {
79 		free(namelist[i]);
80 	}
81 	free(namelist);
82 	return rc;
83       bad_freen:
84 	for (--i; i >= 0; --i)
85 		free(n[i]);
86 	free(n);
87       bad:
88 	goto out;
89 }
90 
selinux_boolean_sub(const char * name)91 char *selinux_boolean_sub(const char *name)
92 {
93 	char *sub = NULL;
94 	char *line_buf = NULL;
95 	size_t line_len;
96 	FILE *cfg;
97 
98 	if (!name)
99 		return NULL;
100 
101 	cfg = fopen(selinux_booleans_subs_path(), "re");
102 	if (!cfg)
103 		goto out;
104 
105 	while (getline(&line_buf, &line_len, cfg) != -1) {
106 		char *ptr;
107 		char *src = line_buf;
108 		char *dst;
109 		while (*src && isspace(*src))
110 			src++;
111 		if (!*src)
112 			continue;
113 		if (src[0] == '#')
114 			continue;
115 
116 		ptr = src;
117 		while (*ptr && !isspace(*ptr))
118 			ptr++;
119 		*ptr++ = '\0';
120 		if (strcmp(src, name) != 0)
121 			continue;
122 
123 		dst = ptr;
124 		while (*dst && isspace(*dst))
125 			dst++;
126 		if (!*dst)
127 			continue;
128 		ptr=dst;
129 		while (*ptr && !isspace(*ptr))
130 			ptr++;
131 		*ptr='\0';
132 
133 		sub = strdup(dst);
134 
135 		break;
136 	}
137 	free(line_buf);
138 	fclose(cfg);
139 out:
140 	if (!sub)
141 		sub = strdup(name);
142 	return sub;
143 }
144 
bool_open(const char * name,int flag)145 static int bool_open(const char *name, int flag) {
146 	char *fname = NULL;
147 	char *alt_name = NULL;
148 	int len;
149 	int fd = -1;
150 	int ret;
151 	char *ptr;
152 
153 	if (!name) {
154 		errno = EINVAL;
155 		return -1;
156 	}
157 
158 	/* note the 'sizeof' gets us enough room for the '\0' */
159 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
160 	fname = malloc(sizeof(char) * len);
161 	if (!fname)
162 		return -1;
163 
164 	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
165 	if (ret < 0)
166 		goto out;
167 	assert(ret < len);
168 
169 	fd = open(fname, flag);
170 	if (fd >= 0 || errno != ENOENT)
171 		goto out;
172 
173 	alt_name = selinux_boolean_sub(name);
174 	if (!alt_name)
175 		goto out;
176 
177 	/* note the 'sizeof' gets us enough room for the '\0' */
178 	len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
179 	ptr = realloc(fname, len);
180 	if (!ptr)
181 		goto out;
182 	fname = ptr;
183 
184 	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name);
185 	if (ret < 0)
186 		goto out;
187 	assert(ret < len);
188 
189 	fd = open(fname, flag);
190 out:
191 	free(fname);
192 	free(alt_name);
193 
194 	return fd;
195 }
196 
197 #define STRBUF_SIZE 3
get_bool_value(const char * name,char ** buf)198 static int get_bool_value(const char *name, char **buf)
199 {
200 	int fd, len;
201 	int errno_tmp;
202 
203 	if (!selinux_mnt) {
204 		errno = ENOENT;
205 		return -1;
206 	}
207 
208 	*buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
209 	if (!*buf)
210 		return -1;
211 
212 	(*buf)[STRBUF_SIZE] = 0;
213 
214 	fd = bool_open(name, O_RDONLY | O_CLOEXEC);
215 	if (fd < 0)
216 		goto out_err;
217 
218 	len = read(fd, *buf, STRBUF_SIZE);
219 	errno_tmp = errno;
220 	close(fd);
221 	errno = errno_tmp;
222 	if (len != STRBUF_SIZE)
223 		goto out_err;
224 
225 	return 0;
226 out_err:
227 	free(*buf);
228 	return -1;
229 }
230 
security_get_boolean_pending(const char * name)231 int security_get_boolean_pending(const char *name)
232 {
233 	char *buf;
234 	int val;
235 
236 	if (get_bool_value(name, &buf))
237 		return -1;
238 
239 	if (atoi(&buf[1]))
240 		val = 1;
241 	else
242 		val = 0;
243 	free(buf);
244 	return val;
245 }
246 
security_get_boolean_active(const char * name)247 int security_get_boolean_active(const char *name)
248 {
249 	char *buf;
250 	int val;
251 
252 	if (get_bool_value(name, &buf))
253 		return -1;
254 
255 	buf[1] = '\0';
256 	if (atoi(buf))
257 		val = 1;
258 	else
259 		val = 0;
260 	free(buf);
261 	return val;
262 }
263 
security_set_boolean(const char * name,int value)264 int security_set_boolean(const char *name, int value)
265 {
266 	int fd, ret;
267 	char buf[2];
268 
269 	if (!selinux_mnt) {
270 		errno = ENOENT;
271 		return -1;
272 	}
273 	if (value < 0 || value > 1) {
274 		errno = EINVAL;
275 		return -1;
276 	}
277 
278 	fd = bool_open(name, O_WRONLY | O_CLOEXEC);
279 	if (fd < 0)
280 		return -1;
281 
282 	if (value)
283 		buf[0] = '1';
284 	else
285 		buf[0] = '0';
286 	buf[1] = '\0';
287 
288 	ret = write(fd, buf, 2);
289 	close(fd);
290 
291 	if (ret > 0)
292 		return 0;
293 	else
294 		return -1;
295 }
296 
security_commit_booleans(void)297 int security_commit_booleans(void)
298 {
299 	int fd, ret;
300 	char buf[2];
301 	char path[PATH_MAX];
302 
303 	if (!selinux_mnt) {
304 		errno = ENOENT;
305 		return -1;
306 	}
307 
308 	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
309 	fd = open(path, O_WRONLY | O_CLOEXEC);
310 	if (fd < 0)
311 		return -1;
312 
313 	buf[0] = '1';
314 	buf[1] = '\0';
315 
316 	ret = write(fd, buf, 2);
317 	close(fd);
318 
319 	if (ret > 0)
320 		return 0;
321 	else
322 		return -1;
323 }
324 
strtrim(char * dest,char * source,int size)325 static char *strtrim(char *dest, char *source, int size)
326 {
327 	int i = 0;
328 	char *ptr = source;
329 	i = 0;
330 	while (isspace(*ptr) && i < size) {
331 		ptr++;
332 		i++;
333 	}
334 	strncpy(dest, ptr, size);
335 	for (i = strlen(dest) - 1; i > 0; i--) {
336 		if (!isspace(dest[i]))
337 			break;
338 	}
339 	dest[i + 1] = '\0';
340 	return dest;
341 }
process_boolean(char * buffer,char * name,int namesize,int * val)342 static int process_boolean(char *buffer, char *name, int namesize, int *val)
343 {
344 	char name1[BUFSIZ];
345 	char *ptr = NULL;
346 	char *tok;
347 
348 	/* Skip spaces */
349 	while (isspace(buffer[0]))
350 		buffer++;
351 	/* Ignore comments */
352 	if (buffer[0] == '#')
353 		return 0;
354 
355 	tok = strtok_r(buffer, "=", &ptr);
356 	if (!tok) {
357 		errno = EINVAL;
358 		return -1;
359 	}
360 	strncpy(name1, tok, BUFSIZ - 1);
361 	strtrim(name, name1, namesize - 1);
362 
363 	tok = strtok_r(NULL, "\0", &ptr);
364 	if (!tok) {
365 		errno = EINVAL;
366 		return -1;
367 	}
368 
369 	while (isspace(*tok))
370 		tok++;
371 
372 	*val = -1;
373 	if (isdigit(tok[0]))
374 		*val = atoi(tok);
375 	else if (!strncasecmp(tok, "true", sizeof("true") - 1))
376 		*val = 1;
377 	else if (!strncasecmp(tok, "false", sizeof("false") - 1))
378 		*val = 0;
379 	if (*val != 0 && *val != 1) {
380 		errno = EINVAL;
381 		return -1;
382 	}
383 	return 1;
384 }
save_booleans(size_t boolcnt,SELboolean * boollist)385 static int save_booleans(size_t boolcnt, SELboolean * boollist)
386 {
387 	ssize_t len;
388 	size_t i;
389 	char outbuf[BUFSIZ];
390 	char *inbuf = NULL;
391 
392 	/* Open file */
393 	const char *bool_file = selinux_booleans_path();
394 	char local_bool_file[PATH_MAX];
395 	char tmp_bool_file[PATH_MAX];
396 	FILE *boolf;
397 	int fd;
398 	int *used = (int *)malloc(sizeof(int) * boolcnt);
399 	if (!used) {
400 		return -1;
401 	}
402 	/* zero out used field */
403 	for (i = 0; i < boolcnt; i++)
404 		used[i] = 0;
405 
406 	snprintf(tmp_bool_file, sizeof(tmp_bool_file), "%s.XXXXXX", bool_file);
407 	fd = mkstemp(tmp_bool_file);
408 	if (fd < 0) {
409 		free(used);
410 		return -1;
411 	}
412 
413 	snprintf(local_bool_file, sizeof(local_bool_file), "%s.local",
414 		 bool_file);
415 	boolf = fopen(local_bool_file, "re");
416 	if (boolf != NULL) {
417 		ssize_t ret;
418 		size_t size = 0;
419 		int val;
420 		char boolname[BUFSIZ-3];
421 		char *buffer;
422 		inbuf = NULL;
423 		__fsetlocking(boolf, FSETLOCKING_BYCALLER);
424 		while ((len = getline(&inbuf, &size, boolf)) > 0) {
425 			buffer = strdup(inbuf);
426 			if (!buffer)
427 				goto close_remove_fail;
428 			ret =
429 			    process_boolean(inbuf, boolname, sizeof(boolname),
430 					    &val);
431 			if (ret != 1) {
432 				ret = write(fd, buffer, len);
433 				free(buffer);
434 				if (ret != len)
435 					goto close_remove_fail;
436 			} else {
437 				free(buffer);
438 				for (i = 0; i < boolcnt; i++) {
439 					if (strcmp(boollist[i].name, boolname)
440 					    == 0) {
441 						snprintf(outbuf, sizeof(outbuf),
442 							 "%s=%d\n", boolname,
443 							 boollist[i].value);
444 						len = strlen(outbuf);
445 						used[i] = 1;
446 						if (write(fd, outbuf, len) !=
447 						    len)
448 							goto close_remove_fail;
449 						else
450 							break;
451 					}
452 				}
453 				if (i == boolcnt) {
454 					val = !!val;
455 					snprintf(outbuf, sizeof(outbuf),
456 						 "%s=%d\n", boolname, val);
457 					len = strlen(outbuf);
458 					if (write(fd, outbuf, len) != len)
459 						goto close_remove_fail;
460 				}
461 			}
462 			free(inbuf);
463 			inbuf = NULL;
464 		}
465 		fclose(boolf);
466 	}
467 
468 	for (i = 0; i < boolcnt; i++) {
469 		if (used[i] == 0) {
470 			snprintf(outbuf, sizeof(outbuf), "%s=%d\n",
471 				 boollist[i].name, boollist[i].value);
472 			len = strlen(outbuf);
473 			if (write(fd, outbuf, len) != len) {
474 			      close_remove_fail:
475 				free(inbuf);
476 				close(fd);
477 			      remove_fail:
478 				unlink(tmp_bool_file);
479 				free(used);
480 				return -1;
481 			}
482 		}
483 
484 	}
485 	if (fchmod(fd, S_IRUSR | S_IWUSR) != 0)
486 		goto close_remove_fail;
487 	close(fd);
488 	if (rename(tmp_bool_file, local_bool_file) != 0)
489 		goto remove_fail;
490 
491 	free(used);
492 	return 0;
493 }
rollback(SELboolean * boollist,int end)494 static void rollback(SELboolean * boollist, int end)
495 {
496 	int i;
497 
498 	for (i = 0; i < end; i++)
499 		security_set_boolean(boollist[i].name,
500 				     security_get_boolean_active(boollist[i].
501 								 name));
502 }
503 
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)504 int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
505 			      int permanent)
506 {
507 
508 	size_t i;
509 	for (i = 0; i < boolcnt; i++) {
510 		boollist[i].value = !!boollist[i].value;
511 		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
512 			rollback(boollist, i);
513 			return -1;
514 		}
515 	}
516 
517 	/* OK, let's do the commit */
518 	if (security_commit_booleans()) {
519 		return -1;
520 	}
521 
522 	if (permanent)
523 		return save_booleans(boolcnt, boollist);
524 
525 	return 0;
526 }
security_load_booleans(char * path)527 int security_load_booleans(char *path)
528 {
529 	FILE *boolf;
530 	char *inbuf;
531 	char localbools[BUFSIZ];
532 	size_t len = 0, errors = 0;
533 	int val;
534 	char name[BUFSIZ];
535 
536 	boolf = fopen(path ? path : selinux_booleans_path(), "re");
537 	if (boolf == NULL)
538 		goto localbool;
539 
540 	__fsetlocking(boolf, FSETLOCKING_BYCALLER);
541 	while (getline(&inbuf, &len, boolf) > 0) {
542 		int ret = process_boolean(inbuf, name, sizeof(name), &val);
543 		if (ret == -1)
544 			errors++;
545 		if (ret == 1)
546 			if (security_set_boolean(name, val) < 0) {
547 				errors++;
548 			}
549 	}
550 	fclose(boolf);
551       localbool:
552 	snprintf(localbools, sizeof(localbools), "%s.local",
553 		 (path ? path : selinux_booleans_path()));
554 	boolf = fopen(localbools, "re");
555 
556 	if (boolf != NULL) {
557 		int ret;
558 		__fsetlocking(boolf, FSETLOCKING_BYCALLER);
559 		while (getline(&inbuf, &len, boolf) > 0) {
560 			ret = process_boolean(inbuf, name, sizeof(name), &val);
561 			if (ret == -1)
562 				errors++;
563 			if (ret == 1)
564 				if (security_set_boolean(name, val) < 0) {
565 					errors++;
566 				}
567 		}
568 		fclose(boolf);
569 	}
570 	if (security_commit_booleans() < 0)
571 		return -1;
572 
573 	if (errors)
574 		errno = EINVAL;
575 	return errors ? -1 : 0;
576 }
577 
578 #else
579 
580 #include <stdlib.h>
581 #include "selinux_internal.h"
582 
security_set_boolean_list(size_t boolcnt,SELboolean * boollist,int permanent)583 int security_set_boolean_list(size_t boolcnt __attribute__((unused)),
584 	SELboolean * boollist __attribute__((unused)),
585 	int permanent __attribute__((unused)))
586 {
587 	return -1;
588 }
589 
security_load_booleans(char * path)590 int security_load_booleans(char *path __attribute__((unused)))
591 {
592 	return -1;
593 }
594 
security_get_boolean_names(char *** names,int * len)595 int security_get_boolean_names(char ***names __attribute__((unused)),
596 	int *len __attribute__((unused)))
597 {
598 	return -1;
599 }
600 
security_get_boolean_pending(const char * name)601 int security_get_boolean_pending(const char *name __attribute__((unused)))
602 {
603 	return -1;
604 }
605 
security_get_boolean_active(const char * name)606 int security_get_boolean_active(const char *name __attribute__((unused)))
607 {
608 	return -1;
609 }
610 
security_set_boolean(const char * name,int value)611 int security_set_boolean(const char *name __attribute__((unused)),
612 	int value __attribute__((unused)))
613 {
614 	return -1;
615 }
616 
security_commit_booleans(void)617 int security_commit_booleans(void)
618 {
619 	return -1;
620 }
621 
selinux_boolean_sub(const char * name)622 char *selinux_boolean_sub(const char *name __attribute__((unused)))
623 {
624 	return NULL;
625 }
626 #endif
627 
628 hidden_def(security_get_boolean_names)
629 hidden_def(selinux_boolean_sub)
630 hidden_def(security_get_boolean_active)
631 hidden_def(security_set_boolean)
632 hidden_def(security_commit_booleans)
633