Home | History | Annotate | Download | only in src
      1 /*
      2  * Author: Karl MacMillan <kmacmillan (at) tresys.com>
      3  *
      4  * Modified:
      5  *   Dan Walsh <dwalsh (at) 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 
     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 
     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 
     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 
    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
    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 
    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 
    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 
    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 
    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 
    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 }
    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 }
    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 }
    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 
    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 }
    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 
    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 
    590 int security_load_booleans(char *path __attribute__((unused)))
    591 {
    592 	return -1;
    593 }
    594 
    595 int security_get_boolean_names(char ***names __attribute__((unused)),
    596 	int *len __attribute__((unused)))
    597 {
    598 	return -1;
    599 }
    600 
    601 int security_get_boolean_pending(const char *name __attribute__((unused)))
    602 {
    603 	return -1;
    604 }
    605 
    606 int security_get_boolean_active(const char *name __attribute__((unused)))
    607 {
    608 	return -1;
    609 }
    610 
    611 int security_set_boolean(const char *name __attribute__((unused)),
    612 	int value __attribute__((unused)))
    613 {
    614 	return -1;
    615 }
    616 
    617 int security_commit_booleans(void)
    618 {
    619 	return -1;
    620 }
    621 
    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