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 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 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 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 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 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 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 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 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 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 } 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 } 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 } 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 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 } 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 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 587 int security_load_booleans(char *path __attribute__((unused))) 588 { 589 return -1; 590 } 591 592 int security_get_boolean_names(char ***names __attribute__((unused)), 593 int *len __attribute__((unused))) 594 { 595 return -1; 596 } 597 598 int security_get_boolean_pending(const char *name __attribute__((unused))) 599 { 600 return -1; 601 } 602 603 int security_get_boolean_active(const char *name __attribute__((unused))) 604 { 605 return -1; 606 } 607 608 int security_set_boolean(const char *name __attribute__((unused)), 609 int value __attribute__((unused))) 610 { 611 return -1; 612 } 613 614 int security_commit_booleans(void) 615 { 616 return -1; 617 } 618 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