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