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 <sys/types.h> 11#include <sys/stat.h> 12#include <fcntl.h> 13#include <stdlib.h> 14#include <dirent.h> 15#include <string.h> 16#include <stdio.h> 17#include <stdio_ext.h> 18#include <unistd.h> 19#include <fnmatch.h> 20#include <limits.h> 21#include <ctype.h> 22#include <errno.h> 23 24#include "selinux_internal.h" 25#include "policy.h" 26 27#define SELINUX_BOOL_DIR "/booleans/" 28 29static int filename_select(const struct dirent *d) 30{ 31 if (d->d_name[0] == '.' 32 && (d->d_name[1] == '\0' 33 || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) 34 return 0; 35 return 1; 36} 37 38int security_get_boolean_names(char ***names, int *len) 39{ 40 char path[PATH_MAX]; 41 int i, rc; 42 struct dirent **namelist; 43 char **n; 44 45 if (!len || names == NULL) { 46 errno = EINVAL; 47 return -1; 48 } 49 if (!selinux_mnt) { 50 errno = ENOENT; 51 return -1; 52 } 53 54 snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR); 55 *len = scandir(path, &namelist, &filename_select, alphasort); 56 if (*len <= 0) { 57 errno = ENOENT; 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 if (i > 0) { 84 while (i >= 1) 85 free(n[--i]); 86 } 87 free(n); 88 bad: 89 goto out; 90} 91 92char *selinux_boolean_sub(const char *name) 93{ 94 char *sub = NULL; 95 char *line_buf = NULL; 96 size_t line_len; 97 FILE *cfg; 98 99 if (!name) 100 return NULL; 101 102 cfg = fopen(selinux_booleans_subs_path(), "re"); 103 if (!cfg) 104 goto out; 105 106 while (getline(&line_buf, &line_len, cfg) != -1) { 107 char *ptr; 108 char *src = line_buf; 109 char *dst; 110 while (*src && isspace(*src)) 111 src++; 112 if (!*src) 113 continue; 114 if (src[0] == '#') 115 continue; 116 117 ptr = src; 118 while (*ptr && !isspace(*ptr)) 119 ptr++; 120 *ptr++ = '\0'; 121 if (strcmp(src, name) != 0) 122 continue; 123 124 dst = ptr; 125 while (*dst && isspace(*dst)) 126 dst++; 127 if (!*dst) 128 continue; 129 ptr = dst; 130 while (*ptr && !isspace(*ptr)) 131 ptr++; 132 *ptr = '\0'; 133 134 if (!strchr(dst, '/')) 135 sub = strdup(dst); 136 137 break; 138 } 139 free(line_buf); 140 fclose(cfg); 141out: 142 if (!sub) 143 sub = strdup(name); 144 return sub; 145} 146 147static int bool_open(const char *name, int flag) { 148 char *fname = NULL; 149 char *alt_name = NULL; 150 size_t len; 151 int fd = -1; 152 int ret; 153 char *ptr; 154 155 if (!name || strchr(name, '/')) { 156 errno = EINVAL; 157 return -1; 158 } 159 160 /* note the 'sizeof' gets us enough room for the '\0' */ 161 len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); 162 fname = malloc(sizeof(char) * len); 163 if (!fname) 164 return -1; 165 166 ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); 167 if (ret < 0 || (size_t)ret >= len) 168 goto out; 169 170 fd = open(fname, flag); 171 if (fd >= 0 || errno != ENOENT) 172 goto out; 173 174 alt_name = selinux_boolean_sub(name); 175 if (!alt_name) 176 goto out; 177 178 /* note the 'sizeof' gets us enough room for the '\0' */ 179 len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); 180 ptr = realloc(fname, len); 181 if (!ptr) 182 goto out; 183 fname = ptr; 184 185 ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); 186 if (ret < 0 || (size_t)ret >= len) 187 goto out; 188 189 fd = open(fname, flag); 190out: 191 free(fname); 192 free(alt_name); 193 194 return fd; 195} 196 197#define STRBUF_SIZE 3 198static 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; 226out_err: 227 free(*buf); 228 return -1; 229} 230 231int 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 247int 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 264int 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 297int 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 325static void rollback(SELboolean * boollist, int end) 326{ 327 int i; 328 329 for (i = 0; i < end; i++) 330 security_set_boolean(boollist[i].name, 331 security_get_boolean_active(boollist[i]. 332 name)); 333} 334 335int security_set_boolean_list(size_t boolcnt, SELboolean * boollist, 336 int permanent) 337{ 338 339 size_t i; 340 for (i = 0; i < boolcnt; i++) { 341 boollist[i].value = !!boollist[i].value; 342 if (security_set_boolean(boollist[i].name, boollist[i].value)) { 343 rollback(boollist, i); 344 return -1; 345 } 346 } 347 348 /* OK, let's do the commit */ 349 if (security_commit_booleans()) { 350 return -1; 351 } 352 353 /* Return error as flag no longer used */ 354 if (permanent) 355 return -1; 356 357 return 0; 358} 359 360/* This function is deprecated */ 361int security_load_booleans(char *path __attribute__((unused))) 362{ 363 return -1; 364} 365#else 366 367#include <stdlib.h> 368#include "selinux_internal.h" 369 370int security_set_boolean_list(size_t boolcnt __attribute__((unused)), 371 SELboolean * boollist __attribute__((unused)), 372 int permanent __attribute__((unused))) 373{ 374 return -1; 375} 376 377int security_load_booleans(char *path __attribute__((unused))) 378{ 379 return -1; 380} 381 382int security_get_boolean_names(char ***names __attribute__((unused)), 383 int *len __attribute__((unused))) 384{ 385 return -1; 386} 387 388int security_get_boolean_pending(const char *name __attribute__((unused))) 389{ 390 return -1; 391} 392 393int security_get_boolean_active(const char *name __attribute__((unused))) 394{ 395 return -1; 396} 397 398int security_set_boolean(const char *name __attribute__((unused)), 399 int value __attribute__((unused))) 400{ 401 return -1; 402} 403 404int security_commit_booleans(void) 405{ 406 return -1; 407} 408 409char *selinux_boolean_sub(const char *name __attribute__((unused))) 410{ 411 return NULL; 412} 413#endif 414 415