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