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 #include <sys/types.h>
      9 #include <sys/stat.h>
     10 #include <fcntl.h>
     11 #include <assert.h>
     12 #include <stdlib.h>
     13 #include <dirent.h>
     14 #include <string.h>
     15 #include <stdio.h>
     16 #include <unistd.h>
     17 #include <fnmatch.h>
     18 #include <limits.h>
     19 #include <ctype.h>
     20 #include <errno.h>
     21 
     22 #include "selinux_internal.h"
     23 #include "policy.h"
     24 
     25 #define SELINUX_BOOL_DIR "/booleans/"
     26 
     27 static int filename_select(const struct dirent *d)
     28 {
     29 	if (d->d_name[0] == '.'
     30 	    && (d->d_name[1] == '\0'
     31 		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
     32 		return 0;
     33 	return 1;
     34 }
     35 
     36 int security_get_boolean_names(char ***names, int *len)
     37 {
     38 	char path[PATH_MAX];
     39 	int i, rc;
     40 	struct dirent **namelist;
     41 	char **n;
     42 
     43 	assert(len);
     44 	if (!selinux_mnt) {
     45 		errno = ENOENT;
     46 		return -1;
     47 	}
     48 
     49 	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
     50 	*len = scandir(path, &namelist, &filename_select, alphasort);
     51 	if (*len <= 0) {
     52 		return -1;
     53 	}
     54 
     55 	n = (char **)malloc(sizeof(char *) * *len);
     56 	if (!n) {
     57 		rc = -1;
     58 		goto bad;
     59 	}
     60 
     61 	for (i = 0; i < *len; i++) {
     62 	        n[i] = strdup(namelist[i]->d_name);
     63 		if (!n[i]) {
     64 			rc = -1;
     65 			goto bad_freen;
     66 		}
     67 	}
     68 	rc = 0;
     69 	*names = n;
     70       out:
     71 	for (i = 0; i < *len; i++) {
     72 		free(namelist[i]);
     73 	}
     74 	free(namelist);
     75 	return rc;
     76       bad_freen:
     77 	for (--i; i >= 0; --i)
     78 		free(n[i]);
     79 	free(n);
     80       bad:
     81 	goto out;
     82 }
     83 
     84 hidden_def(security_get_boolean_names)
     85 #define STRBUF_SIZE 3
     86 static int get_bool_value(const char *name, char **buf)
     87 {
     88 	int fd, len;
     89 	char *fname = NULL;
     90 
     91 	if (!selinux_mnt) {
     92 		errno = ENOENT;
     93 		return -1;
     94 	}
     95 
     96 	*buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1));
     97 	if (!*buf)
     98 		goto out;
     99 	(*buf)[STRBUF_SIZE] = 0;
    100 
    101 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
    102 	fname = (char *)malloc(sizeof(char) * len);
    103 	if (!fname)
    104 		goto out;
    105 	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
    106 
    107 	fd = open(fname, O_RDONLY);
    108 	if (fd < 0)
    109 		goto out;
    110 
    111 	len = read(fd, *buf, STRBUF_SIZE);
    112 	close(fd);
    113 	if (len != STRBUF_SIZE)
    114 		goto out;
    115 
    116 	free(fname);
    117 	return 0;
    118       out:
    119 	if (*buf)
    120 		free(*buf);
    121 	if (fname)
    122 		free(fname);
    123 	return -1;
    124 }
    125 
    126 int security_get_boolean_pending(const char *name)
    127 {
    128 	char *buf;
    129 	int val;
    130 
    131 	if (get_bool_value(name, &buf))
    132 		return -1;
    133 
    134 	if (atoi(&buf[1]))
    135 		val = 1;
    136 	else
    137 		val = 0;
    138 	free(buf);
    139 	return val;
    140 }
    141 
    142 int security_get_boolean_active(const char *name)
    143 {
    144 	char *buf;
    145 	int val;
    146 
    147 	if (get_bool_value(name, &buf))
    148 		return -1;
    149 
    150 	buf[1] = '\0';
    151 	if (atoi(buf))
    152 		val = 1;
    153 	else
    154 		val = 0;
    155 	free(buf);
    156 	return val;
    157 }
    158 
    159 hidden_def(security_get_boolean_active)
    160 
    161 int security_set_boolean(const char *name, int value)
    162 {
    163 	int fd, ret, len;
    164 	char buf[2], *fname;
    165 
    166 	if (!selinux_mnt) {
    167 		errno = ENOENT;
    168 		return -1;
    169 	}
    170 	if (value < 0 || value > 1) {
    171 		errno = EINVAL;
    172 		return -1;
    173 	}
    174 
    175 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
    176 	fname = (char *)malloc(sizeof(char) * len);
    177 	if (!fname)
    178 		return -1;
    179 	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
    180 
    181 	fd = open(fname, O_WRONLY);
    182 	if (fd < 0) {
    183 		ret = -1;
    184 		goto out;
    185 	}
    186 
    187 	if (value)
    188 		buf[0] = '1';
    189 	else
    190 		buf[0] = '0';
    191 	buf[1] = '\0';
    192 
    193 	ret = write(fd, buf, 2);
    194 	close(fd);
    195       out:
    196 	free(fname);
    197 	if (ret > 0)
    198 		return 0;
    199 	else
    200 		return -1;
    201 }
    202 
    203 hidden_def(security_set_boolean)
    204 
    205 int security_commit_booleans(void)
    206 {
    207 	int fd, ret;
    208 	char buf[2];
    209 	char path[PATH_MAX];
    210 
    211 	if (!selinux_mnt) {
    212 		errno = ENOENT;
    213 		return -1;
    214 	}
    215 
    216 	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
    217 	fd = open(path, O_WRONLY);
    218 	if (fd < 0)
    219 		return -1;
    220 
    221 	buf[0] = '1';
    222 	buf[1] = '\0';
    223 
    224 	ret = write(fd, buf, 2);
    225 	close(fd);
    226 
    227 	if (ret > 0)
    228 		return 0;
    229 	else
    230 		return -1;
    231 }
    232 
    233 hidden_def(security_commit_booleans)
    234 
    235 static char *strtrim(char *dest, char *source, int size)
    236 {
    237 	int i = 0;
    238 	char *ptr = source;
    239 	i = 0;
    240 	while (isspace(*ptr) && i < size) {
    241 		ptr++;
    242 		i++;
    243 	}
    244 	strncpy(dest, ptr, size);
    245 	for (i = strlen(dest) - 1; i > 0; i--) {
    246 		if (!isspace(dest[i]))
    247 			break;
    248 	}
    249 	dest[i + 1] = '\0';
    250 	return dest;
    251 }
    252 static int process_boolean(char *buffer, char *name, int namesize, int *val)
    253 {
    254 	char name1[BUFSIZ];
    255 	char *ptr;
    256 	char *tok = strtok_r(buffer, "=", &ptr);
    257 	if (tok) {
    258 		strncpy(name1, tok, BUFSIZ - 1);
    259 		strtrim(name, name1, namesize - 1);
    260 		if (name[0] == '#')
    261 			return 0;
    262 		tok = strtok_r(NULL, "\0", &ptr);
    263 		if (tok) {
    264 			while (isspace(*tok))
    265 				tok++;
    266 			*val = -1;
    267 			if (isdigit(tok[0]))
    268 				*val = atoi(tok);
    269 			else if (!strncasecmp(tok, "true", sizeof("true") - 1))
    270 				*val = 1;
    271 			else if (!strncasecmp
    272 				 (tok, "false", sizeof("false") - 1))
    273 				*val = 0;
    274 			if (*val != 0 && *val != 1) {
    275 				errno = EINVAL;
    276 				return -1;
    277 			}
    278 
    279 		}
    280 	}
    281 	return 1;
    282 }
    283 
    284 static void rollback(SELboolean * boollist, int end)
    285 {
    286 	int i;
    287 
    288 	for (i = 0; i < end; i++)
    289 		security_set_boolean(boollist[i].name,
    290 				     security_get_boolean_active(boollist[i].
    291 								 name));
    292 }
    293 
    294 int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
    295 			      int permanent __attribute__((unused)))
    296 {
    297 
    298 	size_t i;
    299 	for (i = 0; i < boolcnt; i++) {
    300 		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
    301 			rollback(boollist, i);
    302 			return -1;
    303 		}
    304 	}
    305 
    306 	/* OK, let's do the commit */
    307 	if (security_commit_booleans()) {
    308 		return -1;
    309 	}
    310 
    311 	return 0;
    312 }
    313