1 /* Author: Jason Tang <jtang (at) tresys.com> 2 * Christopher Ashworth <cashworth (at) tresys.com> 3 * 4 * Copyright (C) 2004-2006 Tresys Technology, LLC 5 * Copyright (C) 2005 Red Hat, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 #include <sepol/module.h> 23 #include <sepol/handle.h> 24 #include <sepol/cil/cil.h> 25 #include <selinux/selinux.h> 26 27 #include <assert.h> 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdio_ext.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 #include <limits.h> 37 #include <errno.h> 38 #include <dirent.h> 39 40 #include "user_internal.h" 41 #include "seuser_internal.h" 42 #include "port_internal.h" 43 #include "iface_internal.h" 44 #include "boolean_internal.h" 45 #include "fcontext_internal.h" 46 #include "node_internal.h" 47 #include "genhomedircon.h" 48 49 #include "debug.h" 50 #include "handle.h" 51 #include "modules.h" 52 #include "direct_api.h" 53 #include "semanage_store.h" 54 #include "database_policydb.h" 55 #include "policy.h" 56 #include <sys/mman.h> 57 #include <sys/wait.h> 58 59 #define PIPE_READ 0 60 #define PIPE_WRITE 1 61 62 static void semanage_direct_destroy(semanage_handle_t * sh); 63 static int semanage_direct_disconnect(semanage_handle_t * sh); 64 static int semanage_direct_begintrans(semanage_handle_t * sh); 65 static int semanage_direct_commit(semanage_handle_t * sh); 66 static int semanage_direct_install(semanage_handle_t * sh, char *data, 67 size_t data_len, const char *module_name, const char *lang_ext); 68 static int semanage_direct_install_file(semanage_handle_t * sh, const char *module_name); 69 static int semanage_direct_extract(semanage_handle_t * sh, 70 semanage_module_key_t *modkey, 71 int extract_cil, 72 void **mapped_data, 73 size_t *data_len, 74 semanage_module_info_t **modinfo); 75 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name); 76 static int semanage_direct_list(semanage_handle_t * sh, 77 semanage_module_info_t ** modinfo, 78 int *num_modules); 79 static int semanage_direct_get_enabled(semanage_handle_t *sh, 80 const semanage_module_key_t *modkey, 81 int *enabled); 82 static int semanage_direct_set_enabled(semanage_handle_t *sh, 83 const semanage_module_key_t *modkey, 84 int enabled); 85 86 static int semanage_direct_get_module_info(semanage_handle_t *sh, 87 const semanage_module_key_t *modkey, 88 semanage_module_info_t **modinfo); 89 90 static int semanage_direct_list_all(semanage_handle_t *sh, 91 semanage_module_info_t **modinfo, 92 int *num_modules); 93 94 static int semanage_direct_install_info(semanage_handle_t *sh, 95 const semanage_module_info_t *modinfo, 96 char *data, 97 size_t data_len); 98 99 static int semanage_direct_remove_key(semanage_handle_t *sh, 100 const semanage_module_key_t *modkey); 101 102 static struct semanage_policy_table direct_funcs = { 103 .get_serial = semanage_direct_get_serial, 104 .destroy = semanage_direct_destroy, 105 .disconnect = semanage_direct_disconnect, 106 .begin_trans = semanage_direct_begintrans, 107 .commit = semanage_direct_commit, 108 .install = semanage_direct_install, 109 .extract = semanage_direct_extract, 110 .install_file = semanage_direct_install_file, 111 .remove = semanage_direct_remove, 112 .list = semanage_direct_list, 113 .get_enabled = semanage_direct_get_enabled, 114 .set_enabled = semanage_direct_set_enabled, 115 .get_module_info = semanage_direct_get_module_info, 116 .list_all = semanage_direct_list_all, 117 .install_info = semanage_direct_install_info, 118 .remove_key = semanage_direct_remove_key, 119 }; 120 121 int semanage_direct_is_managed(semanage_handle_t * sh) 122 { 123 if (semanage_check_init(sh, sh->conf->store_root_path)) 124 goto err; 125 126 if (semanage_access_check(sh) < 0) 127 return 0; 128 129 return 1; 130 131 err: 132 ERR(sh, "could not check whether policy is managed"); 133 return STATUS_ERR; 134 } 135 136 /* Check that the module store exists, creating it if necessary. 137 */ 138 int semanage_direct_connect(semanage_handle_t * sh) 139 { 140 const char *path; 141 142 if (semanage_check_init(sh, sh->conf->store_root_path)) 143 goto err; 144 145 if (sh->create_store) 146 if (semanage_create_store(sh, 1)) 147 goto err; 148 149 if (semanage_access_check(sh) < SEMANAGE_CAN_READ) 150 goto err; 151 152 sh->u.direct.translock_file_fd = -1; 153 sh->u.direct.activelock_file_fd = -1; 154 155 /* set up function pointers */ 156 sh->funcs = &direct_funcs; 157 158 /* Object databases: local modifications */ 159 if (user_base_file_dbase_init(sh, 160 semanage_path(SEMANAGE_ACTIVE, 161 SEMANAGE_USERS_BASE_LOCAL), 162 semanage_path(SEMANAGE_TMP, 163 SEMANAGE_USERS_BASE_LOCAL), 164 semanage_user_base_dbase_local(sh)) < 0) 165 goto err; 166 167 if (user_extra_file_dbase_init(sh, 168 semanage_path(SEMANAGE_ACTIVE, 169 SEMANAGE_USERS_EXTRA_LOCAL), 170 semanage_path(SEMANAGE_TMP, 171 SEMANAGE_USERS_EXTRA_LOCAL), 172 semanage_user_extra_dbase_local(sh)) < 0) 173 goto err; 174 175 if (user_join_dbase_init(sh, 176 semanage_user_base_dbase_local(sh), 177 semanage_user_extra_dbase_local(sh), 178 semanage_user_dbase_local(sh)) < 0) 179 goto err; 180 181 if (port_file_dbase_init(sh, 182 semanage_path(SEMANAGE_ACTIVE, 183 SEMANAGE_PORTS_LOCAL), 184 semanage_path(SEMANAGE_TMP, 185 SEMANAGE_PORTS_LOCAL), 186 semanage_port_dbase_local(sh)) < 0) 187 goto err; 188 189 if (iface_file_dbase_init(sh, 190 semanage_path(SEMANAGE_ACTIVE, 191 SEMANAGE_INTERFACES_LOCAL), 192 semanage_path(SEMANAGE_TMP, 193 SEMANAGE_INTERFACES_LOCAL), 194 semanage_iface_dbase_local(sh)) < 0) 195 goto err; 196 197 if (bool_file_dbase_init(sh, 198 semanage_path(SEMANAGE_ACTIVE, 199 SEMANAGE_BOOLEANS_LOCAL), 200 semanage_path(SEMANAGE_TMP, 201 SEMANAGE_BOOLEANS_LOCAL), 202 semanage_bool_dbase_local(sh)) < 0) 203 goto err; 204 205 if (fcontext_file_dbase_init(sh, 206 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_LOCAL), 207 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL), 208 semanage_fcontext_dbase_local(sh)) < 0) 209 goto err; 210 211 if (seuser_file_dbase_init(sh, 212 semanage_path(SEMANAGE_ACTIVE, 213 SEMANAGE_SEUSERS_LOCAL), 214 semanage_path(SEMANAGE_TMP, 215 SEMANAGE_SEUSERS_LOCAL), 216 semanage_seuser_dbase_local(sh)) < 0) 217 goto err; 218 219 if (node_file_dbase_init(sh, 220 semanage_path(SEMANAGE_ACTIVE, 221 SEMANAGE_NODES_LOCAL), 222 semanage_path(SEMANAGE_TMP, 223 SEMANAGE_NODES_LOCAL), 224 semanage_node_dbase_local(sh)) < 0) 225 goto err; 226 227 /* Object databases: local modifications + policy */ 228 if (user_base_policydb_dbase_init(sh, 229 semanage_user_base_dbase_policy(sh)) < 230 0) 231 goto err; 232 233 if (user_extra_file_dbase_init(sh, 234 semanage_path(SEMANAGE_ACTIVE, 235 SEMANAGE_USERS_EXTRA), 236 semanage_path(SEMANAGE_TMP, 237 SEMANAGE_USERS_EXTRA), 238 semanage_user_extra_dbase_policy(sh)) < 239 0) 240 goto err; 241 242 if (user_join_dbase_init(sh, 243 semanage_user_base_dbase_policy(sh), 244 semanage_user_extra_dbase_policy(sh), 245 semanage_user_dbase_policy(sh)) < 0) 246 goto err; 247 248 if (port_policydb_dbase_init(sh, semanage_port_dbase_policy(sh)) < 0) 249 goto err; 250 251 if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0) 252 goto err; 253 254 if (bool_policydb_dbase_init(sh, semanage_bool_dbase_policy(sh)) < 0) 255 goto err; 256 257 if (fcontext_file_dbase_init(sh, 258 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC), 259 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), 260 semanage_fcontext_dbase_policy(sh)) < 0) 261 goto err; 262 263 if (seuser_file_dbase_init(sh, 264 semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_SEUSERS), 265 semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS), 266 semanage_seuser_dbase_policy(sh)) < 0) 267 goto err; 268 269 if (node_policydb_dbase_init(sh, semanage_node_dbase_policy(sh)) < 0) 270 goto err; 271 272 /* Active kernel policy */ 273 if (bool_activedb_dbase_init(sh, semanage_bool_dbase_active(sh)) < 0) 274 goto err; 275 276 /* set the disable dontaudit value */ 277 path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_DISABLE_DONTAUDIT); 278 if (access(path, F_OK) == 0) 279 sepol_set_disable_dontaudit(sh->sepolh, 1); 280 else 281 sepol_set_disable_dontaudit(sh->sepolh, 0); 282 283 return STATUS_SUCCESS; 284 285 err: 286 ERR(sh, "could not establish direct connection"); 287 return STATUS_ERR; 288 } 289 290 static void semanage_direct_destroy(semanage_handle_t * sh 291 __attribute__ ((unused))) 292 { 293 /* do nothing */ 294 } 295 296 static int semanage_direct_disconnect(semanage_handle_t * sh) 297 { 298 /* destroy transaction */ 299 if (sh->is_in_transaction) { 300 /* destroy sandbox */ 301 if (semanage_remove_directory 302 (semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)) < 0) { 303 ERR(sh, "Could not cleanly remove sandbox %s.", 304 semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); 305 return -1; 306 } 307 if (semanage_remove_directory 308 (semanage_final_path(SEMANAGE_FINAL_TMP, 309 SEMANAGE_FINAL_TOPLEVEL)) < 0) { 310 ERR(sh, "Could not cleanly remove tmp %s.", 311 semanage_final_path(SEMANAGE_FINAL_TMP, 312 SEMANAGE_FINAL_TOPLEVEL)); 313 return -1; 314 } 315 semanage_release_trans_lock(sh); 316 } 317 318 /* Release object databases: local modifications */ 319 user_base_file_dbase_release(semanage_user_base_dbase_local(sh)); 320 user_extra_file_dbase_release(semanage_user_extra_dbase_local(sh)); 321 user_join_dbase_release(semanage_user_dbase_local(sh)); 322 port_file_dbase_release(semanage_port_dbase_local(sh)); 323 iface_file_dbase_release(semanage_iface_dbase_local(sh)); 324 bool_file_dbase_release(semanage_bool_dbase_local(sh)); 325 fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh)); 326 seuser_file_dbase_release(semanage_seuser_dbase_local(sh)); 327 node_file_dbase_release(semanage_node_dbase_local(sh)); 328 329 /* Release object databases: local modifications + policy */ 330 user_base_policydb_dbase_release(semanage_user_base_dbase_policy(sh)); 331 user_extra_file_dbase_release(semanage_user_extra_dbase_policy(sh)); 332 user_join_dbase_release(semanage_user_dbase_policy(sh)); 333 port_policydb_dbase_release(semanage_port_dbase_policy(sh)); 334 iface_policydb_dbase_release(semanage_iface_dbase_policy(sh)); 335 bool_policydb_dbase_release(semanage_bool_dbase_policy(sh)); 336 fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh)); 337 seuser_file_dbase_release(semanage_seuser_dbase_policy(sh)); 338 node_policydb_dbase_release(semanage_node_dbase_policy(sh)); 339 340 /* Release object databases: active kernel policy */ 341 bool_activedb_dbase_release(semanage_bool_dbase_active(sh)); 342 343 return 0; 344 } 345 346 static int semanage_direct_begintrans(semanage_handle_t * sh) 347 { 348 349 if (semanage_access_check(sh) != SEMANAGE_CAN_WRITE) { 350 return -1; 351 } 352 if (semanage_get_trans_lock(sh) < 0) { 353 return -1; 354 } 355 if ((semanage_make_sandbox(sh)) < 0) { 356 return -1; 357 } 358 if ((semanage_make_final(sh)) < 0) { 359 return -1; 360 } 361 return 0; 362 } 363 364 /********************* utility functions *********************/ 365 366 /* Takes a module stored in 'module_data' and parses its headers. 367 * Sets reference variables 'module_name' to module's name, and 368 * 'version' to module's version. The caller is responsible for 369 * free()ing 'module_name', and 'version'; they will be 370 * set to NULL upon entering this function. Returns 0 on success, -1 371 * if out of memory. 372 */ 373 static int parse_module_headers(semanage_handle_t * sh, char *module_data, 374 size_t data_len, char **module_name, 375 char **version) 376 { 377 struct sepol_policy_file *pf; 378 int file_type; 379 *module_name = *version = NULL; 380 381 if (sepol_policy_file_create(&pf)) { 382 ERR(sh, "Out of memory!"); 383 return -1; 384 } 385 sepol_policy_file_set_mem(pf, module_data, data_len); 386 sepol_policy_file_set_handle(pf, sh->sepolh); 387 if (module_data != NULL && data_len > 0) 388 sepol_module_package_info(pf, &file_type, module_name, 389 version); 390 sepol_policy_file_free(pf); 391 392 return 0; 393 } 394 395 #include <stdlib.h> 396 #include <bzlib.h> 397 #include <string.h> 398 #include <sys/sendfile.h> 399 400 /* bzip() a data to a file, returning the total number of compressed bytes 401 * in the file. Returns -1 if file could not be compressed. */ 402 static ssize_t bzip(semanage_handle_t *sh, const char *filename, char *data, 403 size_t num_bytes) 404 { 405 BZFILE* b; 406 size_t size = 1<<16; 407 int bzerror; 408 size_t total = 0; 409 size_t len = 0; 410 FILE *f; 411 412 if ((f = fopen(filename, "wb")) == NULL) { 413 return -1; 414 } 415 416 if (!sh->conf->bzip_blocksize) { 417 if (fwrite(data, 1, num_bytes, f) < num_bytes) { 418 fclose(f); 419 return -1; 420 } 421 fclose(f); 422 return num_bytes; 423 } 424 425 b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0); 426 if (bzerror != BZ_OK) { 427 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 ); 428 return -1; 429 } 430 431 while ( num_bytes > total ) { 432 if (num_bytes - total > size) { 433 len = size; 434 } else { 435 len = num_bytes - total; 436 } 437 BZ2_bzWrite ( &bzerror, b, &data[total], len ); 438 if (bzerror == BZ_IO_ERROR) { 439 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 ); 440 return -1; 441 } 442 total += len; 443 } 444 445 BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 ); 446 fclose(f); 447 if (bzerror == BZ_IO_ERROR) { 448 return -1; 449 } 450 return total; 451 } 452 453 #define BZ2_MAGICSTR "BZh" 454 #define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1) 455 456 /* bunzip() a file to '*data', returning the total number of uncompressed bytes 457 * in the file. Returns -1 if file could not be decompressed. */ 458 ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data) 459 { 460 BZFILE* b = NULL; 461 size_t nBuf; 462 char* buf = NULL; 463 size_t size = 1<<18; 464 size_t bufsize = size; 465 int bzerror; 466 size_t total=0; 467 char* uncompress = NULL; 468 char* tmpalloc = NULL; 469 int ret = -1; 470 471 buf = malloc(bufsize); 472 if (buf == NULL) { 473 ERR(sh, "Failure allocating memory."); 474 goto exit; 475 } 476 477 /* Check if the file is bzipped */ 478 bzerror = fread(buf, 1, BZ2_MAGICLEN, f); 479 rewind(f); 480 if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) { 481 goto exit; 482 } 483 484 b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 ); 485 if ( bzerror != BZ_OK ) { 486 ERR(sh, "Failure opening bz2 archive."); 487 goto exit; 488 } 489 490 uncompress = malloc(size); 491 if (uncompress == NULL) { 492 ERR(sh, "Failure allocating memory."); 493 goto exit; 494 } 495 496 while ( bzerror == BZ_OK) { 497 nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize); 498 if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) { 499 if (total + nBuf > size) { 500 size *= 2; 501 tmpalloc = realloc(uncompress, size); 502 if (tmpalloc == NULL) { 503 ERR(sh, "Failure allocating memory."); 504 goto exit; 505 } 506 uncompress = tmpalloc; 507 } 508 memcpy(&uncompress[total], buf, nBuf); 509 total += nBuf; 510 } 511 } 512 if ( bzerror != BZ_STREAM_END ) { 513 ERR(sh, "Failure reading bz2 archive."); 514 goto exit; 515 } 516 517 ret = total; 518 *data = uncompress; 519 520 exit: 521 BZ2_bzReadClose ( &bzerror, b ); 522 free(buf); 523 if ( ret < 0 ) { 524 free(uncompress); 525 } 526 return ret; 527 } 528 529 /* mmap() a file to '*data', 530 * If the file is bzip compressed map_file will uncompress 531 * the file into '*data'. 532 * Returns the total number of bytes in memory . 533 * Returns -1 if file could not be opened or mapped. */ 534 static ssize_t map_file(semanage_handle_t *sh, const char *path, char **data, 535 int *compressed) 536 { 537 ssize_t size = -1; 538 char *uncompress; 539 int fd = -1; 540 FILE *file = NULL; 541 542 fd = open(path, O_RDONLY); 543 if (fd == -1) { 544 ERR(sh, "Unable to open %s\n", path); 545 return -1; 546 } 547 548 file = fdopen(fd, "r"); 549 if (file == NULL) { 550 ERR(sh, "Unable to open %s\n", path); 551 close(fd); 552 return -1; 553 } 554 555 if ((size = bunzip(sh, file, &uncompress)) > 0) { 556 *data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 557 if (*data == MAP_FAILED) { 558 free(uncompress); 559 fclose(file); 560 return -1; 561 } else { 562 memcpy(*data, uncompress, size); 563 } 564 free(uncompress); 565 *compressed = 1; 566 } else { 567 struct stat sb; 568 if (fstat(fd, &sb) == -1 || 569 (*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == 570 MAP_FAILED) { 571 size = -1; 572 } else { 573 size = sb.st_size; 574 } 575 *compressed = 0; 576 } 577 578 fclose(file); 579 580 return size; 581 } 582 583 /* Writes a block of data to a file. Returns 0 on success, -1 on 584 * error. */ 585 static int write_file(semanage_handle_t * sh, 586 const char *filename, char *data, size_t num_bytes) 587 { 588 int out; 589 590 if ((out = 591 open(filename, O_WRONLY | O_CREAT | O_TRUNC, 592 S_IRUSR | S_IWUSR)) == -1) { 593 ERR(sh, "Could not open %s for writing.", filename); 594 return -1; 595 } 596 if (write(out, data, num_bytes) == -1) { 597 ERR(sh, "Error while writing to %s.", filename); 598 close(out); 599 return -1; 600 } 601 close(out); 602 return 0; 603 } 604 605 static int semanage_direct_update_user_extra(semanage_handle_t * sh, cil_db_t *cildb) 606 { 607 const char *ofilename = NULL; 608 int retval = -1; 609 char *data = NULL; 610 size_t size = 0; 611 612 dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh); 613 614 retval = cil_userprefixes_to_string(cildb, &data, &size); 615 if (retval != SEPOL_OK) { 616 goto cleanup; 617 } 618 619 if (size > 0) { 620 /* 621 * Write the users_extra entries from CIL modules. 622 * This file is used as our baseline when we do not require 623 * re-linking. 624 */ 625 ofilename = semanage_path(SEMANAGE_TMP, 626 SEMANAGE_USERS_EXTRA_LINKED); 627 if (ofilename == NULL) { 628 retval = -1; 629 goto cleanup; 630 } 631 retval = write_file(sh, ofilename, data, size); 632 if (retval < 0) 633 goto cleanup; 634 635 /* 636 * Write the users_extra file; users_extra.local 637 * will be merged into this file. 638 */ 639 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA); 640 if (ofilename == NULL) { 641 retval = -1; 642 goto cleanup; 643 } 644 retval = write_file(sh, ofilename, data, size); 645 if (retval < 0) 646 goto cleanup; 647 648 pusers_extra->dtable->drop_cache(pusers_extra->dbase); 649 650 } else { 651 retval = pusers_extra->dtable->clear(sh, pusers_extra->dbase); 652 } 653 654 cleanup: 655 free(data); 656 657 return retval; 658 } 659 660 static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb) 661 { 662 const char *ofilename = NULL; 663 int retval = -1; 664 char *data = NULL; 665 size_t size = 0; 666 667 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh); 668 669 retval = cil_selinuxusers_to_string(cildb, &data, &size); 670 if (retval != SEPOL_OK) { 671 goto cleanup; 672 } 673 674 if (size > 0) { 675 /* 676 * Write the seusers entries from CIL modules. 677 * This file is used as our baseline when we do not require 678 * re-linking. 679 */ 680 ofilename = semanage_path(SEMANAGE_TMP, 681 SEMANAGE_SEUSERS_LINKED); 682 if (ofilename == NULL) { 683 retval = -1; 684 goto cleanup; 685 } 686 retval = write_file(sh, ofilename, data, size); 687 if (retval < 0) 688 goto cleanup; 689 690 /* 691 * Write the seusers file; seusers.local will be merged into 692 * this file. 693 */ 694 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 695 if (ofilename == NULL) { 696 retval = -1; 697 goto cleanup; 698 } 699 retval = write_file(sh, ofilename, data, size); 700 if (retval < 0) 701 goto cleanup; 702 703 pseusers->dtable->drop_cache(pseusers->dbase); 704 } else { 705 retval = pseusers->dtable->clear(sh, pseusers->dbase); 706 } 707 708 cleanup: 709 free(data); 710 711 return retval; 712 } 713 714 static int read_from_pipe_to_data(semanage_handle_t *sh, size_t initial_len, int fd, char **out_data_read, size_t *out_read_len) 715 { 716 size_t max_len = initial_len; 717 size_t read_len = 0; 718 size_t data_read_len = 0; 719 char *data_read = NULL; 720 721 if (max_len <= 0) { 722 max_len = 1; 723 } 724 data_read = malloc(max_len * sizeof(*data_read)); 725 if (data_read == NULL) { 726 ERR(sh, "Failed to malloc, out of memory.\n"); 727 return -1; 728 } 729 730 while ((read_len = read(fd, data_read + data_read_len, max_len - data_read_len)) > 0) { 731 data_read_len += read_len; 732 if (data_read_len == max_len) { 733 max_len *= 2; 734 data_read = realloc(data_read, max_len); 735 if (data_read == NULL) { 736 ERR(sh, "Failed to realloc, out of memory.\n"); 737 return -1; 738 } 739 } 740 } 741 742 *out_read_len = data_read_len; 743 *out_data_read = data_read; 744 745 return 0; 746 } 747 748 static int semanage_pipe_data(semanage_handle_t *sh, char *path, char *in_data, size_t in_data_len, char **out_data, size_t *out_data_len, char **err_data, size_t *err_data_len) 749 { 750 int input_fd[2] = {-1, -1}; 751 int output_fd[2] = {-1, -1}; 752 int err_fd[2] = {-1, -1}; 753 pid_t pid; 754 char *data_read = NULL; 755 char *err_data_read = NULL; 756 int retval; 757 int status = 0; 758 size_t initial_len; 759 size_t data_read_len = 0; 760 size_t err_data_read_len = 0; 761 struct sigaction old_signal; 762 struct sigaction new_signal; 763 new_signal.sa_handler = SIG_IGN; 764 sigemptyset(&new_signal.sa_mask); 765 new_signal.sa_flags = 0; 766 /* This is needed in case the read end of input_fd is closed causing a SIGPIPE signal to be sent. 767 * If SIGPIPE is not caught, the signal will cause semanage to terminate immediately. The sigaction below 768 * creates a new_signal that ignores SIGPIPE allowing the write to exit cleanly. 769 * 770 * Another sigaction is called in cleanup to restore the original behavior when a SIGPIPE is received. 771 */ 772 sigaction(SIGPIPE, &new_signal, &old_signal); 773 774 retval = pipe(input_fd); 775 if (retval == -1) { 776 ERR(sh, "Unable to create pipe for input pipe: %s\n", strerror(errno)); 777 goto cleanup; 778 } 779 retval = pipe(output_fd); 780 if (retval == -1) { 781 ERR(sh, "Unable to create pipe for output pipe: %s\n", strerror(errno)); 782 goto cleanup; 783 } 784 retval = pipe(err_fd); 785 if (retval == -1) { 786 ERR(sh, "Unable to create pipe for error pipe: %s\n", strerror(errno)); 787 goto cleanup; 788 } 789 790 pid = fork(); 791 if (pid == -1) { 792 ERR(sh, "Unable to fork from parent: %s.", strerror(errno)); 793 retval = -1; 794 goto cleanup; 795 } else if (pid == 0) { 796 retval = dup2(input_fd[PIPE_READ], STDIN_FILENO); 797 if (retval == -1) { 798 ERR(sh, "Unable to dup2 input pipe: %s\n", strerror(errno)); 799 goto cleanup; 800 } 801 retval = dup2(output_fd[PIPE_WRITE], STDOUT_FILENO); 802 if (retval == -1) { 803 ERR(sh, "Unable to dup2 output pipe: %s\n", strerror(errno)); 804 goto cleanup; 805 } 806 retval = dup2(err_fd[PIPE_WRITE], STDERR_FILENO); 807 if (retval == -1) { 808 ERR(sh, "Unable to dup2 error pipe: %s\n", strerror(errno)); 809 goto cleanup; 810 } 811 812 retval = close(input_fd[PIPE_WRITE]); 813 if (retval == -1) { 814 ERR(sh, "Unable to close input pipe: %s\n", strerror(errno)); 815 goto cleanup; 816 } 817 retval = close(output_fd[PIPE_READ]); 818 if (retval == -1) { 819 ERR(sh, "Unable to close output pipe: %s\n", strerror(errno)); 820 goto cleanup; 821 } 822 retval = close(err_fd[PIPE_READ]); 823 if (retval == -1) { 824 ERR(sh, "Unable to close error pipe: %s\n", strerror(errno)); 825 goto cleanup; 826 } 827 retval = execl(path, path, NULL); 828 if (retval == -1) { 829 ERR(sh, "Unable to execute %s : %s\n", path, strerror(errno)); 830 _exit(EXIT_FAILURE); 831 } 832 } else { 833 retval = close(input_fd[PIPE_READ]); 834 input_fd[PIPE_READ] = -1; 835 if (retval == -1) { 836 ERR(sh, "Unable to close read end of input pipe: %s\n", strerror(errno)); 837 goto cleanup; 838 } 839 840 retval = close(output_fd[PIPE_WRITE]); 841 output_fd[PIPE_WRITE] = -1; 842 if (retval == -1) { 843 ERR(sh, "Unable to close write end of output pipe: %s\n", strerror(errno)); 844 goto cleanup; 845 } 846 847 retval = close(err_fd[PIPE_WRITE]); 848 err_fd[PIPE_WRITE] = -1; 849 if (retval == -1) { 850 ERR(sh, "Unable to close write end of error pipe: %s\n", strerror(errno)); 851 goto cleanup; 852 } 853 854 retval = write(input_fd[PIPE_WRITE], in_data, in_data_len); 855 if (retval == -1) { 856 ERR(sh, "Failed to write data to input pipe: %s\n", strerror(errno)); 857 goto cleanup; 858 } 859 retval = close(input_fd[PIPE_WRITE]); 860 input_fd[PIPE_WRITE] = -1; 861 if (retval == -1) { 862 ERR(sh, "Unable to close write end of input pipe: %s\n", strerror(errno)); 863 goto cleanup; 864 } 865 866 initial_len = 1 << 17; 867 retval = read_from_pipe_to_data(sh, initial_len, output_fd[PIPE_READ], &data_read, &data_read_len); 868 if (retval != 0) { 869 goto cleanup; 870 } 871 retval = close(output_fd[PIPE_READ]); 872 output_fd[PIPE_READ] = -1; 873 if (retval == -1) { 874 ERR(sh, "Unable to close read end of output pipe: %s\n", strerror(errno)); 875 goto cleanup; 876 } 877 878 initial_len = 1 << 9; 879 retval = read_from_pipe_to_data(sh, initial_len, err_fd[PIPE_READ], &err_data_read, &err_data_read_len); 880 if (retval != 0) { 881 goto cleanup; 882 } 883 retval = close(err_fd[PIPE_READ]); 884 err_fd[PIPE_READ] = -1; 885 if (retval == -1) { 886 ERR(sh, "Unable to close read end of error pipe: %s\n", strerror(errno)); 887 goto cleanup; 888 } 889 890 if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status)) { 891 ERR(sh, "Child process %s did not exit cleanly.", path); 892 retval = -1; 893 goto cleanup; 894 } 895 if (WEXITSTATUS(status) != 0) { 896 ERR(sh, "Child process %s failed with code: %d.", path, WEXITSTATUS(status)); 897 retval = -1; 898 goto cleanup; 899 } 900 } 901 902 retval = 0; 903 904 cleanup: 905 sigaction(SIGPIPE, &old_signal, NULL); 906 907 if (data_read != NULL) { 908 *out_data = data_read; 909 *out_data_len = data_read_len; 910 } 911 912 if (err_data_read != NULL) { 913 *err_data = err_data_read; 914 *err_data_len = err_data_read_len; 915 } 916 917 if (output_fd[PIPE_READ] != -1) { 918 close(output_fd[PIPE_READ]); 919 } 920 if (output_fd[PIPE_WRITE] != -1) { 921 close(output_fd[PIPE_WRITE]); 922 } 923 if (err_fd[PIPE_READ] != -1) { 924 close(err_fd[PIPE_READ]); 925 } 926 if (err_fd[PIPE_WRITE] != -1) { 927 close(err_fd[PIPE_WRITE]); 928 } 929 if (input_fd[PIPE_READ] != -1) { 930 close(input_fd[PIPE_READ]); 931 } 932 if (input_fd[PIPE_WRITE] != -1) { 933 close(input_fd[PIPE_WRITE]); 934 } 935 936 return retval; 937 } 938 939 static int semanage_direct_write_langext(semanage_handle_t *sh, 940 const char *lang_ext, 941 const semanage_module_info_t *modinfo) 942 { 943 int ret = -1; 944 char fn[PATH_MAX]; 945 FILE *fp = NULL; 946 947 ret = semanage_module_get_path(sh, 948 modinfo, 949 SEMANAGE_MODULE_PATH_LANG_EXT, 950 fn, 951 sizeof(fn)); 952 if (ret != 0) { 953 goto cleanup; 954 } 955 956 fp = fopen(fn, "w"); 957 if (fp == NULL) { 958 ERR(sh, "Unable to open %s module ext file.", modinfo->name); 959 ret = -1; 960 goto cleanup; 961 } 962 963 if (fputs(lang_ext, fp) < 0) { 964 ERR(sh, "Unable to write %s module ext file.", modinfo->name); 965 ret = -1; 966 goto cleanup; 967 } 968 969 if (fclose(fp) != 0) { 970 ERR(sh, "Unable to close %s module ext file.", modinfo->name); 971 ret = -1; 972 goto cleanup; 973 } 974 975 fp = NULL; 976 977 ret = 0; 978 979 cleanup: 980 if (fp != NULL) fclose(fp); 981 982 return ret; 983 } 984 985 static int semanage_compile_module(semanage_handle_t *sh, 986 semanage_module_info_t *modinfo) 987 { 988 char cil_path[PATH_MAX]; 989 char hll_path[PATH_MAX]; 990 char *compiler_path = NULL; 991 char *cil_data = NULL; 992 char *err_data = NULL; 993 char *hll_data = NULL; 994 char *start = NULL; 995 char *end = NULL; 996 ssize_t hll_data_len = 0; 997 ssize_t bzip_status; 998 int status = 0; 999 int compressed; 1000 size_t cil_data_len = 0; 1001 size_t err_data_len = 0; 1002 1003 if (!strcasecmp(modinfo->lang_ext, "cil")) { 1004 goto cleanup; 1005 } 1006 1007 status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path); 1008 if (status != 0) { 1009 goto cleanup; 1010 } 1011 1012 status = semanage_module_get_path( 1013 sh, 1014 modinfo, 1015 SEMANAGE_MODULE_PATH_CIL, 1016 cil_path, 1017 sizeof(cil_path)); 1018 if (status != 0) { 1019 goto cleanup; 1020 } 1021 1022 status = semanage_module_get_path( 1023 sh, 1024 modinfo, 1025 SEMANAGE_MODULE_PATH_HLL, 1026 hll_path, 1027 sizeof(hll_path)); 1028 if (status != 0) { 1029 goto cleanup; 1030 } 1031 1032 if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) { 1033 ERR(sh, "Unable to read file %s\n", hll_path); 1034 status = -1; 1035 goto cleanup; 1036 } 1037 1038 status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len); 1039 if (err_data_len > 0) { 1040 for (start = end = err_data; end < err_data + err_data_len; end++) { 1041 if (*end == '\n') { 1042 fprintf(stderr, "%s: ", modinfo->name); 1043 fwrite(start, 1, end - start + 1, stderr); 1044 start = end + 1; 1045 } 1046 } 1047 1048 if (end != start) { 1049 fprintf(stderr, "%s: ", modinfo->name); 1050 fwrite(start, 1, end - start, stderr); 1051 fprintf(stderr, "\n"); 1052 } 1053 } 1054 if (status != 0) { 1055 goto cleanup; 1056 } 1057 1058 bzip_status = bzip(sh, cil_path, cil_data, cil_data_len); 1059 if (bzip_status == -1) { 1060 ERR(sh, "Failed to bzip %s\n", cil_path); 1061 status = -1; 1062 goto cleanup; 1063 } 1064 1065 if (sh->conf->remove_hll == 1) { 1066 status = unlink(hll_path); 1067 if (status != 0) { 1068 ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno)); 1069 goto cleanup; 1070 } 1071 1072 status = semanage_direct_write_langext(sh, "cil", modinfo); 1073 if (status != 0) { 1074 goto cleanup; 1075 } 1076 } 1077 1078 cleanup: 1079 if (hll_data_len > 0) { 1080 munmap(hll_data, hll_data_len); 1081 } 1082 free(cil_data); 1083 free(err_data); 1084 free(compiler_path); 1085 1086 return status; 1087 } 1088 1089 static int semanage_compile_hll_modules(semanage_handle_t *sh, 1090 semanage_module_info_t *modinfos, 1091 int num_modinfos) 1092 { 1093 int status = 0; 1094 int i; 1095 char cil_path[PATH_MAX]; 1096 1097 assert(sh); 1098 assert(modinfos); 1099 1100 for (i = 0; i < num_modinfos; i++) { 1101 status = semanage_module_get_path( 1102 sh, 1103 &modinfos[i], 1104 SEMANAGE_MODULE_PATH_CIL, 1105 cil_path, 1106 sizeof(cil_path)); 1107 if (status != 0) { 1108 goto cleanup; 1109 } 1110 1111 if (semanage_get_ignore_module_cache(sh) == 0 && 1112 access(cil_path, F_OK) == 0) { 1113 continue; 1114 } 1115 1116 status = semanage_compile_module(sh, &modinfos[i]); 1117 if (status < 0) { 1118 goto cleanup; 1119 } 1120 } 1121 1122 status = 0; 1123 1124 cleanup: 1125 return status; 1126 } 1127 1128 /********************* direct API functions ********************/ 1129 1130 /* Commits all changes in sandbox to the actual kernel policy. 1131 * Returns commit number on success, -1 on error. 1132 */ 1133 static int semanage_direct_commit(semanage_handle_t * sh) 1134 { 1135 char **mod_filenames = NULL; 1136 char *fc_buffer = NULL; 1137 size_t fc_buffer_len = 0; 1138 const char *ofilename = NULL; 1139 const char *path; 1140 int retval = -1, num_modinfos = 0, i; 1141 sepol_policydb_t *out = NULL; 1142 struct cil_db *cildb = NULL; 1143 semanage_module_info_t *modinfos = NULL; 1144 1145 int do_rebuild, do_write_kernel, do_install; 1146 int fcontexts_modified, ports_modified, seusers_modified, 1147 disable_dontaudit, preserve_tunables; 1148 dbase_config_t *users = semanage_user_dbase_local(sh); 1149 dbase_config_t *users_base = semanage_user_base_dbase_local(sh); 1150 dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh); 1151 dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh); 1152 dbase_config_t *ports = semanage_port_dbase_local(sh); 1153 dbase_config_t *pports = semanage_port_dbase_policy(sh); 1154 dbase_config_t *bools = semanage_bool_dbase_local(sh); 1155 dbase_config_t *pbools = semanage_bool_dbase_policy(sh); 1156 dbase_config_t *ifaces = semanage_iface_dbase_local(sh); 1157 dbase_config_t *pifaces = semanage_iface_dbase_policy(sh); 1158 dbase_config_t *nodes = semanage_node_dbase_local(sh); 1159 dbase_config_t *pnodes = semanage_node_dbase_policy(sh); 1160 dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh); 1161 dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh); 1162 dbase_config_t *seusers = semanage_seuser_dbase_local(sh); 1163 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh); 1164 1165 /* Modified flags that we need to use more than once. */ 1166 ports_modified = ports->dtable->is_modified(ports->dbase); 1167 seusers_modified = seusers->dtable->is_modified(seusers->dbase); 1168 fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase); 1169 1170 /* Rebuild if explicitly requested or any module changes occurred. */ 1171 do_rebuild = sh->do_rebuild | sh->modules_modified; 1172 1173 /* Create or remove the disable_dontaudit flag file. */ 1174 path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT); 1175 if (access(path, F_OK) == 0) 1176 do_rebuild |= !(sepol_get_disable_dontaudit(sh->sepolh) == 1); 1177 else 1178 do_rebuild |= (sepol_get_disable_dontaudit(sh->sepolh) == 1); 1179 if (sepol_get_disable_dontaudit(sh->sepolh) == 1) { 1180 FILE *touch; 1181 touch = fopen(path, "w"); 1182 if (touch != NULL) { 1183 if (fclose(touch) != 0) { 1184 ERR(sh, "Error attempting to create disable_dontaudit flag."); 1185 goto cleanup; 1186 } 1187 } else { 1188 ERR(sh, "Error attempting to create disable_dontaudit flag."); 1189 goto cleanup; 1190 } 1191 } else { 1192 if (remove(path) == -1 && errno != ENOENT) { 1193 ERR(sh, "Error removing the disable_dontaudit flag."); 1194 goto cleanup; 1195 } 1196 } 1197 1198 /* Create or remove the preserve_tunables flag file. */ 1199 path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES); 1200 if (access(path, F_OK) == 0) 1201 do_rebuild |= !(sepol_get_preserve_tunables(sh->sepolh) == 1); 1202 else 1203 do_rebuild |= (sepol_get_preserve_tunables(sh->sepolh) == 1); 1204 if (sepol_get_preserve_tunables(sh->sepolh) == 1) { 1205 FILE *touch; 1206 touch = fopen(path, "w"); 1207 if (touch != NULL) { 1208 if (fclose(touch) != 0) { 1209 ERR(sh, "Error attempting to create preserve_tunable flag."); 1210 goto cleanup; 1211 } 1212 } else { 1213 ERR(sh, "Error attempting to create preserve_tunable flag."); 1214 goto cleanup; 1215 } 1216 } else { 1217 if (remove(path) == -1 && errno != ENOENT) { 1218 ERR(sh, "Error removing the preserve_tunables flag."); 1219 goto cleanup; 1220 } 1221 } 1222 1223 /* Before we do anything else, flush the join to its component parts. 1224 * This *does not* flush to disk automatically */ 1225 if (users->dtable->is_modified(users->dbase)) { 1226 retval = users->dtable->flush(sh, users->dbase); 1227 if (retval < 0) 1228 goto cleanup; 1229 } 1230 1231 /* 1232 * This is for systems that have already migrated with an older version 1233 * of semanage_migrate_store. The older version did not copy 1234 * policy.kern so the policy binary must be rebuilt here. 1235 * This also ensures that any linked files that are required 1236 * in order to skip re-linking are present; otherwise, we force 1237 * a rebuild. 1238 */ 1239 if (!do_rebuild) { 1240 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL); 1241 if (access(path, F_OK) != 0) { 1242 do_rebuild = 1; 1243 goto rebuild; 1244 } 1245 1246 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); 1247 if (access(path, F_OK) != 0) { 1248 do_rebuild = 1; 1249 goto rebuild; 1250 } 1251 1252 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 1253 if (access(path, F_OK) != 0) { 1254 do_rebuild = 1; 1255 goto rebuild; 1256 } 1257 1258 path = semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED); 1259 if (access(path, F_OK) != 0) { 1260 do_rebuild = 1; 1261 goto rebuild; 1262 } 1263 1264 path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED); 1265 if (access(path, F_OK) != 0) { 1266 do_rebuild = 1; 1267 goto rebuild; 1268 } 1269 1270 path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED); 1271 if (access(path, F_OK) != 0) { 1272 do_rebuild = 1; 1273 goto rebuild; 1274 } 1275 } 1276 1277 rebuild: 1278 /* 1279 * Now that we know whether or not a rebuild is required, 1280 * we can determine what else needs to be done. 1281 * We need to write the kernel policy if we are rebuilding 1282 * or if any other policy component that lives in the kernel 1283 * policy has been modified. 1284 * We need to install the policy files if any of the managed files 1285 * that live under /etc/selinux (kernel policy, seusers, file contexts) 1286 * will be modified. 1287 */ 1288 do_write_kernel = do_rebuild | ports_modified | 1289 bools->dtable->is_modified(bools->dbase) | 1290 ifaces->dtable->is_modified(ifaces->dbase) | 1291 nodes->dtable->is_modified(nodes->dbase) | 1292 users->dtable->is_modified(users_base->dbase); 1293 do_install = do_write_kernel | seusers_modified | fcontexts_modified; 1294 1295 /* 1296 * If there were policy changes, or explicitly requested, or 1297 * any required files are missing, rebuild the policy. 1298 */ 1299 if (do_rebuild) { 1300 /* =================== Module expansion =============== */ 1301 1302 retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos); 1303 if (retval < 0) { 1304 goto cleanup; 1305 } 1306 1307 if (num_modinfos == 0) { 1308 goto cleanup; 1309 } 1310 1311 retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos); 1312 if (retval < 0) { 1313 ERR(sh, "Failed to compile hll files into cil files.\n"); 1314 goto cleanup; 1315 } 1316 1317 retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames); 1318 if (retval < 0) 1319 goto cleanup; 1320 1321 retval = semanage_verify_modules(sh, mod_filenames, num_modinfos); 1322 if (retval < 0) 1323 goto cleanup; 1324 1325 cil_db_init(&cildb); 1326 1327 disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh); 1328 preserve_tunables = sepol_get_preserve_tunables(sh->sepolh); 1329 cil_set_disable_dontaudit(cildb, disable_dontaudit); 1330 cil_set_disable_neverallow(cildb, !(sh->conf->expand_check)); 1331 cil_set_preserve_tunables(cildb, preserve_tunables); 1332 cil_set_target_platform(cildb, sh->conf->target_platform); 1333 cil_set_policy_version(cildb, sh->conf->policyvers); 1334 1335 if (sh->conf->handle_unknown != -1) { 1336 cil_set_handle_unknown(cildb, sh->conf->handle_unknown); 1337 } 1338 1339 retval = semanage_load_files(sh, cildb, mod_filenames, num_modinfos); 1340 if (retval < 0) { 1341 goto cleanup; 1342 } 1343 1344 retval = cil_compile(cildb); 1345 if (retval < 0) 1346 goto cleanup; 1347 1348 retval = cil_build_policydb(cildb, &out); 1349 if (retval < 0) 1350 goto cleanup; 1351 1352 /* File Contexts */ 1353 retval = cil_filecons_to_string(cildb, &fc_buffer, &fc_buffer_len); 1354 if (retval < 0) 1355 goto cleanup; 1356 1357 /* Write the contexts (including template contexts) to a single file. */ 1358 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL); 1359 if (ofilename == NULL) { 1360 retval = -1; 1361 goto cleanup; 1362 } 1363 retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len); 1364 if (retval < 0) 1365 goto cleanup; 1366 1367 /* Split complete and template file contexts into their separate files. */ 1368 retval = semanage_split_fc(sh); 1369 if (retval < 0) 1370 goto cleanup; 1371 1372 /* remove FC_TMPL now that it is now longer needed */ 1373 unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL)); 1374 1375 pfcontexts->dtable->drop_cache(pfcontexts->dbase); 1376 1377 /* SEUsers */ 1378 retval = semanage_direct_update_seuser(sh, cildb); 1379 if (retval < 0) 1380 goto cleanup; 1381 1382 /* User Extra */ 1383 retval = semanage_direct_update_user_extra(sh, cildb); 1384 if (retval < 0) 1385 goto cleanup; 1386 1387 cil_db_destroy(&cildb); 1388 1389 /* Write the linked policy before merging local changes. */ 1390 retval = semanage_write_policydb(sh, out, 1391 SEMANAGE_LINKED); 1392 if (retval < 0) 1393 goto cleanup; 1394 } else { 1395 /* Load the existing linked policy, w/o local changes */ 1396 retval = sepol_policydb_create(&out); 1397 if (retval < 0) 1398 goto cleanup; 1399 1400 retval = semanage_read_policydb(sh, out, SEMANAGE_LINKED); 1401 if (retval < 0) 1402 goto cleanup; 1403 1404 path = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS_LINKED); 1405 if (access(path, F_OK) == 0) { 1406 retval = semanage_copy_file(path, 1407 semanage_path(SEMANAGE_TMP, 1408 SEMANAGE_STORE_SEUSERS), 1409 sh->conf->file_mode); 1410 if (retval < 0) 1411 goto cleanup; 1412 pseusers->dtable->drop_cache(pseusers->dbase); 1413 } else { 1414 pseusers->dtable->clear(sh, pseusers->dbase); 1415 } 1416 1417 path = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA_LINKED); 1418 if (access(path, F_OK) == 0) { 1419 retval = semanage_copy_file(path, 1420 semanage_path(SEMANAGE_TMP, 1421 SEMANAGE_USERS_EXTRA), 1422 sh->conf->file_mode); 1423 if (retval < 0) 1424 goto cleanup; 1425 pusers_extra->dtable->drop_cache(pusers_extra->dbase); 1426 } else { 1427 pusers_extra->dtable->clear(sh, pusers_extra->dbase); 1428 } 1429 } 1430 1431 /* Attach our databases to the policydb we just created or loaded. */ 1432 dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out); 1433 dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out); 1434 dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out); 1435 dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out); 1436 dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out); 1437 1438 /* Merge local changes */ 1439 retval = semanage_base_merge_components(sh); 1440 if (retval < 0) 1441 goto cleanup; 1442 1443 if (do_write_kernel) { 1444 /* Write new kernel policy. */ 1445 retval = semanage_write_policydb(sh, out, 1446 SEMANAGE_STORE_KERNEL); 1447 if (retval < 0) 1448 goto cleanup; 1449 1450 /* Run the kernel policy verifier, if any. */ 1451 retval = semanage_verify_kernel(sh); 1452 if (retval < 0) 1453 goto cleanup; 1454 } 1455 1456 /* ======= Post-process: Validate non-policydb components ===== */ 1457 1458 /* Validate local modifications to file contexts. 1459 * Note: those are still cached, even though they've been 1460 * merged into the main file_contexts. We won't check the 1461 * large file_contexts - checked at compile time */ 1462 if (do_rebuild || fcontexts_modified) { 1463 retval = semanage_fcontext_validate_local(sh, out); 1464 if (retval < 0) 1465 goto cleanup; 1466 } 1467 1468 /* Validate local seusers against policy */ 1469 if (do_rebuild || seusers_modified) { 1470 retval = semanage_seuser_validate_local(sh, out); 1471 if (retval < 0) 1472 goto cleanup; 1473 } 1474 1475 /* Validate local ports for overlap */ 1476 if (do_rebuild || ports_modified) { 1477 retval = semanage_port_validate_local(sh); 1478 if (retval < 0) 1479 goto cleanup; 1480 } 1481 1482 /* ================== Write non-policydb components ========= */ 1483 1484 /* Commit changes to components */ 1485 retval = semanage_commit_components(sh); 1486 if (retval < 0) 1487 goto cleanup; 1488 1489 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), 1490 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL), 1491 sh->conf->file_mode); 1492 if (retval < 0) { 1493 goto cleanup; 1494 } 1495 1496 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL); 1497 if (access(path, F_OK) == 0) { 1498 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL), 1499 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL), 1500 sh->conf->file_mode); 1501 if (retval < 0) { 1502 goto cleanup; 1503 } 1504 } 1505 1506 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); 1507 if (access(path, F_OK) == 0) { 1508 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), 1509 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC), 1510 sh->conf->file_mode); 1511 if (retval < 0) { 1512 goto cleanup; 1513 } 1514 } 1515 1516 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 1517 if (access(path, F_OK) == 0) { 1518 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS), 1519 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS), 1520 sh->conf->file_mode); 1521 if (retval < 0) { 1522 goto cleanup; 1523 } 1524 } 1525 1526 /* run genhomedircon if its enabled, this should be the last operation 1527 * which requires the out policydb */ 1528 if (!sh->conf->disable_genhomedircon) { 1529 if (out && (retval = 1530 semanage_genhomedircon(sh, out, sh->conf->usepasswd, sh->conf->ignoredirs)) != 0) { 1531 ERR(sh, "semanage_genhomedircon returned error code %d.", 1532 retval); 1533 goto cleanup; 1534 } 1535 } else { 1536 WARN(sh, "WARNING: genhomedircon is disabled. \ 1537 See /etc/selinux/semanage.conf if you need to enable it."); 1538 } 1539 1540 /* free out, if we don't free it before calling semanage_install_sandbox 1541 * then fork() may fail on low memory machines */ 1542 sepol_policydb_free(out); 1543 out = NULL; 1544 1545 if (do_install) 1546 retval = semanage_install_sandbox(sh); 1547 1548 cleanup: 1549 for (i = 0; i < num_modinfos; i++) { 1550 semanage_module_info_destroy(sh, &modinfos[i]); 1551 } 1552 free(modinfos); 1553 1554 for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) { 1555 free(mod_filenames[i]); 1556 } 1557 1558 /* Detach from policydb, so it can be freed */ 1559 dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase); 1560 dbase_policydb_detach((dbase_policydb_t *) pports->dbase); 1561 dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase); 1562 dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase); 1563 dbase_policydb_detach((dbase_policydb_t *) pbools->dbase); 1564 1565 free(mod_filenames); 1566 sepol_policydb_free(out); 1567 cil_db_destroy(&cildb); 1568 semanage_release_trans_lock(sh); 1569 1570 free(fc_buffer); 1571 1572 /* regardless if the commit was successful or not, remove the 1573 sandbox if it is still there */ 1574 semanage_remove_directory(semanage_path 1575 (SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); 1576 semanage_remove_directory(semanage_final_path 1577 (SEMANAGE_FINAL_TMP, 1578 SEMANAGE_FINAL_TOPLEVEL)); 1579 return retval; 1580 } 1581 1582 /* Writes a module to the sandbox's module directory, overwriting any 1583 * previous module stored within. Note that module data are not 1584 * free()d by this function; caller is responsible for deallocating it 1585 * if necessary. Returns 0 on success, -1 if out of memory, -2 if the 1586 * data does not represent a valid module file, -3 if error while 1587 * writing file. */ 1588 static int semanage_direct_install(semanage_handle_t * sh, 1589 char *data, size_t data_len, 1590 const char *module_name, const char *lang_ext) 1591 { 1592 int status = 0; 1593 int ret = 0; 1594 1595 semanage_module_info_t modinfo; 1596 ret = semanage_module_info_init(sh, &modinfo); 1597 if (ret != 0) { 1598 status = -1; 1599 goto cleanup; 1600 } 1601 1602 ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority); 1603 if (ret != 0) { 1604 status = -1; 1605 goto cleanup; 1606 } 1607 1608 ret = semanage_module_info_set_name(sh, &modinfo, module_name); 1609 if (ret != 0) { 1610 status = -1; 1611 goto cleanup; 1612 } 1613 1614 ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext); 1615 if (ret != 0) { 1616 status = -1; 1617 goto cleanup; 1618 } 1619 1620 ret = semanage_module_info_set_enabled(sh, &modinfo, -1); 1621 if (ret != 0) { 1622 status = -1; 1623 goto cleanup; 1624 } 1625 1626 status = semanage_direct_install_info(sh, &modinfo, data, data_len); 1627 1628 cleanup: 1629 1630 semanage_module_info_destroy(sh, &modinfo); 1631 1632 return status; 1633 } 1634 1635 /* Attempts to link a module to the sandbox's module directory, unlinking any 1636 * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the 1637 * data does not represent a valid module file, -3 if error while 1638 * writing file. */ 1639 1640 static int semanage_direct_install_file(semanage_handle_t * sh, 1641 const char *install_filename) 1642 { 1643 1644 int retval = -1; 1645 char *data = NULL; 1646 ssize_t data_len = 0; 1647 int compressed = 0; 1648 char *path = NULL; 1649 char *filename; 1650 char *lang_ext = NULL; 1651 char *module_name = NULL; 1652 char *separator; 1653 char *version = NULL; 1654 1655 if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) { 1656 ERR(sh, "Unable to read file %s\n", install_filename); 1657 retval = -1; 1658 goto cleanup; 1659 } 1660 1661 path = strdup(install_filename); 1662 if (path == NULL) { 1663 ERR(sh, "No memory available for strdup.\n"); 1664 retval = -1; 1665 goto cleanup; 1666 } 1667 1668 filename = basename(path); 1669 1670 if (compressed) { 1671 separator = strrchr(filename, '.'); 1672 if (separator == NULL) { 1673 ERR(sh, "Compressed module does not have a valid extension."); 1674 retval = -1; 1675 goto cleanup; 1676 } 1677 *separator = '\0'; 1678 lang_ext = separator + 1; 1679 } 1680 1681 separator = strrchr(filename, '.'); 1682 if (separator == NULL) { 1683 if (lang_ext == NULL) { 1684 ERR(sh, "Module does not have a valid extension."); 1685 retval = -1; 1686 goto cleanup; 1687 } 1688 } else { 1689 *separator = '\0'; 1690 lang_ext = separator + 1; 1691 } 1692 1693 if (strcmp(lang_ext, "pp") == 0) { 1694 retval = parse_module_headers(sh, data, data_len, &module_name, &version); 1695 free(version); 1696 if (retval != 0) 1697 goto cleanup; 1698 } 1699 1700 if (module_name == NULL) { 1701 module_name = strdup(filename); 1702 if (module_name == NULL) { 1703 ERR(sh, "No memory available for module_name.\n"); 1704 retval = -1; 1705 goto cleanup; 1706 } 1707 } else if (strcmp(module_name, filename) != 0) { 1708 fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename); 1709 } 1710 1711 retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext); 1712 1713 cleanup: 1714 if (data_len > 0) munmap(data, data_len); 1715 free(module_name); 1716 free(path); 1717 1718 return retval; 1719 } 1720 1721 static int semanage_direct_extract(semanage_handle_t * sh, 1722 semanage_module_key_t *modkey, 1723 int extract_cil, 1724 void **mapped_data, 1725 size_t *data_len, 1726 semanage_module_info_t **modinfo) 1727 { 1728 char module_path[PATH_MAX]; 1729 char input_file[PATH_MAX]; 1730 enum semanage_module_path_type file_type; 1731 int rc = -1; 1732 semanage_module_info_t *_modinfo = NULL; 1733 ssize_t _data_len; 1734 char *_data; 1735 int compressed; 1736 1737 /* get path of module */ 1738 rc = semanage_module_get_path( 1739 sh, 1740 (const semanage_module_info_t *)modkey, 1741 SEMANAGE_MODULE_PATH_NAME, 1742 module_path, 1743 sizeof(module_path)); 1744 if (rc != 0) { 1745 goto cleanup; 1746 } 1747 1748 if (access(module_path, F_OK) != 0) { 1749 ERR(sh, "Module does not exist: %s", module_path); 1750 rc = -1; 1751 goto cleanup; 1752 } 1753 1754 rc = semanage_module_get_module_info(sh, 1755 modkey, 1756 &_modinfo); 1757 if (rc != 0) { 1758 goto cleanup; 1759 } 1760 1761 if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) { 1762 file_type = SEMANAGE_MODULE_PATH_CIL; 1763 } else { 1764 file_type = SEMANAGE_MODULE_PATH_HLL; 1765 } 1766 1767 /* get path of what to extract */ 1768 rc = semanage_module_get_path( 1769 sh, 1770 _modinfo, 1771 file_type, 1772 input_file, 1773 sizeof(input_file)); 1774 if (rc != 0) { 1775 goto cleanup; 1776 } 1777 1778 if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && access(input_file, F_OK) != 0) { 1779 rc = semanage_compile_module(sh, _modinfo); 1780 if (rc < 0) { 1781 goto cleanup; 1782 } 1783 } 1784 1785 _data_len = map_file(sh, input_file, &_data, &compressed); 1786 if (_data_len <= 0) { 1787 ERR(sh, "Error mapping file: %s", input_file); 1788 rc = -1; 1789 goto cleanup; 1790 } 1791 1792 *modinfo = _modinfo; 1793 *data_len = (size_t)_data_len; 1794 *mapped_data = _data; 1795 1796 cleanup: 1797 if (rc != 0) { 1798 semanage_module_info_destroy(sh, _modinfo); 1799 free(_modinfo); 1800 } 1801 1802 return rc; 1803 } 1804 1805 /* Removes a module from the sandbox. Returns 0 on success, -1 if out 1806 * of memory, -2 if module not found or could not be removed. */ 1807 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name) 1808 { 1809 int status = 0; 1810 int ret = 0; 1811 1812 semanage_module_key_t modkey; 1813 ret = semanage_module_key_init(sh, &modkey); 1814 if (ret != 0) { 1815 status = -1; 1816 goto cleanup; 1817 } 1818 1819 ret = semanage_module_key_set_priority(sh, &modkey, sh->priority); 1820 if (ret != 0) { 1821 status = -1; 1822 goto cleanup; 1823 } 1824 1825 ret = semanage_module_key_set_name(sh, &modkey, module_name); 1826 if (ret != 0) { 1827 status = -1; 1828 goto cleanup; 1829 } 1830 1831 status = semanage_direct_remove_key(sh, &modkey); 1832 1833 cleanup: 1834 return status; 1835 } 1836 1837 /* Allocate an array of module_info structures for each readable 1838 * module within the store. Note that if the calling program has 1839 * already begun a transaction then this function will get a list of 1840 * modules within the sandbox. The caller is responsible for calling 1841 * semanage_module_info_datum_destroy() on each element of the array 1842 * as well as free()ing the entire list. 1843 */ 1844 static int semanage_direct_list(semanage_handle_t * sh, 1845 semanage_module_info_t ** modinfo, 1846 int *num_modules) 1847 { 1848 int i, retval = -1; 1849 *modinfo = NULL; 1850 *num_modules = 0; 1851 1852 /* get the read lock when reading from the active 1853 (non-transaction) directory */ 1854 if (!sh->is_in_transaction) 1855 if (semanage_get_active_lock(sh) < 0) 1856 return -1; 1857 1858 if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) { 1859 goto cleanup; 1860 } 1861 1862 if (num_modules == 0) { 1863 retval = semanage_direct_get_serial(sh); 1864 goto cleanup; 1865 } 1866 1867 retval = semanage_direct_get_serial(sh); 1868 1869 cleanup: 1870 if (retval < 0) { 1871 for (i = 0; i < *num_modules; i++) { 1872 semanage_module_info_destroy(sh, &(*modinfo[i])); 1873 modinfo[i] = NULL; 1874 } 1875 free(*modinfo); 1876 *modinfo = NULL; 1877 } 1878 1879 if (!sh->is_in_transaction) { 1880 semanage_release_active_lock(sh); 1881 } 1882 return retval; 1883 } 1884 1885 static int semanage_direct_get_enabled(semanage_handle_t *sh, 1886 const semanage_module_key_t *modkey, 1887 int *enabled) 1888 { 1889 assert(sh); 1890 assert(modkey); 1891 assert(enabled); 1892 1893 int status = 0; 1894 int ret = 0; 1895 1896 char path[PATH_MAX]; 1897 struct stat sb; 1898 semanage_module_info_t *modinfo = NULL; 1899 1900 /* get module info */ 1901 ret = semanage_module_get_module_info( 1902 sh, 1903 modkey, 1904 &modinfo); 1905 if (ret != 0) { 1906 status = -1; 1907 goto cleanup; 1908 } 1909 1910 /* get disabled file path */ 1911 ret = semanage_module_get_path( 1912 sh, 1913 modinfo, 1914 SEMANAGE_MODULE_PATH_DISABLED, 1915 path, 1916 sizeof(path)); 1917 if (ret != 0) { 1918 status = -1; 1919 goto cleanup; 1920 } 1921 1922 if (stat(path, &sb) < 0) { 1923 *enabled = 1; 1924 } 1925 else { 1926 *enabled = 0; 1927 } 1928 1929 cleanup: 1930 semanage_module_info_destroy(sh, modinfo); 1931 free(modinfo); 1932 1933 return status; 1934 } 1935 1936 static int semanage_direct_set_enabled(semanage_handle_t *sh, 1937 const semanage_module_key_t *modkey, 1938 int enabled) 1939 { 1940 assert(sh); 1941 assert(modkey); 1942 1943 int status = 0; 1944 int ret = 0; 1945 1946 char fn[PATH_MAX]; 1947 const char *path = NULL; 1948 FILE *fp = NULL; 1949 semanage_module_info_t *modinfo = NULL; 1950 1951 /* check transaction */ 1952 if (!sh->is_in_transaction) { 1953 if (semanage_begin_transaction(sh) < 0) { 1954 status = -1; 1955 goto cleanup; 1956 } 1957 } 1958 1959 /* validate name */ 1960 ret = semanage_module_validate_name(modkey->name); 1961 if (ret != 0) { 1962 errno = 0; 1963 ERR(sh, "Name %s is invalid.", modkey->name); 1964 status = -1; 1965 goto cleanup; 1966 } 1967 1968 /* validate enabled */ 1969 ret = semanage_module_validate_enabled(enabled); 1970 if (ret != 0) { 1971 errno = 0; 1972 ERR(sh, "Enabled status %d is invalid.", enabled); 1973 status = -1; 1974 goto cleanup; 1975 } 1976 1977 /* check for disabled path, create if missing */ 1978 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); 1979 1980 ret = semanage_mkdir(sh, path); 1981 if (ret != 0) { 1982 status = -1; 1983 goto cleanup; 1984 } 1985 1986 /* get module info */ 1987 ret = semanage_module_get_module_info( 1988 sh, 1989 modkey, 1990 &modinfo); 1991 if (ret != 0) { 1992 status = -1; 1993 goto cleanup; 1994 } 1995 1996 /* get module disabled file */ 1997 ret = semanage_module_get_path( 1998 sh, 1999 modinfo, 2000 SEMANAGE_MODULE_PATH_DISABLED, 2001 fn, 2002 sizeof(fn)); 2003 if (ret != 0) { 2004 status = -1; 2005 goto cleanup; 2006 } 2007 2008 switch (enabled) { 2009 case 0: /* disable the module */ 2010 fp = fopen(fn, "w"); 2011 2012 if (fp == NULL) { 2013 ERR(sh, 2014 "Unable to disable module %s", 2015 modkey->name); 2016 status = -1; 2017 goto cleanup; 2018 } 2019 2020 if (fclose(fp) != 0) { 2021 ERR(sh, 2022 "Unable to close disabled file for module %s", 2023 modkey->name); 2024 status = -1; 2025 goto cleanup; 2026 } 2027 2028 fp = NULL; 2029 2030 break; 2031 case 1: /* enable the module */ 2032 if (unlink(fn) < 0) { 2033 if (errno != ENOENT) { 2034 ERR(sh, 2035 "Unable to enable module %s", 2036 modkey->name); 2037 status = -1; 2038 goto cleanup; 2039 } 2040 else { 2041 /* module already enabled */ 2042 errno = 0; 2043 } 2044 } 2045 2046 break; 2047 case -1: /* warn about ignored setting to default */ 2048 WARN(sh, 2049 "Setting module %s to 'default' state has no effect", 2050 modkey->name); 2051 break; 2052 } 2053 2054 cleanup: 2055 semanage_module_info_destroy(sh, modinfo); 2056 free(modinfo); 2057 2058 if (fp != NULL) fclose(fp); 2059 return status; 2060 } 2061 2062 int semanage_direct_access_check(semanage_handle_t * sh) 2063 { 2064 if (semanage_check_init(sh, sh->conf->store_root_path)) 2065 return -1; 2066 2067 return semanage_store_access_check(); 2068 } 2069 2070 int semanage_direct_mls_enabled(semanage_handle_t * sh) 2071 { 2072 sepol_policydb_t *p = NULL; 2073 int retval; 2074 2075 retval = sepol_policydb_create(&p); 2076 if (retval < 0) 2077 goto cleanup; 2078 2079 retval = semanage_read_policydb(sh, p, SEMANAGE_STORE_KERNEL); 2080 if (retval < 0) 2081 goto cleanup; 2082 2083 retval = sepol_policydb_mls_enabled(p); 2084 cleanup: 2085 sepol_policydb_free(p); 2086 return retval; 2087 } 2088 2089 static int semanage_direct_get_module_info(semanage_handle_t *sh, 2090 const semanage_module_key_t *modkey, 2091 semanage_module_info_t **modinfo) 2092 { 2093 assert(sh); 2094 assert(modkey); 2095 assert(modinfo); 2096 2097 int status = 0; 2098 int ret = 0; 2099 2100 char fn[PATH_MAX]; 2101 FILE *fp = NULL; 2102 size_t size = 0; 2103 struct stat sb; 2104 char *tmp = NULL; 2105 2106 int i = 0; 2107 2108 semanage_module_info_t *modinfos = NULL; 2109 int modinfos_len = 0; 2110 semanage_module_info_t *highest = NULL; 2111 2112 /* check module name */ 2113 ret = semanage_module_validate_name(modkey->name); 2114 if (ret < 0) { 2115 errno = 0; 2116 ERR(sh, "Name %s is invalid.", modkey->name); 2117 status = -1; 2118 goto cleanup; 2119 } 2120 2121 /* if priority == 0, then find the highest priority available */ 2122 if (modkey->priority == 0) { 2123 ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len); 2124 if (ret != 0) { 2125 status = -1; 2126 goto cleanup; 2127 } 2128 2129 for (i = 0; i < modinfos_len; i++) { 2130 ret = strcmp(modinfos[i].name, modkey->name); 2131 if (ret == 0) { 2132 highest = &modinfos[i]; 2133 break; 2134 } 2135 } 2136 2137 if (highest == NULL) { 2138 status = -1; 2139 goto cleanup; 2140 } 2141 2142 ret = semanage_module_info_create(sh, modinfo); 2143 if (ret != 0) { 2144 status = -1; 2145 goto cleanup; 2146 } 2147 2148 ret = semanage_module_info_clone(sh, highest, *modinfo); 2149 if (ret != 0) { 2150 status = -1; 2151 } 2152 2153 /* skip to cleanup, module was found */ 2154 goto cleanup; 2155 } 2156 2157 /* check module priority */ 2158 ret = semanage_module_validate_priority(modkey->priority); 2159 if (ret != 0) { 2160 errno = 0; 2161 ERR(sh, "Priority %d is invalid.", modkey->priority); 2162 status = -1; 2163 goto cleanup; 2164 } 2165 2166 /* copy in key values */ 2167 ret = semanage_module_info_create(sh, modinfo); 2168 if (ret != 0) { 2169 status = -1; 2170 goto cleanup; 2171 } 2172 2173 ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority); 2174 if (ret != 0) { 2175 status = -1; 2176 goto cleanup; 2177 } 2178 2179 ret = semanage_module_info_set_name(sh, *modinfo, modkey->name); 2180 if (ret != 0) { 2181 status = -1; 2182 goto cleanup; 2183 } 2184 2185 /* lookup module ext */ 2186 ret = semanage_module_get_path(sh, 2187 *modinfo, 2188 SEMANAGE_MODULE_PATH_LANG_EXT, 2189 fn, 2190 sizeof(fn)); 2191 if (ret != 0) { 2192 status = -1; 2193 goto cleanup; 2194 } 2195 2196 fp = fopen(fn, "r"); 2197 2198 if (fp == NULL) { 2199 ERR(sh, 2200 "Unable to open %s module lang ext file at %s.", 2201 (*modinfo)->name, fn); 2202 status = -1; 2203 goto cleanup; 2204 } 2205 2206 /* set module ext */ 2207 if (getline(&tmp, &size, fp) < 0) { 2208 ERR(sh, 2209 "Unable to read %s module lang ext file.", 2210 (*modinfo)->name); 2211 status = -1; 2212 goto cleanup; 2213 } 2214 2215 ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp); 2216 if (ret != 0) { 2217 status = -1; 2218 goto cleanup; 2219 } 2220 free(tmp); 2221 tmp = NULL; 2222 2223 if (fclose(fp) != 0) { 2224 ERR(sh, 2225 "Unable to close %s module lang ext file.", 2226 (*modinfo)->name); 2227 status = -1; 2228 goto cleanup; 2229 } 2230 2231 fp = NULL; 2232 2233 /* lookup enabled/disabled status */ 2234 ret = semanage_module_get_path(sh, 2235 *modinfo, 2236 SEMANAGE_MODULE_PATH_DISABLED, 2237 fn, 2238 sizeof(fn)); 2239 if (ret != 0) { 2240 status = -1; 2241 goto cleanup; 2242 } 2243 2244 /* set enabled/disabled status */ 2245 if (stat(fn, &sb) < 0) { 2246 ret = semanage_module_info_set_enabled(sh, *modinfo, 1); 2247 if (ret != 0) { 2248 status = -1; 2249 goto cleanup; 2250 } 2251 } 2252 else { 2253 ret = semanage_module_info_set_enabled(sh, *modinfo, 0); 2254 if (ret != 0) { 2255 status = -1; 2256 goto cleanup; 2257 } 2258 } 2259 2260 cleanup: 2261 free(tmp); 2262 2263 if (modinfos != NULL) { 2264 for (i = 0; i < modinfos_len; i++) { 2265 semanage_module_info_destroy(sh, &modinfos[i]); 2266 } 2267 free(modinfos); 2268 } 2269 2270 if (fp != NULL) fclose(fp); 2271 return status; 2272 } 2273 2274 static int semanage_direct_set_module_info(semanage_handle_t *sh, 2275 const semanage_module_info_t *modinfo) 2276 { 2277 int status = 0; 2278 int ret = 0; 2279 2280 char fn[PATH_MAX]; 2281 const char *path = NULL; 2282 int enabled = 0; 2283 semanage_module_info_t *modinfo_tmp = NULL; 2284 2285 semanage_module_key_t modkey; 2286 ret = semanage_module_key_init(sh, &modkey); 2287 if (ret != 0) { 2288 status = -1; 2289 goto cleanup; 2290 } 2291 2292 /* check transaction */ 2293 if (!sh->is_in_transaction) { 2294 if (semanage_begin_transaction(sh) < 0) { 2295 status = -1; 2296 goto cleanup; 2297 } 2298 } 2299 2300 /* validate module */ 2301 ret = semanage_module_info_validate(modinfo); 2302 if (ret != 0) { 2303 status = -1; 2304 goto cleanup; 2305 } 2306 2307 sh->modules_modified = 1; 2308 2309 /* check for modules path, create if missing */ 2310 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); 2311 2312 ret = semanage_mkdir(sh, path); 2313 if (ret != 0) { 2314 status = -1; 2315 goto cleanup; 2316 } 2317 2318 /* write priority */ 2319 ret = semanage_module_get_path(sh, 2320 modinfo, 2321 SEMANAGE_MODULE_PATH_PRIORITY, 2322 fn, 2323 sizeof(fn)); 2324 if (ret != 0) { 2325 status = -1; 2326 goto cleanup; 2327 } 2328 2329 ret = semanage_mkdir(sh, fn); 2330 if (ret != 0) { 2331 status = -1; 2332 goto cleanup; 2333 } 2334 2335 /* write name */ 2336 ret = semanage_module_get_path(sh, 2337 modinfo, 2338 SEMANAGE_MODULE_PATH_NAME, 2339 fn, 2340 sizeof(fn)); 2341 if (ret != 0) { 2342 status = -1; 2343 goto cleanup; 2344 } 2345 2346 ret = semanage_mkdir(sh, fn); 2347 if (ret != 0) { 2348 status = -1; 2349 goto cleanup; 2350 } 2351 2352 /* write ext */ 2353 ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo); 2354 if (ret != 0) { 2355 status = -1; 2356 goto cleanup; 2357 } 2358 2359 /* write enabled/disabled status */ 2360 2361 /* check for disabled path, create if missing */ 2362 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); 2363 2364 ret = semanage_mkdir(sh, path); 2365 if (ret != 0) { 2366 status = -1; 2367 goto cleanup; 2368 } 2369 2370 ret = semanage_module_get_path(sh, 2371 modinfo, 2372 SEMANAGE_MODULE_PATH_DISABLED, 2373 fn, 2374 sizeof(fn)); 2375 if (ret != 0) { 2376 status = -1; 2377 goto cleanup; 2378 } 2379 2380 ret = semanage_module_key_set_name(sh, &modkey, modinfo->name); 2381 if (ret != 0) { 2382 status = -1; 2383 goto cleanup; 2384 } 2385 2386 if (modinfo->enabled == -1) { 2387 /* default to enabled */ 2388 enabled = 1; 2389 2390 /* check if a module is already installed */ 2391 ret = semanage_module_get_module_info(sh, 2392 &modkey, 2393 &modinfo_tmp); 2394 if (ret == 0) { 2395 /* set enabled status to current one */ 2396 enabled = modinfo_tmp->enabled; 2397 } 2398 } 2399 else { 2400 enabled = modinfo->enabled; 2401 } 2402 2403 ret = semanage_module_set_enabled(sh, &modkey, enabled); 2404 if (ret != 0) { 2405 status = -1; 2406 goto cleanup; 2407 } 2408 2409 cleanup: 2410 semanage_module_key_destroy(sh, &modkey); 2411 2412 semanage_module_info_destroy(sh, modinfo_tmp); 2413 free(modinfo_tmp); 2414 2415 return status; 2416 } 2417 2418 static int semanage_priorities_filename_select(const struct dirent *d) 2419 { 2420 if (d->d_name[0] == '.' || 2421 strcmp(d->d_name, "disabled") == 0) 2422 return 0; 2423 return 1; 2424 } 2425 2426 static int semanage_modules_filename_select(const struct dirent *d) 2427 { 2428 if (d->d_name[0] == '.') 2429 return 0; 2430 return 1; 2431 } 2432 2433 static int semanage_direct_list_all(semanage_handle_t *sh, 2434 semanage_module_info_t **modinfos, 2435 int *modinfos_len) 2436 { 2437 assert(sh); 2438 assert(modinfos); 2439 assert(modinfos_len); 2440 2441 int status = 0; 2442 int ret = 0; 2443 2444 int i = 0; 2445 int j = 0; 2446 2447 *modinfos = NULL; 2448 *modinfos_len = 0; 2449 void *tmp = NULL; 2450 2451 const char *toplevel = NULL; 2452 2453 struct dirent **priorities = NULL; 2454 int priorities_len = 0; 2455 char priority_path[PATH_MAX]; 2456 2457 struct dirent **modules = NULL; 2458 int modules_len = 0; 2459 2460 uint16_t priority = 0; 2461 2462 semanage_module_info_t *modinfo_tmp = NULL; 2463 2464 semanage_module_info_t modinfo; 2465 ret = semanage_module_info_init(sh, &modinfo); 2466 if (ret != 0) { 2467 status = -1; 2468 goto cleanup; 2469 } 2470 2471 if (sh->is_in_transaction) { 2472 toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); 2473 } else { 2474 toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); 2475 } 2476 2477 /* find priorities */ 2478 priorities_len = scandir(toplevel, 2479 &priorities, 2480 semanage_priorities_filename_select, 2481 versionsort); 2482 if (priorities_len == -1) { 2483 ERR(sh, "Error while scanning directory %s.", toplevel); 2484 status = -1; 2485 goto cleanup; 2486 } 2487 2488 /* for each priority directory */ 2489 /* loop through in reverse so that highest priority is first */ 2490 for (i = priorities_len - 1; i >= 0; i--) { 2491 /* convert priority string to uint16_t */ 2492 ret = semanage_string_to_priority(priorities[i]->d_name, 2493 &priority); 2494 if (ret != 0) { 2495 status = -1; 2496 goto cleanup; 2497 } 2498 2499 /* set our priority */ 2500 ret = semanage_module_info_set_priority(sh, 2501 &modinfo, 2502 priority); 2503 if (ret != 0) { 2504 status = -1; 2505 goto cleanup; 2506 } 2507 2508 /* get the priority path */ 2509 ret = semanage_module_get_path(sh, 2510 &modinfo, 2511 SEMANAGE_MODULE_PATH_PRIORITY, 2512 priority_path, 2513 sizeof(priority_path)); 2514 if (ret != 0) { 2515 status = -1; 2516 goto cleanup; 2517 } 2518 2519 /* cleanup old modules */ 2520 if (modules != NULL) { 2521 for (j = 0; j < modules_len; j++) { 2522 free(modules[j]); 2523 modules[j] = NULL; 2524 } 2525 free(modules); 2526 modules = NULL; 2527 modules_len = 0; 2528 } 2529 2530 /* find modules at this priority */ 2531 modules_len = scandir(priority_path, 2532 &modules, 2533 semanage_modules_filename_select, 2534 versionsort); 2535 if (modules_len == -1) { 2536 ERR(sh, 2537 "Error while scanning directory %s.", 2538 priority_path); 2539 status = -1; 2540 goto cleanup; 2541 } 2542 2543 if (modules_len == 0) continue; 2544 2545 /* add space for modules */ 2546 tmp = realloc(*modinfos, 2547 sizeof(semanage_module_info_t) * 2548 (*modinfos_len + modules_len)); 2549 if (tmp == NULL) { 2550 ERR(sh, "Error allocating memory for module array."); 2551 status = -1; 2552 goto cleanup; 2553 } 2554 *modinfos = tmp; 2555 2556 /* for each module directory */ 2557 for(j = 0; j < modules_len; j++) { 2558 /* set module name */ 2559 ret = semanage_module_info_set_name( 2560 sh, 2561 &modinfo, 2562 modules[j]->d_name); 2563 if (ret != 0) { 2564 status = -1; 2565 goto cleanup; 2566 } 2567 2568 /* get module values */ 2569 ret = semanage_direct_get_module_info( 2570 sh, 2571 (const semanage_module_key_t *) 2572 (&modinfo), 2573 &modinfo_tmp); 2574 if (ret != 0) { 2575 status = -1; 2576 goto cleanup; 2577 } 2578 2579 /* copy into array */ 2580 ret = semanage_module_info_init( 2581 sh, 2582 &((*modinfos)[*modinfos_len])); 2583 if (ret != 0) { 2584 status = -1; 2585 goto cleanup; 2586 } 2587 2588 ret = semanage_module_info_clone( 2589 sh, 2590 modinfo_tmp, 2591 &((*modinfos)[*modinfos_len])); 2592 if (ret != 0) { 2593 status = -1; 2594 goto cleanup; 2595 } 2596 2597 semanage_module_info_destroy(sh, modinfo_tmp); 2598 free(modinfo_tmp); 2599 modinfo_tmp = NULL; 2600 2601 *modinfos_len += 1; 2602 } 2603 } 2604 2605 cleanup: 2606 semanage_module_info_destroy(sh, &modinfo); 2607 2608 if (priorities != NULL) { 2609 for (i = 0; i < priorities_len; i++) { 2610 free(priorities[i]); 2611 } 2612 free(priorities); 2613 } 2614 2615 if (modules != NULL) { 2616 for (i = 0; i < modules_len; i++) { 2617 free(modules[i]); 2618 } 2619 free(modules); 2620 } 2621 2622 semanage_module_info_destroy(sh, modinfo_tmp); 2623 free(modinfo_tmp); 2624 modinfo_tmp = NULL; 2625 2626 if (status != 0) { 2627 if (modinfos != NULL) { 2628 for (i = 0; i < *modinfos_len; i++) { 2629 semanage_module_info_destroy( 2630 sh, 2631 &(*modinfos)[i]); 2632 } 2633 free(*modinfos); 2634 *modinfos = NULL; 2635 *modinfos_len = 0; 2636 } 2637 } 2638 2639 return status; 2640 } 2641 2642 static int semanage_direct_install_info(semanage_handle_t *sh, 2643 const semanage_module_info_t *modinfo, 2644 char *data, 2645 size_t data_len) 2646 { 2647 assert(sh); 2648 assert(modinfo); 2649 assert(data); 2650 2651 int status = 0; 2652 int ret = 0; 2653 int type; 2654 2655 char path[PATH_MAX]; 2656 2657 semanage_module_info_t *higher_info = NULL; 2658 semanage_module_key_t higher_key; 2659 ret = semanage_module_key_init(sh, &higher_key); 2660 if (ret != 0) { 2661 status = -1; 2662 goto cleanup; 2663 } 2664 2665 /* validate module info */ 2666 ret = semanage_module_info_validate(modinfo); 2667 if (ret != 0) { 2668 ERR(sh, "%s failed module validation.\n", modinfo->name); 2669 status = -2; 2670 goto cleanup; 2671 } 2672 2673 /* Check for higher priority module and warn if there is one as 2674 * it will override the module currently being installed. 2675 */ 2676 ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name); 2677 if (ret != 0) { 2678 status = -1; 2679 goto cleanup; 2680 } 2681 2682 ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info); 2683 if (ret == 0) { 2684 if (higher_info->priority > modinfo->priority) { 2685 errno = 0; 2686 WARN(sh, 2687 "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.", 2688 modinfo->name, 2689 higher_info->priority, 2690 modinfo->priority); 2691 } 2692 else if (higher_info->priority < modinfo->priority) { 2693 errno = 0; 2694 INFO(sh, 2695 "Overriding %s module at lower priority %d with module at priority %d.", 2696 modinfo->name, 2697 higher_info->priority, 2698 modinfo->priority); 2699 } 2700 2701 if (higher_info->enabled == 0 && modinfo->enabled == -1) { 2702 errno = 0; 2703 WARN(sh, 2704 "%s module will be disabled after install due to default enabled status.", 2705 modinfo->name); 2706 } 2707 } 2708 2709 /* set module meta data */ 2710 ret = semanage_direct_set_module_info(sh, modinfo); 2711 if (ret != 0) { 2712 status = -2; 2713 goto cleanup; 2714 } 2715 2716 /* install module source file */ 2717 if (!strcasecmp(modinfo->lang_ext, "cil")) { 2718 type = SEMANAGE_MODULE_PATH_CIL; 2719 } else { 2720 type = SEMANAGE_MODULE_PATH_HLL; 2721 } 2722 ret = semanage_module_get_path( 2723 sh, 2724 modinfo, 2725 type, 2726 path, 2727 sizeof(path)); 2728 if (ret != 0) { 2729 status = -3; 2730 goto cleanup; 2731 } 2732 2733 ret = bzip(sh, path, data, data_len); 2734 if (ret <= 0) { 2735 ERR(sh, "Error while writing to %s.", path); 2736 status = -3; 2737 goto cleanup; 2738 } 2739 2740 /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */ 2741 if (type == SEMANAGE_MODULE_PATH_HLL) { 2742 ret = semanage_module_get_path( 2743 sh, 2744 modinfo, 2745 SEMANAGE_MODULE_PATH_CIL, 2746 path, 2747 sizeof(path)); 2748 if (ret != 0) { 2749 status = -3; 2750 goto cleanup; 2751 } 2752 2753 if (access(path, F_OK) == 0) { 2754 ret = unlink(path); 2755 if (ret != 0) { 2756 ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno)); 2757 status = -3; 2758 goto cleanup; 2759 } 2760 } 2761 } 2762 2763 cleanup: 2764 semanage_module_key_destroy(sh, &higher_key); 2765 semanage_module_info_destroy(sh, higher_info); 2766 free(higher_info); 2767 2768 return status; 2769 } 2770 2771 static int semanage_direct_remove_key(semanage_handle_t *sh, 2772 const semanage_module_key_t *modkey) 2773 { 2774 assert(sh); 2775 assert(modkey); 2776 2777 int status = 0; 2778 int ret = 0; 2779 2780 char path[PATH_MAX]; 2781 semanage_module_info_t *modinfo = NULL; 2782 2783 semanage_module_key_t modkey_tmp; 2784 ret = semanage_module_key_init(sh, &modkey_tmp); 2785 if (ret != 0) { 2786 status = -1; 2787 goto cleanup; 2788 } 2789 2790 /* validate module key */ 2791 ret = semanage_module_validate_priority(modkey->priority); 2792 if (ret != 0) { 2793 errno = 0; 2794 ERR(sh, "Priority %d is invalid.", modkey->priority); 2795 status = -1; 2796 goto cleanup; 2797 } 2798 2799 ret = semanage_module_validate_name(modkey->name); 2800 if (ret != 0) { 2801 errno = 0; 2802 ERR(sh, "Name %s is invalid.", modkey->name); 2803 status = -1; 2804 goto cleanup; 2805 } 2806 2807 ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name); 2808 if (ret != 0) { 2809 status = -1; 2810 goto cleanup; 2811 } 2812 2813 /* get module path */ 2814 ret = semanage_module_get_path( 2815 sh, 2816 (const semanage_module_info_t *)modkey, 2817 SEMANAGE_MODULE_PATH_NAME, 2818 path, 2819 sizeof(path)); 2820 if (ret != 0) { 2821 status = -2; 2822 goto cleanup; 2823 } 2824 2825 /* remove directory */ 2826 ret = semanage_remove_directory(path); 2827 if (ret != 0) { 2828 ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority); 2829 status = -2; 2830 goto cleanup; 2831 } 2832 2833 /* check if its the last module at any priority */ 2834 ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo); 2835 if (ret != 0) { 2836 /* info that no other module will override */ 2837 errno = 0; 2838 INFO(sh, 2839 "Removing last %s module (no other %s module exists at another priority).", 2840 modkey->name, 2841 modkey->name); 2842 2843 /* remove disabled status file */ 2844 ret = semanage_module_get_path( 2845 sh, 2846 (const semanage_module_info_t *)modkey, 2847 SEMANAGE_MODULE_PATH_DISABLED, 2848 path, 2849 sizeof(path)); 2850 if (ret != 0) { 2851 status = -1; 2852 goto cleanup; 2853 } 2854 2855 struct stat sb; 2856 if (stat(path, &sb) == 0) { 2857 ret = unlink(path); 2858 if (ret != 0) { 2859 status = -1; 2860 goto cleanup; 2861 } 2862 } 2863 } 2864 else { 2865 /* if a lower priority module is going to become active */ 2866 if (modkey->priority > modinfo->priority) { 2867 /* inform what the new active module will be */ 2868 errno = 0; 2869 INFO(sh, 2870 "%s module at priority %d is now active.", 2871 modinfo->name, 2872 modinfo->priority); 2873 } 2874 } 2875 2876 cleanup: 2877 semanage_module_key_destroy(sh, &modkey_tmp); 2878 2879 semanage_module_info_destroy(sh, modinfo); 2880 free(modinfo); 2881 2882 return status; 2883 } 2884 2885