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 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA); 621 if (ofilename == NULL) { 622 return retval; 623 } 624 retval = write_file(sh, ofilename, data, size); 625 if (retval < 0) 626 return retval; 627 628 pusers_extra->dtable->drop_cache(pusers_extra->dbase); 629 630 } else { 631 retval = pusers_extra->dtable->clear(sh, pusers_extra->dbase); 632 } 633 634 cleanup: 635 free(data); 636 637 return retval; 638 } 639 640 static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb) 641 { 642 const char *ofilename = NULL; 643 int retval = -1; 644 char *data = NULL; 645 size_t size = 0; 646 647 dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh); 648 649 retval = cil_selinuxusers_to_string(cildb, &data, &size); 650 if (retval != SEPOL_OK) { 651 goto cleanup; 652 } 653 654 if (size > 0) { 655 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 656 if (ofilename == NULL) { 657 return -1; 658 } 659 retval = write_file(sh, ofilename, data, size); 660 661 pseusers->dtable->drop_cache(pseusers->dbase); 662 } else { 663 retval = pseusers->dtable->clear(sh, pseusers->dbase); 664 } 665 666 cleanup: 667 free(data); 668 669 return retval; 670 } 671 672 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) 673 { 674 size_t max_len = initial_len; 675 size_t read_len = 0; 676 size_t data_read_len = 0; 677 char *data_read = NULL; 678 679 if (max_len <= 0) { 680 max_len = 1; 681 } 682 data_read = malloc(max_len * sizeof(*data_read)); 683 if (data_read == NULL) { 684 ERR(sh, "Failed to malloc, out of memory.\n"); 685 return -1; 686 } 687 688 while ((read_len = read(fd, data_read + data_read_len, max_len - data_read_len)) > 0) { 689 data_read_len += read_len; 690 if (data_read_len == max_len) { 691 max_len *= 2; 692 data_read = realloc(data_read, max_len); 693 if (data_read == NULL) { 694 ERR(sh, "Failed to realloc, out of memory.\n"); 695 return -1; 696 } 697 } 698 } 699 700 *out_read_len = data_read_len; 701 *out_data_read = data_read; 702 703 return 0; 704 } 705 706 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) 707 { 708 int input_fd[2]; 709 int output_fd[2]; 710 int err_fd[2]; 711 pid_t pid; 712 char *data_read = NULL; 713 char *err_data_read = NULL; 714 int retval; 715 int status = 0; 716 size_t initial_len; 717 size_t data_read_len = 0; 718 size_t err_data_read_len = 0; 719 struct sigaction old_signal; 720 struct sigaction new_signal; 721 new_signal.sa_handler = SIG_IGN; 722 sigemptyset(&new_signal.sa_mask); 723 new_signal.sa_flags = 0; 724 /* This is needed in case the read end of input_fd is closed causing a SIGPIPE signal to be sent. 725 * If SIGPIPE is not caught, the signal will cause semanage to terminate immediately. The sigaction below 726 * creates a new_signal that ignores SIGPIPE allowing the write to exit cleanly. 727 * 728 * Another sigaction is called in cleanup to restore the original behavior when a SIGPIPE is received. 729 */ 730 sigaction(SIGPIPE, &new_signal, &old_signal); 731 732 retval = pipe(input_fd); 733 if (retval == -1) { 734 ERR(sh, "Unable to create pipe for input pipe: %s\n", strerror(errno)); 735 goto cleanup; 736 } 737 retval = pipe(output_fd); 738 if (retval == -1) { 739 ERR(sh, "Unable to create pipe for output pipe: %s\n", strerror(errno)); 740 goto cleanup; 741 } 742 retval = pipe(err_fd); 743 if (retval == -1) { 744 ERR(sh, "Unable to create pipe for error pipe: %s\n", strerror(errno)); 745 goto cleanup; 746 } 747 748 pid = fork(); 749 if (pid == -1) { 750 ERR(sh, "Unable to fork from parent: %s.", strerror(errno)); 751 retval = -1; 752 goto cleanup; 753 } else if (pid == 0) { 754 retval = dup2(input_fd[PIPE_READ], STDIN_FILENO); 755 if (retval == -1) { 756 ERR(sh, "Unable to dup2 input pipe: %s\n", strerror(errno)); 757 goto cleanup; 758 } 759 retval = dup2(output_fd[PIPE_WRITE], STDOUT_FILENO); 760 if (retval == -1) { 761 ERR(sh, "Unable to dup2 output pipe: %s\n", strerror(errno)); 762 goto cleanup; 763 } 764 retval = dup2(err_fd[PIPE_WRITE], STDERR_FILENO); 765 if (retval == -1) { 766 ERR(sh, "Unable to dup2 error pipe: %s\n", strerror(errno)); 767 goto cleanup; 768 } 769 770 retval = close(input_fd[PIPE_WRITE]); 771 if (retval == -1) { 772 ERR(sh, "Unable to close input pipe: %s\n", strerror(errno)); 773 goto cleanup; 774 } 775 retval = close(output_fd[PIPE_READ]); 776 if (retval == -1) { 777 ERR(sh, "Unable to close output pipe: %s\n", strerror(errno)); 778 goto cleanup; 779 } 780 retval = close(err_fd[PIPE_READ]); 781 if (retval == -1) { 782 ERR(sh, "Unable to close error pipe: %s\n", strerror(errno)); 783 goto cleanup; 784 } 785 retval = execl(path, path, NULL); 786 if (retval == -1) { 787 ERR(sh, "Unable to execute %s : %s\n", path, strerror(errno)); 788 _exit(EXIT_FAILURE); 789 } 790 } else { 791 retval = close(input_fd[PIPE_READ]); 792 input_fd[PIPE_READ] = -1; 793 if (retval == -1) { 794 ERR(sh, "Unable to close read end of input pipe: %s\n", strerror(errno)); 795 goto cleanup; 796 } 797 798 retval = close(output_fd[PIPE_WRITE]); 799 output_fd[PIPE_WRITE] = -1; 800 if (retval == -1) { 801 ERR(sh, "Unable to close write end of output pipe: %s\n", strerror(errno)); 802 goto cleanup; 803 } 804 805 retval = close(err_fd[PIPE_WRITE]); 806 err_fd[PIPE_WRITE] = -1; 807 if (retval == -1) { 808 ERR(sh, "Unable to close write end of error pipe: %s\n", strerror(errno)); 809 goto cleanup; 810 } 811 812 retval = write(input_fd[PIPE_WRITE], in_data, in_data_len); 813 if (retval == -1) { 814 ERR(sh, "Failed to write data to input pipe: %s\n", strerror(errno)); 815 goto cleanup; 816 } 817 retval = close(input_fd[PIPE_WRITE]); 818 input_fd[PIPE_WRITE] = -1; 819 if (retval == -1) { 820 ERR(sh, "Unable to close write end of input pipe: %s\n", strerror(errno)); 821 goto cleanup; 822 } 823 824 initial_len = 1 << 17; 825 retval = read_from_pipe_to_data(sh, initial_len, output_fd[PIPE_READ], &data_read, &data_read_len); 826 if (retval != 0) { 827 goto cleanup; 828 } 829 retval = close(output_fd[PIPE_READ]); 830 output_fd[PIPE_READ] = -1; 831 if (retval == -1) { 832 ERR(sh, "Unable to close read end of output pipe: %s\n", strerror(errno)); 833 goto cleanup; 834 } 835 836 initial_len = 1 << 9; 837 retval = read_from_pipe_to_data(sh, initial_len, err_fd[PIPE_READ], &err_data_read, &err_data_read_len); 838 if (retval != 0) { 839 goto cleanup; 840 } 841 retval = close(err_fd[PIPE_READ]); 842 err_fd[PIPE_READ] = -1; 843 if (retval == -1) { 844 ERR(sh, "Unable to close read end of error pipe: %s\n", strerror(errno)); 845 goto cleanup; 846 } 847 848 if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status)) { 849 ERR(sh, "Child process %s did not exit cleanly.", path); 850 retval = -1; 851 goto cleanup; 852 } 853 if (WEXITSTATUS(status) != 0) { 854 ERR(sh, "Child process %s failed with code: %d.", path, WEXITSTATUS(status)); 855 retval = -1; 856 goto cleanup; 857 } 858 } 859 860 retval = 0; 861 862 cleanup: 863 sigaction(SIGPIPE, &old_signal, NULL); 864 865 if (data_read != NULL) { 866 *out_data = data_read; 867 *out_data_len = data_read_len; 868 } 869 870 if (err_data_read != NULL) { 871 *err_data = err_data_read; 872 *err_data_len = err_data_read_len; 873 } 874 875 if (output_fd[PIPE_READ] != -1) { 876 close(output_fd[PIPE_READ]); 877 } 878 if (output_fd[PIPE_WRITE] != -1) { 879 close(output_fd[PIPE_WRITE]); 880 } 881 if (err_fd[PIPE_READ] != -1) { 882 close(err_fd[PIPE_READ]); 883 } 884 if (err_fd[PIPE_WRITE] != -1) { 885 close(err_fd[PIPE_WRITE]); 886 } 887 if (input_fd[PIPE_READ] != -1) { 888 close(input_fd[PIPE_READ]); 889 } 890 if (input_fd[PIPE_WRITE] != -1) { 891 close(input_fd[PIPE_WRITE]); 892 } 893 894 return retval; 895 } 896 897 static int semanage_direct_write_langext(semanage_handle_t *sh, 898 const char *lang_ext, 899 const semanage_module_info_t *modinfo) 900 { 901 int ret = -1; 902 char fn[PATH_MAX]; 903 FILE *fp = NULL; 904 905 ret = semanage_module_get_path(sh, 906 modinfo, 907 SEMANAGE_MODULE_PATH_LANG_EXT, 908 fn, 909 sizeof(fn)); 910 if (ret != 0) { 911 goto cleanup; 912 } 913 914 fp = fopen(fn, "w"); 915 if (fp == NULL) { 916 ERR(sh, "Unable to open %s module ext file.", modinfo->name); 917 ret = -1; 918 goto cleanup; 919 } 920 921 if (fputs(lang_ext, fp) < 0) { 922 ERR(sh, "Unable to write %s module ext file.", modinfo->name); 923 ret = -1; 924 goto cleanup; 925 } 926 927 if (fclose(fp) != 0) { 928 ERR(sh, "Unable to close %s module ext file.", modinfo->name); 929 ret = -1; 930 goto cleanup; 931 } 932 933 fp = NULL; 934 935 ret = 0; 936 937 cleanup: 938 if (fp != NULL) fclose(fp); 939 940 return ret; 941 } 942 943 static int semanage_compile_module(semanage_handle_t *sh, 944 semanage_module_info_t *modinfo) 945 { 946 char cil_path[PATH_MAX]; 947 char hll_path[PATH_MAX]; 948 char *compiler_path = NULL; 949 char *cil_data = NULL; 950 char *err_data = NULL; 951 char *hll_data = NULL; 952 char *start = NULL; 953 char *end = NULL; 954 ssize_t hll_data_len = 0; 955 ssize_t bzip_status; 956 int status = 0; 957 int compressed; 958 size_t cil_data_len = 0; 959 size_t err_data_len = 0; 960 961 if (!strcasecmp(modinfo->lang_ext, "cil")) { 962 goto cleanup; 963 } 964 965 status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path); 966 if (status != 0) { 967 goto cleanup; 968 } 969 970 status = semanage_module_get_path( 971 sh, 972 modinfo, 973 SEMANAGE_MODULE_PATH_CIL, 974 cil_path, 975 sizeof(cil_path)); 976 if (status != 0) { 977 goto cleanup; 978 } 979 980 status = semanage_module_get_path( 981 sh, 982 modinfo, 983 SEMANAGE_MODULE_PATH_HLL, 984 hll_path, 985 sizeof(hll_path)); 986 if (status != 0) { 987 goto cleanup; 988 } 989 990 if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) { 991 ERR(sh, "Unable to read file %s\n", hll_path); 992 status = -1; 993 goto cleanup; 994 } 995 996 status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len); 997 if (err_data_len > 0) { 998 for (start = end = err_data; end < err_data + err_data_len; end++) { 999 if (*end == '\n') { 1000 fprintf(stderr, "%s: ", modinfo->name); 1001 fwrite(start, 1, end - start + 1, stderr); 1002 start = end + 1; 1003 } 1004 } 1005 1006 if (end != start) { 1007 fprintf(stderr, "%s: ", modinfo->name); 1008 fwrite(start, 1, end - start, stderr); 1009 fprintf(stderr, "\n"); 1010 } 1011 } 1012 if (status != 0) { 1013 goto cleanup; 1014 } 1015 1016 bzip_status = bzip(sh, cil_path, cil_data, cil_data_len); 1017 if (bzip_status == -1) { 1018 ERR(sh, "Failed to bzip %s\n", cil_path); 1019 status = -1; 1020 goto cleanup; 1021 } 1022 1023 if (sh->conf->remove_hll == 1) { 1024 status = unlink(hll_path); 1025 if (status != 0) { 1026 ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno)); 1027 goto cleanup; 1028 } 1029 1030 status = semanage_direct_write_langext(sh, "cil", modinfo); 1031 if (status != 0) { 1032 goto cleanup; 1033 } 1034 } 1035 1036 cleanup: 1037 if (hll_data_len > 0) { 1038 munmap(hll_data, hll_data_len); 1039 } 1040 free(cil_data); 1041 free(err_data); 1042 free(compiler_path); 1043 1044 return status; 1045 } 1046 1047 static int semanage_compile_hll_modules(semanage_handle_t *sh, 1048 semanage_module_info_t *modinfos, 1049 int num_modinfos) 1050 { 1051 int status = 0; 1052 int i; 1053 char cil_path[PATH_MAX]; 1054 1055 assert(sh); 1056 assert(modinfos); 1057 1058 for (i = 0; i < num_modinfos; i++) { 1059 status = semanage_module_get_path( 1060 sh, 1061 &modinfos[i], 1062 SEMANAGE_MODULE_PATH_CIL, 1063 cil_path, 1064 sizeof(cil_path)); 1065 if (status != 0) { 1066 goto cleanup; 1067 } 1068 1069 if (semanage_get_ignore_module_cache(sh) == 0 && 1070 access(cil_path, F_OK) == 0) { 1071 continue; 1072 } 1073 1074 status = semanage_compile_module(sh, &modinfos[i]); 1075 if (status < 0) { 1076 goto cleanup; 1077 } 1078 } 1079 1080 status = 0; 1081 1082 cleanup: 1083 return status; 1084 } 1085 1086 /********************* direct API functions ********************/ 1087 1088 /* Commits all changes in sandbox to the actual kernel policy. 1089 * Returns commit number on success, -1 on error. 1090 */ 1091 static int semanage_direct_commit(semanage_handle_t * sh) 1092 { 1093 char **mod_filenames = NULL; 1094 char *fc_buffer = NULL; 1095 size_t fc_buffer_len = 0; 1096 const char *ofilename = NULL; 1097 const char *path; 1098 int retval = -1, num_modinfos = 0, i, missing_policy_kern = 0, 1099 missing_seusers = 0, missing_fc = 0, missing = 0; 1100 sepol_policydb_t *out = NULL; 1101 struct cil_db *cildb = NULL; 1102 semanage_module_info_t *modinfos = NULL; 1103 1104 /* Declare some variables */ 1105 int modified = 0, fcontexts_modified, ports_modified, 1106 seusers_modified, users_extra_modified, dontaudit_modified, 1107 preserve_tunables_modified, bools_modified = 0, 1108 disable_dontaudit, preserve_tunables; 1109 dbase_config_t *users = semanage_user_dbase_local(sh); 1110 dbase_config_t *users_base = semanage_user_base_dbase_local(sh); 1111 dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh); 1112 dbase_config_t *users_extra = semanage_user_extra_dbase_local(sh); 1113 dbase_config_t *ports = semanage_port_dbase_local(sh); 1114 dbase_config_t *pports = semanage_port_dbase_policy(sh); 1115 dbase_config_t *bools = semanage_bool_dbase_local(sh); 1116 dbase_config_t *pbools = semanage_bool_dbase_policy(sh); 1117 dbase_config_t *ifaces = semanage_iface_dbase_local(sh); 1118 dbase_config_t *pifaces = semanage_iface_dbase_policy(sh); 1119 dbase_config_t *nodes = semanage_node_dbase_local(sh); 1120 dbase_config_t *pnodes = semanage_node_dbase_policy(sh); 1121 dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh); 1122 dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh); 1123 dbase_config_t *seusers = semanage_seuser_dbase_local(sh); 1124 1125 /* Create or remove the disable_dontaudit flag file. */ 1126 path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT); 1127 if (access(path, F_OK) == 0) 1128 dontaudit_modified = !(sepol_get_disable_dontaudit(sh->sepolh) == 1); 1129 else 1130 dontaudit_modified = (sepol_get_disable_dontaudit(sh->sepolh) == 1); 1131 if (sepol_get_disable_dontaudit(sh->sepolh) == 1) { 1132 FILE *touch; 1133 touch = fopen(path, "w"); 1134 if (touch != NULL) { 1135 if (fclose(touch) != 0) { 1136 ERR(sh, "Error attempting to create disable_dontaudit flag."); 1137 goto cleanup; 1138 } 1139 } else { 1140 ERR(sh, "Error attempting to create disable_dontaudit flag."); 1141 goto cleanup; 1142 } 1143 } else { 1144 if (remove(path) == -1 && errno != ENOENT) { 1145 ERR(sh, "Error removing the disable_dontaudit flag."); 1146 goto cleanup; 1147 } 1148 } 1149 1150 /* Create or remove the preserve_tunables flag file. */ 1151 path = semanage_path(SEMANAGE_TMP, SEMANAGE_PRESERVE_TUNABLES); 1152 if (access(path, F_OK) == 0) 1153 preserve_tunables_modified = !(sepol_get_preserve_tunables(sh->sepolh) == 1); 1154 else 1155 preserve_tunables_modified = (sepol_get_preserve_tunables(sh->sepolh) == 1); 1156 if (sepol_get_preserve_tunables(sh->sepolh) == 1) { 1157 FILE *touch; 1158 touch = fopen(path, "w"); 1159 if (touch != NULL) { 1160 if (fclose(touch) != 0) { 1161 ERR(sh, "Error attempting to create preserve_tunable flag."); 1162 goto cleanup; 1163 } 1164 } else { 1165 ERR(sh, "Error attempting to create preserve_tunable flag."); 1166 goto cleanup; 1167 } 1168 } else { 1169 if (remove(path) == -1 && errno != ENOENT) { 1170 ERR(sh, "Error removing the preserve_tunables flag."); 1171 goto cleanup; 1172 } 1173 } 1174 1175 /* Before we do anything else, flush the join to its component parts. 1176 * This *does not* flush to disk automatically */ 1177 if (users->dtable->is_modified(users->dbase)) { 1178 retval = users->dtable->flush(sh, users->dbase); 1179 if (retval < 0) 1180 goto cleanup; 1181 } 1182 1183 /* Decide if anything was modified */ 1184 fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase); 1185 seusers_modified = seusers->dtable->is_modified(seusers->dbase); 1186 users_extra_modified = 1187 users_extra->dtable->is_modified(users_extra->dbase); 1188 ports_modified = ports->dtable->is_modified(ports->dbase); 1189 bools_modified = bools->dtable->is_modified(bools->dbase); 1190 1191 modified = sh->modules_modified; 1192 modified |= seusers_modified; 1193 modified |= users_extra_modified; 1194 modified |= ports_modified; 1195 modified |= users->dtable->is_modified(users_base->dbase); 1196 modified |= ifaces->dtable->is_modified(ifaces->dbase); 1197 modified |= nodes->dtable->is_modified(nodes->dbase); 1198 modified |= dontaudit_modified; 1199 modified |= preserve_tunables_modified; 1200 1201 /* This is for systems that have already migrated with an older version 1202 * of semanage_migrate_store. The older version did not copy policy.kern so 1203 * the policy binary must be rebuilt here. 1204 */ 1205 if (!sh->do_rebuild && !modified) { 1206 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL); 1207 1208 if (access(path, F_OK) != 0) { 1209 missing_policy_kern = 1; 1210 } 1211 1212 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); 1213 1214 if (access(path, F_OK) != 0) { 1215 missing_fc = 1; 1216 } 1217 1218 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 1219 1220 if (access(path, F_OK) != 0) { 1221 missing_seusers = 1; 1222 } 1223 } 1224 1225 missing |= missing_policy_kern; 1226 missing |= missing_fc; 1227 missing |= missing_seusers; 1228 1229 /* If there were policy changes, or explicitly requested, rebuild the policy */ 1230 if (sh->do_rebuild || modified || missing) { 1231 /* =================== Module expansion =============== */ 1232 1233 retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos); 1234 if (retval < 0) { 1235 goto cleanup; 1236 } 1237 1238 if (num_modinfos == 0) { 1239 goto cleanup; 1240 } 1241 1242 retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos); 1243 if (retval < 0) { 1244 ERR(sh, "Failed to compile hll files into cil files.\n"); 1245 goto cleanup; 1246 } 1247 1248 retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames); 1249 if (retval < 0) 1250 goto cleanup; 1251 1252 retval = semanage_verify_modules(sh, mod_filenames, num_modinfos); 1253 if (retval < 0) 1254 goto cleanup; 1255 1256 cil_db_init(&cildb); 1257 1258 disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh); 1259 preserve_tunables = sepol_get_preserve_tunables(sh->sepolh); 1260 cil_set_disable_dontaudit(cildb, disable_dontaudit); 1261 cil_set_disable_neverallow(cildb, !(sh->conf->expand_check)); 1262 cil_set_preserve_tunables(cildb, preserve_tunables); 1263 cil_set_target_platform(cildb, sh->conf->target_platform); 1264 cil_set_policy_version(cildb, sh->conf->policyvers); 1265 1266 if (sh->conf->handle_unknown != -1) { 1267 cil_set_handle_unknown(cildb, sh->conf->handle_unknown); 1268 } 1269 1270 retval = semanage_load_files(sh, cildb, mod_filenames, num_modinfos); 1271 if (retval < 0) { 1272 goto cleanup; 1273 } 1274 1275 retval = cil_compile(cildb); 1276 if (retval < 0) 1277 goto cleanup; 1278 1279 retval = cil_build_policydb(cildb, &out); 1280 if (retval < 0) 1281 goto cleanup; 1282 1283 /* File Contexts */ 1284 retval = cil_filecons_to_string(cildb, &fc_buffer, &fc_buffer_len); 1285 if (retval < 0) 1286 goto cleanup; 1287 1288 /* Write the contexts (including template contexts) to a single file. */ 1289 ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL); 1290 if (ofilename == NULL) { 1291 retval = -1; 1292 goto cleanup; 1293 } 1294 retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len); 1295 if (retval < 0) 1296 goto cleanup; 1297 1298 /* Split complete and template file contexts into their separate files. */ 1299 retval = semanage_split_fc(sh); 1300 if (retval < 0) 1301 goto cleanup; 1302 1303 /* remove FC_TMPL now that it is now longer needed */ 1304 unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL)); 1305 1306 pfcontexts->dtable->drop_cache(pfcontexts->dbase); 1307 1308 /* SEUsers */ 1309 retval = semanage_direct_update_seuser(sh, cildb); 1310 if (retval < 0) 1311 goto cleanup; 1312 1313 /* User Extra */ 1314 retval = semanage_direct_update_user_extra(sh, cildb); 1315 if (retval < 0) 1316 goto cleanup; 1317 1318 cil_db_destroy(&cildb); 1319 1320 } else { 1321 /* Load already linked policy */ 1322 retval = sepol_policydb_create(&out); 1323 if (retval < 0) 1324 goto cleanup; 1325 1326 retval = semanage_read_policydb(sh, out); 1327 if (retval < 0) 1328 goto cleanup; 1329 } 1330 1331 if (sh->do_rebuild || modified || bools_modified) { 1332 /* Attach to policy databases that work with a policydb. */ 1333 dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out); 1334 dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out); 1335 dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out); 1336 dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out); 1337 dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out); 1338 1339 /* ============= Apply changes, and verify =============== */ 1340 1341 retval = semanage_base_merge_components(sh); 1342 if (retval < 0) 1343 goto cleanup; 1344 1345 retval = semanage_write_policydb(sh, out); 1346 if (retval < 0) 1347 goto cleanup; 1348 1349 retval = semanage_verify_kernel(sh); 1350 if (retval < 0) 1351 goto cleanup; 1352 } else { 1353 retval = semanage_base_merge_components(sh); 1354 if (retval < 0) 1355 goto cleanup; 1356 } 1357 1358 /* ======= Post-process: Validate non-policydb components ===== */ 1359 1360 /* Validate local modifications to file contexts. 1361 * Note: those are still cached, even though they've been 1362 * merged into the main file_contexts. We won't check the 1363 * large file_contexts - checked at compile time */ 1364 if (sh->do_rebuild || modified || fcontexts_modified) { 1365 retval = semanage_fcontext_validate_local(sh, out); 1366 if (retval < 0) 1367 goto cleanup; 1368 } 1369 1370 /* Validate local seusers against policy */ 1371 if (sh->do_rebuild || modified || seusers_modified) { 1372 retval = semanage_seuser_validate_local(sh, out); 1373 if (retval < 0) 1374 goto cleanup; 1375 } 1376 1377 /* Validate local ports for overlap */ 1378 if (sh->do_rebuild || modified || ports_modified) { 1379 retval = semanage_port_validate_local(sh); 1380 if (retval < 0) 1381 goto cleanup; 1382 } 1383 1384 /* ================== Write non-policydb components ========= */ 1385 1386 /* Commit changes to components */ 1387 retval = semanage_commit_components(sh); 1388 if (retval < 0) 1389 goto cleanup; 1390 1391 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL), 1392 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL), 1393 sh->conf->file_mode); 1394 if (retval < 0) { 1395 goto cleanup; 1396 } 1397 1398 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL); 1399 if (access(path, F_OK) == 0) { 1400 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL), 1401 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL), 1402 sh->conf->file_mode); 1403 if (retval < 0) { 1404 goto cleanup; 1405 } 1406 } 1407 1408 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC); 1409 if (access(path, F_OK) == 0) { 1410 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC), 1411 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC), 1412 sh->conf->file_mode); 1413 if (retval < 0) { 1414 goto cleanup; 1415 } 1416 } 1417 1418 path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS); 1419 if (access(path, F_OK) == 0) { 1420 retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS), 1421 semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS), 1422 sh->conf->file_mode); 1423 if (retval < 0) { 1424 goto cleanup; 1425 } 1426 } 1427 1428 /* run genhomedircon if its enabled, this should be the last operation 1429 * which requires the out policydb */ 1430 if (!sh->conf->disable_genhomedircon) { 1431 if (out && (retval = 1432 semanage_genhomedircon(sh, out, sh->conf->usepasswd, sh->conf->ignoredirs)) != 0) { 1433 ERR(sh, "semanage_genhomedircon returned error code %d.", 1434 retval); 1435 goto cleanup; 1436 } 1437 } else { 1438 WARN(sh, "WARNING: genhomedircon is disabled. \ 1439 See /etc/selinux/semanage.conf if you need to enable it."); 1440 } 1441 1442 /* free out, if we don't free it before calling semanage_install_sandbox 1443 * then fork() may fail on low memory machines */ 1444 sepol_policydb_free(out); 1445 out = NULL; 1446 1447 if (sh->do_rebuild || modified || bools_modified || fcontexts_modified) { 1448 retval = semanage_install_sandbox(sh); 1449 } 1450 1451 cleanup: 1452 for (i = 0; i < num_modinfos; i++) { 1453 semanage_module_info_destroy(sh, &modinfos[i]); 1454 } 1455 free(modinfos); 1456 1457 for (i = 0; mod_filenames != NULL && i < num_modinfos; i++) { 1458 free(mod_filenames[i]); 1459 } 1460 1461 if (modified || bools_modified) { 1462 /* Detach from policydb, so it can be freed */ 1463 dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase); 1464 dbase_policydb_detach((dbase_policydb_t *) pports->dbase); 1465 dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase); 1466 dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase); 1467 dbase_policydb_detach((dbase_policydb_t *) pbools->dbase); 1468 } 1469 1470 free(mod_filenames); 1471 sepol_policydb_free(out); 1472 cil_db_destroy(&cildb); 1473 semanage_release_trans_lock(sh); 1474 1475 free(fc_buffer); 1476 1477 /* regardless if the commit was successful or not, remove the 1478 sandbox if it is still there */ 1479 semanage_remove_directory(semanage_path 1480 (SEMANAGE_TMP, SEMANAGE_TOPLEVEL)); 1481 semanage_remove_directory(semanage_final_path 1482 (SEMANAGE_FINAL_TMP, 1483 SEMANAGE_FINAL_TOPLEVEL)); 1484 return retval; 1485 } 1486 1487 /* Writes a module to the sandbox's module directory, overwriting any 1488 * previous module stored within. Note that module data are not 1489 * free()d by this function; caller is responsible for deallocating it 1490 * if necessary. Returns 0 on success, -1 if out of memory, -2 if the 1491 * data does not represent a valid module file, -3 if error while 1492 * writing file. */ 1493 static int semanage_direct_install(semanage_handle_t * sh, 1494 char *data, size_t data_len, 1495 const char *module_name, const char *lang_ext) 1496 { 1497 int status = 0; 1498 int ret = 0; 1499 1500 semanage_module_info_t modinfo; 1501 ret = semanage_module_info_init(sh, &modinfo); 1502 if (ret != 0) { 1503 status = -1; 1504 goto cleanup; 1505 } 1506 1507 ret = semanage_module_info_set_priority(sh, &modinfo, sh->priority); 1508 if (ret != 0) { 1509 status = -1; 1510 goto cleanup; 1511 } 1512 1513 ret = semanage_module_info_set_name(sh, &modinfo, module_name); 1514 if (ret != 0) { 1515 status = -1; 1516 goto cleanup; 1517 } 1518 1519 ret = semanage_module_info_set_lang_ext(sh, &modinfo, lang_ext); 1520 if (ret != 0) { 1521 status = -1; 1522 goto cleanup; 1523 } 1524 1525 ret = semanage_module_info_set_enabled(sh, &modinfo, -1); 1526 if (ret != 0) { 1527 status = -1; 1528 goto cleanup; 1529 } 1530 1531 status = semanage_direct_install_info(sh, &modinfo, data, data_len); 1532 1533 cleanup: 1534 1535 semanage_module_info_destroy(sh, &modinfo); 1536 1537 return status; 1538 } 1539 1540 /* Attempts to link a module to the sandbox's module directory, unlinking any 1541 * previous module stored within. Returns 0 on success, -1 if out of memory, -2 if the 1542 * data does not represent a valid module file, -3 if error while 1543 * writing file. */ 1544 1545 static int semanage_direct_install_file(semanage_handle_t * sh, 1546 const char *install_filename) 1547 { 1548 1549 int retval = -1; 1550 char *data = NULL; 1551 ssize_t data_len = 0; 1552 int compressed = 0; 1553 char *path = NULL; 1554 char *filename; 1555 char *lang_ext = NULL; 1556 char *module_name = NULL; 1557 char *separator; 1558 char *version = NULL; 1559 1560 if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) { 1561 ERR(sh, "Unable to read file %s\n", install_filename); 1562 retval = -1; 1563 goto cleanup; 1564 } 1565 1566 path = strdup(install_filename); 1567 if (path == NULL) { 1568 ERR(sh, "No memory available for strdup.\n"); 1569 retval = -1; 1570 goto cleanup; 1571 } 1572 1573 filename = basename(path); 1574 1575 if (compressed) { 1576 separator = strrchr(filename, '.'); 1577 if (separator == NULL) { 1578 ERR(sh, "Compressed module does not have a valid extension."); 1579 retval = -1; 1580 goto cleanup; 1581 } 1582 *separator = '\0'; 1583 lang_ext = separator + 1; 1584 } 1585 1586 separator = strrchr(filename, '.'); 1587 if (separator == NULL) { 1588 if (lang_ext == NULL) { 1589 ERR(sh, "Module does not have a valid extension."); 1590 retval = -1; 1591 goto cleanup; 1592 } 1593 } else { 1594 *separator = '\0'; 1595 lang_ext = separator + 1; 1596 } 1597 1598 if (strcmp(lang_ext, "pp") == 0) { 1599 retval = parse_module_headers(sh, data, data_len, &module_name, &version); 1600 free(version); 1601 if (retval != 0) 1602 goto cleanup; 1603 } 1604 1605 if (module_name == NULL) { 1606 module_name = strdup(filename); 1607 if (module_name == NULL) { 1608 ERR(sh, "No memory available for module_name.\n"); 1609 retval = -1; 1610 goto cleanup; 1611 } 1612 } else if (strcmp(module_name, filename) != 0) { 1613 fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename); 1614 } 1615 1616 retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext); 1617 1618 cleanup: 1619 if (data_len > 0) munmap(data, data_len); 1620 free(module_name); 1621 free(path); 1622 1623 return retval; 1624 } 1625 1626 static int semanage_direct_extract(semanage_handle_t * sh, 1627 semanage_module_key_t *modkey, 1628 int extract_cil, 1629 void **mapped_data, 1630 size_t *data_len, 1631 semanage_module_info_t **modinfo) 1632 { 1633 char module_path[PATH_MAX]; 1634 char input_file[PATH_MAX]; 1635 enum semanage_module_path_type file_type; 1636 int rc = -1; 1637 semanage_module_info_t *_modinfo = NULL; 1638 ssize_t _data_len; 1639 char *_data; 1640 int compressed; 1641 1642 /* get path of module */ 1643 rc = semanage_module_get_path( 1644 sh, 1645 (const semanage_module_info_t *)modkey, 1646 SEMANAGE_MODULE_PATH_NAME, 1647 module_path, 1648 sizeof(module_path)); 1649 if (rc != 0) { 1650 goto cleanup; 1651 } 1652 1653 if (access(module_path, F_OK) != 0) { 1654 ERR(sh, "Module does not exist: %s", module_path); 1655 rc = -1; 1656 goto cleanup; 1657 } 1658 1659 rc = semanage_module_get_module_info(sh, 1660 modkey, 1661 &_modinfo); 1662 if (rc != 0) { 1663 goto cleanup; 1664 } 1665 1666 if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) { 1667 file_type = SEMANAGE_MODULE_PATH_CIL; 1668 } else { 1669 file_type = SEMANAGE_MODULE_PATH_HLL; 1670 } 1671 1672 /* get path of what to extract */ 1673 rc = semanage_module_get_path( 1674 sh, 1675 _modinfo, 1676 file_type, 1677 input_file, 1678 sizeof(input_file)); 1679 if (rc != 0) { 1680 goto cleanup; 1681 } 1682 1683 if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && access(input_file, F_OK) != 0) { 1684 rc = semanage_compile_module(sh, _modinfo); 1685 if (rc < 0) { 1686 goto cleanup; 1687 } 1688 } 1689 1690 _data_len = map_file(sh, input_file, &_data, &compressed); 1691 if (_data_len <= 0) { 1692 ERR(sh, "Error mapping file: %s", input_file); 1693 rc = -1; 1694 goto cleanup; 1695 } 1696 1697 *modinfo = _modinfo; 1698 *data_len = (size_t)_data_len; 1699 *mapped_data = _data; 1700 1701 cleanup: 1702 if (rc != 0) { 1703 semanage_module_info_destroy(sh, _modinfo); 1704 free(_modinfo); 1705 } 1706 1707 return rc; 1708 } 1709 1710 /* Removes a module from the sandbox. Returns 0 on success, -1 if out 1711 * of memory, -2 if module not found or could not be removed. */ 1712 static int semanage_direct_remove(semanage_handle_t * sh, char *module_name) 1713 { 1714 int status = 0; 1715 int ret = 0; 1716 1717 semanage_module_key_t modkey; 1718 ret = semanage_module_key_init(sh, &modkey); 1719 if (ret != 0) { 1720 status = -1; 1721 goto cleanup; 1722 } 1723 1724 ret = semanage_module_key_set_priority(sh, &modkey, sh->priority); 1725 if (ret != 0) { 1726 status = -1; 1727 goto cleanup; 1728 } 1729 1730 ret = semanage_module_key_set_name(sh, &modkey, module_name); 1731 if (ret != 0) { 1732 status = -1; 1733 goto cleanup; 1734 } 1735 1736 status = semanage_direct_remove_key(sh, &modkey); 1737 1738 cleanup: 1739 return status; 1740 } 1741 1742 /* Allocate an array of module_info structures for each readable 1743 * module within the store. Note that if the calling program has 1744 * already begun a transaction then this function will get a list of 1745 * modules within the sandbox. The caller is responsible for calling 1746 * semanage_module_info_datum_destroy() on each element of the array 1747 * as well as free()ing the entire list. 1748 */ 1749 static int semanage_direct_list(semanage_handle_t * sh, 1750 semanage_module_info_t ** modinfo, 1751 int *num_modules) 1752 { 1753 int i, retval = -1; 1754 *modinfo = NULL; 1755 *num_modules = 0; 1756 1757 /* get the read lock when reading from the active 1758 (non-transaction) directory */ 1759 if (!sh->is_in_transaction) 1760 if (semanage_get_active_lock(sh) < 0) 1761 return -1; 1762 1763 if (semanage_get_active_modules(sh, modinfo, num_modules) == -1) { 1764 goto cleanup; 1765 } 1766 1767 if (num_modules == 0) { 1768 retval = semanage_direct_get_serial(sh); 1769 goto cleanup; 1770 } 1771 1772 retval = semanage_direct_get_serial(sh); 1773 1774 cleanup: 1775 if (retval < 0) { 1776 for (i = 0; i < *num_modules; i++) { 1777 semanage_module_info_destroy(sh, &(*modinfo[i])); 1778 modinfo[i] = NULL; 1779 } 1780 free(*modinfo); 1781 *modinfo = NULL; 1782 } 1783 1784 if (!sh->is_in_transaction) { 1785 semanage_release_active_lock(sh); 1786 } 1787 return retval; 1788 } 1789 1790 static int semanage_direct_get_enabled(semanage_handle_t *sh, 1791 const semanage_module_key_t *modkey, 1792 int *enabled) 1793 { 1794 assert(sh); 1795 assert(modkey); 1796 assert(enabled); 1797 1798 int status = 0; 1799 int ret = 0; 1800 1801 char path[PATH_MAX]; 1802 struct stat sb; 1803 semanage_module_info_t *modinfo = NULL; 1804 1805 /* get module info */ 1806 ret = semanage_module_get_module_info( 1807 sh, 1808 modkey, 1809 &modinfo); 1810 if (ret != 0) { 1811 status = -1; 1812 goto cleanup; 1813 } 1814 1815 /* get disabled file path */ 1816 ret = semanage_module_get_path( 1817 sh, 1818 modinfo, 1819 SEMANAGE_MODULE_PATH_DISABLED, 1820 path, 1821 sizeof(path)); 1822 if (ret != 0) { 1823 status = -1; 1824 goto cleanup; 1825 } 1826 1827 if (stat(path, &sb) < 0) { 1828 *enabled = 1; 1829 } 1830 else { 1831 *enabled = 0; 1832 } 1833 1834 cleanup: 1835 semanage_module_info_destroy(sh, modinfo); 1836 free(modinfo); 1837 1838 return status; 1839 } 1840 1841 static int semanage_direct_set_enabled(semanage_handle_t *sh, 1842 const semanage_module_key_t *modkey, 1843 int enabled) 1844 { 1845 assert(sh); 1846 assert(modkey); 1847 1848 int status = 0; 1849 int ret = 0; 1850 1851 char fn[PATH_MAX]; 1852 const char *path = NULL; 1853 FILE *fp = NULL; 1854 semanage_module_info_t *modinfo = NULL; 1855 1856 /* check transaction */ 1857 if (!sh->is_in_transaction) { 1858 if (semanage_begin_transaction(sh) < 0) { 1859 status = -1; 1860 goto cleanup; 1861 } 1862 } 1863 1864 /* validate name */ 1865 ret = semanage_module_validate_name(modkey->name); 1866 if (ret != 0) { 1867 errno = 0; 1868 ERR(sh, "Name %s is invalid.", modkey->name); 1869 status = -1; 1870 goto cleanup; 1871 } 1872 1873 /* validate enabled */ 1874 ret = semanage_module_validate_enabled(enabled); 1875 if (ret != 0) { 1876 errno = 0; 1877 ERR(sh, "Enabled status %d is invalid.", enabled); 1878 status = -1; 1879 goto cleanup; 1880 } 1881 1882 /* check for disabled path, create if missing */ 1883 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); 1884 1885 ret = semanage_mkdir(sh, path); 1886 if (ret != 0) { 1887 status = -1; 1888 goto cleanup; 1889 } 1890 1891 /* get module info */ 1892 ret = semanage_module_get_module_info( 1893 sh, 1894 modkey, 1895 &modinfo); 1896 if (ret != 0) { 1897 status = -1; 1898 goto cleanup; 1899 } 1900 1901 /* get module disabled file */ 1902 ret = semanage_module_get_path( 1903 sh, 1904 modinfo, 1905 SEMANAGE_MODULE_PATH_DISABLED, 1906 fn, 1907 sizeof(fn)); 1908 if (ret != 0) { 1909 status = -1; 1910 goto cleanup; 1911 } 1912 1913 switch (enabled) { 1914 case 0: /* disable the module */ 1915 fp = fopen(fn, "w"); 1916 1917 if (fp == NULL) { 1918 ERR(sh, 1919 "Unable to disable module %s", 1920 modkey->name); 1921 status = -1; 1922 goto cleanup; 1923 } 1924 1925 if (fclose(fp) != 0) { 1926 ERR(sh, 1927 "Unable to close disabled file for module %s", 1928 modkey->name); 1929 status = -1; 1930 goto cleanup; 1931 } 1932 1933 fp = NULL; 1934 1935 break; 1936 case 1: /* enable the module */ 1937 if (unlink(fn) < 0) { 1938 if (errno != ENOENT) { 1939 ERR(sh, 1940 "Unable to enable module %s", 1941 modkey->name); 1942 status = -1; 1943 goto cleanup; 1944 } 1945 else { 1946 /* module already enabled */ 1947 errno = 0; 1948 } 1949 } 1950 1951 break; 1952 case -1: /* warn about ignored setting to default */ 1953 WARN(sh, 1954 "Setting module %s to 'default' state has no effect", 1955 modkey->name); 1956 break; 1957 } 1958 1959 cleanup: 1960 semanage_module_info_destroy(sh, modinfo); 1961 free(modinfo); 1962 1963 if (fp != NULL) fclose(fp); 1964 return status; 1965 } 1966 1967 int semanage_direct_access_check(semanage_handle_t * sh) 1968 { 1969 if (semanage_check_init(sh, sh->conf->store_root_path)) 1970 return -1; 1971 1972 return semanage_store_access_check(); 1973 } 1974 1975 int semanage_direct_mls_enabled(semanage_handle_t * sh) 1976 { 1977 sepol_policydb_t *p = NULL; 1978 int retval; 1979 1980 retval = sepol_policydb_create(&p); 1981 if (retval < 0) 1982 goto cleanup; 1983 1984 retval = semanage_read_policydb(sh, p); 1985 if (retval < 0) 1986 goto cleanup; 1987 1988 retval = sepol_policydb_mls_enabled(p); 1989 cleanup: 1990 sepol_policydb_free(p); 1991 return retval; 1992 } 1993 1994 static int semanage_direct_get_module_info(semanage_handle_t *sh, 1995 const semanage_module_key_t *modkey, 1996 semanage_module_info_t **modinfo) 1997 { 1998 assert(sh); 1999 assert(modkey); 2000 assert(modinfo); 2001 2002 int status = 0; 2003 int ret = 0; 2004 2005 char fn[PATH_MAX]; 2006 FILE *fp = NULL; 2007 size_t size = 0; 2008 struct stat sb; 2009 char *tmp = NULL; 2010 2011 int i = 0; 2012 2013 semanage_module_info_t *modinfos = NULL; 2014 int modinfos_len = 0; 2015 semanage_module_info_t *highest = NULL; 2016 2017 /* check module name */ 2018 ret = semanage_module_validate_name(modkey->name); 2019 if (ret < 0) { 2020 errno = 0; 2021 ERR(sh, "Name %s is invalid.", modkey->name); 2022 status = -1; 2023 goto cleanup; 2024 } 2025 2026 /* if priority == 0, then find the highest priority available */ 2027 if (modkey->priority == 0) { 2028 ret = semanage_direct_list_all(sh, &modinfos, &modinfos_len); 2029 if (ret != 0) { 2030 status = -1; 2031 goto cleanup; 2032 } 2033 2034 for (i = 0; i < modinfos_len; i++) { 2035 ret = strcmp(modinfos[i].name, modkey->name); 2036 if (ret == 0) { 2037 highest = &modinfos[i]; 2038 break; 2039 } 2040 } 2041 2042 if (highest == NULL) { 2043 status = -1; 2044 goto cleanup; 2045 } 2046 2047 ret = semanage_module_info_create(sh, modinfo); 2048 if (ret != 0) { 2049 status = -1; 2050 goto cleanup; 2051 } 2052 2053 ret = semanage_module_info_clone(sh, highest, *modinfo); 2054 if (ret != 0) { 2055 status = -1; 2056 } 2057 2058 /* skip to cleanup, module was found */ 2059 goto cleanup; 2060 } 2061 2062 /* check module priority */ 2063 ret = semanage_module_validate_priority(modkey->priority); 2064 if (ret != 0) { 2065 errno = 0; 2066 ERR(sh, "Priority %d is invalid.", modkey->priority); 2067 status = -1; 2068 goto cleanup; 2069 } 2070 2071 /* copy in key values */ 2072 ret = semanage_module_info_create(sh, modinfo); 2073 if (ret != 0) { 2074 status = -1; 2075 goto cleanup; 2076 } 2077 2078 ret = semanage_module_info_set_priority(sh, *modinfo, modkey->priority); 2079 if (ret != 0) { 2080 status = -1; 2081 goto cleanup; 2082 } 2083 2084 ret = semanage_module_info_set_name(sh, *modinfo, modkey->name); 2085 if (ret != 0) { 2086 status = -1; 2087 goto cleanup; 2088 } 2089 2090 /* lookup module ext */ 2091 ret = semanage_module_get_path(sh, 2092 *modinfo, 2093 SEMANAGE_MODULE_PATH_LANG_EXT, 2094 fn, 2095 sizeof(fn)); 2096 if (ret != 0) { 2097 status = -1; 2098 goto cleanup; 2099 } 2100 2101 fp = fopen(fn, "r"); 2102 2103 if (fp == NULL) { 2104 ERR(sh, 2105 "Unable to open %s module lang ext file at %s.", 2106 (*modinfo)->name, fn); 2107 status = -1; 2108 goto cleanup; 2109 } 2110 2111 /* set module ext */ 2112 if (getline(&tmp, &size, fp) < 0) { 2113 ERR(sh, 2114 "Unable to read %s module lang ext file.", 2115 (*modinfo)->name); 2116 status = -1; 2117 goto cleanup; 2118 } 2119 2120 ret = semanage_module_info_set_lang_ext(sh, *modinfo, tmp); 2121 if (ret != 0) { 2122 status = -1; 2123 goto cleanup; 2124 } 2125 free(tmp); 2126 tmp = NULL; 2127 2128 if (fclose(fp) != 0) { 2129 ERR(sh, 2130 "Unable to close %s module lang ext file.", 2131 (*modinfo)->name); 2132 status = -1; 2133 goto cleanup; 2134 } 2135 2136 fp = NULL; 2137 2138 /* lookup enabled/disabled status */ 2139 ret = semanage_module_get_path(sh, 2140 *modinfo, 2141 SEMANAGE_MODULE_PATH_DISABLED, 2142 fn, 2143 sizeof(fn)); 2144 if (ret != 0) { 2145 status = -1; 2146 goto cleanup; 2147 } 2148 2149 /* set enabled/disabled status */ 2150 if (stat(fn, &sb) < 0) { 2151 ret = semanage_module_info_set_enabled(sh, *modinfo, 1); 2152 if (ret != 0) { 2153 status = -1; 2154 goto cleanup; 2155 } 2156 } 2157 else { 2158 ret = semanage_module_info_set_enabled(sh, *modinfo, 0); 2159 if (ret != 0) { 2160 status = -1; 2161 goto cleanup; 2162 } 2163 } 2164 2165 cleanup: 2166 free(tmp); 2167 2168 if (modinfos != NULL) { 2169 for (i = 0; i < modinfos_len; i++) { 2170 semanage_module_info_destroy(sh, &modinfos[i]); 2171 } 2172 free(modinfos); 2173 } 2174 2175 if (fp != NULL) fclose(fp); 2176 return status; 2177 } 2178 2179 static int semanage_direct_set_module_info(semanage_handle_t *sh, 2180 const semanage_module_info_t *modinfo) 2181 { 2182 int status = 0; 2183 int ret = 0; 2184 2185 char fn[PATH_MAX]; 2186 const char *path = NULL; 2187 int enabled = 0; 2188 semanage_module_info_t *modinfo_tmp = NULL; 2189 2190 semanage_module_key_t modkey; 2191 ret = semanage_module_key_init(sh, &modkey); 2192 if (ret != 0) { 2193 status = -1; 2194 goto cleanup; 2195 } 2196 2197 /* check transaction */ 2198 if (!sh->is_in_transaction) { 2199 if (semanage_begin_transaction(sh) < 0) { 2200 status = -1; 2201 goto cleanup; 2202 } 2203 } 2204 2205 /* validate module */ 2206 ret = semanage_module_info_validate(modinfo); 2207 if (ret != 0) { 2208 status = -1; 2209 goto cleanup; 2210 } 2211 2212 sh->modules_modified = 1; 2213 2214 /* check for modules path, create if missing */ 2215 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); 2216 2217 ret = semanage_mkdir(sh, path); 2218 if (ret != 0) { 2219 status = -1; 2220 goto cleanup; 2221 } 2222 2223 /* write priority */ 2224 ret = semanage_module_get_path(sh, 2225 modinfo, 2226 SEMANAGE_MODULE_PATH_PRIORITY, 2227 fn, 2228 sizeof(fn)); 2229 if (ret != 0) { 2230 status = -1; 2231 goto cleanup; 2232 } 2233 2234 ret = semanage_mkdir(sh, fn); 2235 if (ret != 0) { 2236 status = -1; 2237 goto cleanup; 2238 } 2239 2240 /* write name */ 2241 ret = semanage_module_get_path(sh, 2242 modinfo, 2243 SEMANAGE_MODULE_PATH_NAME, 2244 fn, 2245 sizeof(fn)); 2246 if (ret != 0) { 2247 status = -1; 2248 goto cleanup; 2249 } 2250 2251 ret = semanage_mkdir(sh, fn); 2252 if (ret != 0) { 2253 status = -1; 2254 goto cleanup; 2255 } 2256 2257 /* write ext */ 2258 ret = semanage_direct_write_langext(sh, modinfo->lang_ext, modinfo); 2259 if (ret != 0) { 2260 status = -1; 2261 goto cleanup; 2262 } 2263 2264 /* write enabled/disabled status */ 2265 2266 /* check for disabled path, create if missing */ 2267 path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_DISABLED); 2268 2269 ret = semanage_mkdir(sh, path); 2270 if (ret != 0) { 2271 status = -1; 2272 goto cleanup; 2273 } 2274 2275 ret = semanage_module_get_path(sh, 2276 modinfo, 2277 SEMANAGE_MODULE_PATH_DISABLED, 2278 fn, 2279 sizeof(fn)); 2280 if (ret != 0) { 2281 status = -1; 2282 goto cleanup; 2283 } 2284 2285 ret = semanage_module_key_set_name(sh, &modkey, modinfo->name); 2286 if (ret != 0) { 2287 status = -1; 2288 goto cleanup; 2289 } 2290 2291 if (modinfo->enabled == -1) { 2292 /* default to enabled */ 2293 enabled = 1; 2294 2295 /* check if a module is already installed */ 2296 ret = semanage_module_get_module_info(sh, 2297 &modkey, 2298 &modinfo_tmp); 2299 if (ret == 0) { 2300 /* set enabled status to current one */ 2301 enabled = modinfo_tmp->enabled; 2302 } 2303 } 2304 else { 2305 enabled = modinfo->enabled; 2306 } 2307 2308 ret = semanage_module_set_enabled(sh, &modkey, enabled); 2309 if (ret != 0) { 2310 status = -1; 2311 goto cleanup; 2312 } 2313 2314 cleanup: 2315 semanage_module_key_destroy(sh, &modkey); 2316 2317 semanage_module_info_destroy(sh, modinfo_tmp); 2318 free(modinfo_tmp); 2319 2320 return status; 2321 } 2322 2323 static int semanage_priorities_filename_select(const struct dirent *d) 2324 { 2325 if (d->d_name[0] == '.' || 2326 strcmp(d->d_name, "disabled") == 0) 2327 return 0; 2328 return 1; 2329 } 2330 2331 static int semanage_modules_filename_select(const struct dirent *d) 2332 { 2333 if (d->d_name[0] == '.') 2334 return 0; 2335 return 1; 2336 } 2337 2338 static int semanage_direct_list_all(semanage_handle_t *sh, 2339 semanage_module_info_t **modinfos, 2340 int *modinfos_len) 2341 { 2342 assert(sh); 2343 assert(modinfos); 2344 assert(modinfos_len); 2345 2346 int status = 0; 2347 int ret = 0; 2348 2349 int i = 0; 2350 int j = 0; 2351 2352 *modinfos = NULL; 2353 *modinfos_len = 0; 2354 void *tmp = NULL; 2355 2356 const char *toplevel = NULL; 2357 2358 struct dirent **priorities = NULL; 2359 int priorities_len = 0; 2360 char priority_path[PATH_MAX]; 2361 2362 struct dirent **modules = NULL; 2363 int modules_len = 0; 2364 2365 uint16_t priority = 0; 2366 2367 semanage_module_info_t *modinfo_tmp = NULL; 2368 2369 semanage_module_info_t modinfo; 2370 ret = semanage_module_info_init(sh, &modinfo); 2371 if (ret != 0) { 2372 status = -1; 2373 goto cleanup; 2374 } 2375 2376 if (sh->is_in_transaction) { 2377 toplevel = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES); 2378 } else { 2379 toplevel = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES); 2380 } 2381 2382 /* find priorities */ 2383 priorities_len = scandir(toplevel, 2384 &priorities, 2385 semanage_priorities_filename_select, 2386 versionsort); 2387 if (priorities_len == -1) { 2388 ERR(sh, "Error while scanning directory %s.", toplevel); 2389 status = -1; 2390 goto cleanup; 2391 } 2392 2393 /* for each priority directory */ 2394 /* loop through in reverse so that highest priority is first */ 2395 for (i = priorities_len - 1; i >= 0; i--) { 2396 /* convert priority string to uint16_t */ 2397 ret = semanage_string_to_priority(priorities[i]->d_name, 2398 &priority); 2399 if (ret != 0) { 2400 status = -1; 2401 goto cleanup; 2402 } 2403 2404 /* set our priority */ 2405 ret = semanage_module_info_set_priority(sh, 2406 &modinfo, 2407 priority); 2408 if (ret != 0) { 2409 status = -1; 2410 goto cleanup; 2411 } 2412 2413 /* get the priority path */ 2414 ret = semanage_module_get_path(sh, 2415 &modinfo, 2416 SEMANAGE_MODULE_PATH_PRIORITY, 2417 priority_path, 2418 sizeof(priority_path)); 2419 if (ret != 0) { 2420 status = -1; 2421 goto cleanup; 2422 } 2423 2424 /* cleanup old modules */ 2425 if (modules != NULL) { 2426 for (j = 0; j < modules_len; j++) { 2427 free(modules[j]); 2428 modules[j] = NULL; 2429 } 2430 free(modules); 2431 modules = NULL; 2432 modules_len = 0; 2433 } 2434 2435 /* find modules at this priority */ 2436 modules_len = scandir(priority_path, 2437 &modules, 2438 semanage_modules_filename_select, 2439 versionsort); 2440 if (modules_len == -1) { 2441 ERR(sh, 2442 "Error while scanning directory %s.", 2443 priority_path); 2444 status = -1; 2445 goto cleanup; 2446 } 2447 2448 if (modules_len == 0) continue; 2449 2450 /* add space for modules */ 2451 tmp = realloc(*modinfos, 2452 sizeof(semanage_module_info_t) * 2453 (*modinfos_len + modules_len)); 2454 if (tmp == NULL) { 2455 ERR(sh, "Error allocating memory for module array."); 2456 status = -1; 2457 goto cleanup; 2458 } 2459 *modinfos = tmp; 2460 2461 /* for each module directory */ 2462 for(j = 0; j < modules_len; j++) { 2463 /* set module name */ 2464 ret = semanage_module_info_set_name( 2465 sh, 2466 &modinfo, 2467 modules[j]->d_name); 2468 if (ret != 0) { 2469 status = -1; 2470 goto cleanup; 2471 } 2472 2473 /* get module values */ 2474 ret = semanage_direct_get_module_info( 2475 sh, 2476 (const semanage_module_key_t *) 2477 (&modinfo), 2478 &modinfo_tmp); 2479 if (ret != 0) { 2480 status = -1; 2481 goto cleanup; 2482 } 2483 2484 /* copy into array */ 2485 ret = semanage_module_info_init( 2486 sh, 2487 &((*modinfos)[*modinfos_len])); 2488 if (ret != 0) { 2489 status = -1; 2490 goto cleanup; 2491 } 2492 2493 ret = semanage_module_info_clone( 2494 sh, 2495 modinfo_tmp, 2496 &((*modinfos)[*modinfos_len])); 2497 if (ret != 0) { 2498 status = -1; 2499 goto cleanup; 2500 } 2501 2502 ret = semanage_module_info_destroy(sh, modinfo_tmp); 2503 if (ret != 0) { 2504 status = -1; 2505 goto cleanup; 2506 } 2507 free(modinfo_tmp); 2508 modinfo_tmp = NULL; 2509 2510 *modinfos_len += 1; 2511 } 2512 } 2513 2514 cleanup: 2515 semanage_module_info_destroy(sh, &modinfo); 2516 2517 if (priorities != NULL) { 2518 for (i = 0; i < priorities_len; i++) { 2519 free(priorities[i]); 2520 } 2521 free(priorities); 2522 } 2523 2524 if (modules != NULL) { 2525 for (i = 0; i < modules_len; i++) { 2526 free(modules[i]); 2527 } 2528 free(modules); 2529 } 2530 2531 ret = semanage_module_info_destroy(sh, modinfo_tmp); 2532 if (ret != 0) { 2533 status = -1; 2534 goto cleanup; 2535 } 2536 free(modinfo_tmp); 2537 modinfo_tmp = NULL; 2538 2539 if (status != 0) { 2540 if (modinfos != NULL) { 2541 for (i = 0; i < *modinfos_len; i++) { 2542 semanage_module_info_destroy( 2543 sh, 2544 &(*modinfos)[i]); 2545 } 2546 free(*modinfos); 2547 *modinfos = NULL; 2548 *modinfos_len = 0; 2549 } 2550 } 2551 2552 return status; 2553 } 2554 2555 static int semanage_direct_install_info(semanage_handle_t *sh, 2556 const semanage_module_info_t *modinfo, 2557 char *data, 2558 size_t data_len) 2559 { 2560 assert(sh); 2561 assert(modinfo); 2562 assert(data); 2563 2564 int status = 0; 2565 int ret = 0; 2566 int type; 2567 2568 char path[PATH_MAX]; 2569 2570 semanage_module_info_t *higher_info = NULL; 2571 semanage_module_key_t higher_key; 2572 ret = semanage_module_key_init(sh, &higher_key); 2573 if (ret != 0) { 2574 status = -1; 2575 goto cleanup; 2576 } 2577 2578 /* validate module info */ 2579 ret = semanage_module_info_validate(modinfo); 2580 if (ret != 0) { 2581 ERR(sh, "%s failed module validation.\n", modinfo->name); 2582 status = -2; 2583 goto cleanup; 2584 } 2585 2586 /* Check for higher priority module and warn if there is one as 2587 * it will override the module currently being installed. 2588 */ 2589 ret = semanage_module_key_set_name(sh, &higher_key, modinfo->name); 2590 if (ret != 0) { 2591 status = -1; 2592 goto cleanup; 2593 } 2594 2595 ret = semanage_direct_get_module_info(sh, &higher_key, &higher_info); 2596 if (ret == 0) { 2597 if (higher_info->priority > modinfo->priority) { 2598 errno = 0; 2599 WARN(sh, 2600 "A higher priority %s module exists at priority %d and will override the module currently being installed at priority %d.", 2601 modinfo->name, 2602 higher_info->priority, 2603 modinfo->priority); 2604 } 2605 else if (higher_info->priority < modinfo->priority) { 2606 errno = 0; 2607 INFO(sh, 2608 "Overriding %s module at lower priority %d with module at priority %d.", 2609 modinfo->name, 2610 higher_info->priority, 2611 modinfo->priority); 2612 } 2613 2614 if (higher_info->enabled == 0 && modinfo->enabled == -1) { 2615 errno = 0; 2616 WARN(sh, 2617 "%s module will be disabled after install due to default enabled status.", 2618 modinfo->name); 2619 } 2620 } 2621 2622 /* set module meta data */ 2623 ret = semanage_direct_set_module_info(sh, modinfo); 2624 if (ret != 0) { 2625 status = -2; 2626 goto cleanup; 2627 } 2628 2629 /* install module source file */ 2630 if (!strcasecmp(modinfo->lang_ext, "cil")) { 2631 type = SEMANAGE_MODULE_PATH_CIL; 2632 } else { 2633 type = SEMANAGE_MODULE_PATH_HLL; 2634 } 2635 ret = semanage_module_get_path( 2636 sh, 2637 modinfo, 2638 type, 2639 path, 2640 sizeof(path)); 2641 if (ret != 0) { 2642 status = -3; 2643 goto cleanup; 2644 } 2645 2646 ret = bzip(sh, path, data, data_len); 2647 if (ret <= 0) { 2648 ERR(sh, "Error while writing to %s.", path); 2649 status = -3; 2650 goto cleanup; 2651 } 2652 2653 /* if this is an HLL, delete the CIL cache if it exists so it will get recompiled */ 2654 if (type == SEMANAGE_MODULE_PATH_HLL) { 2655 ret = semanage_module_get_path( 2656 sh, 2657 modinfo, 2658 SEMANAGE_MODULE_PATH_CIL, 2659 path, 2660 sizeof(path)); 2661 if (ret != 0) { 2662 status = -3; 2663 goto cleanup; 2664 } 2665 2666 if (access(path, F_OK) == 0) { 2667 ret = unlink(path); 2668 if (ret != 0) { 2669 ERR(sh, "Error while removing cached CIL file %s: %s", path, strerror(errno)); 2670 status = -3; 2671 goto cleanup; 2672 } 2673 } 2674 } 2675 2676 cleanup: 2677 semanage_module_key_destroy(sh, &higher_key); 2678 semanage_module_info_destroy(sh, higher_info); 2679 free(higher_info); 2680 2681 return status; 2682 } 2683 2684 static int semanage_direct_remove_key(semanage_handle_t *sh, 2685 const semanage_module_key_t *modkey) 2686 { 2687 assert(sh); 2688 assert(modkey); 2689 2690 int status = 0; 2691 int ret = 0; 2692 2693 char path[PATH_MAX]; 2694 semanage_module_info_t *modinfo = NULL; 2695 2696 semanage_module_key_t modkey_tmp; 2697 ret = semanage_module_key_init(sh, &modkey_tmp); 2698 if (ret != 0) { 2699 status = -1; 2700 goto cleanup; 2701 } 2702 2703 /* validate module key */ 2704 ret = semanage_module_validate_priority(modkey->priority); 2705 if (ret != 0) { 2706 errno = 0; 2707 ERR(sh, "Priority %d is invalid.", modkey->priority); 2708 status = -1; 2709 goto cleanup; 2710 } 2711 2712 ret = semanage_module_validate_name(modkey->name); 2713 if (ret != 0) { 2714 errno = 0; 2715 ERR(sh, "Name %s is invalid.", modkey->name); 2716 status = -1; 2717 goto cleanup; 2718 } 2719 2720 ret = semanage_module_key_set_name(sh, &modkey_tmp, modkey->name); 2721 if (ret != 0) { 2722 status = -1; 2723 goto cleanup; 2724 } 2725 2726 /* get module path */ 2727 ret = semanage_module_get_path( 2728 sh, 2729 (const semanage_module_info_t *)modkey, 2730 SEMANAGE_MODULE_PATH_NAME, 2731 path, 2732 sizeof(path)); 2733 if (ret != 0) { 2734 status = -2; 2735 goto cleanup; 2736 } 2737 2738 /* remove directory */ 2739 ret = semanage_remove_directory(path); 2740 if (ret != 0) { 2741 ERR(sh, "Unable to remove module %s at priority %d.", modkey->name, modkey->priority); 2742 status = -2; 2743 goto cleanup; 2744 } 2745 2746 /* check if its the last module at any priority */ 2747 ret = semanage_module_get_module_info(sh, &modkey_tmp, &modinfo); 2748 if (ret != 0) { 2749 /* info that no other module will override */ 2750 errno = 0; 2751 INFO(sh, 2752 "Removing last %s module (no other %s module exists at another priority).", 2753 modkey->name, 2754 modkey->name); 2755 2756 /* remove disabled status file */ 2757 ret = semanage_module_get_path( 2758 sh, 2759 (const semanage_module_info_t *)modkey, 2760 SEMANAGE_MODULE_PATH_DISABLED, 2761 path, 2762 sizeof(path)); 2763 if (ret != 0) { 2764 status = -1; 2765 goto cleanup; 2766 } 2767 2768 struct stat sb; 2769 if (stat(path, &sb) == 0) { 2770 ret = unlink(path); 2771 if (ret != 0) { 2772 status = -1; 2773 goto cleanup; 2774 } 2775 } 2776 } 2777 else { 2778 /* if a lower priority module is going to become active */ 2779 if (modkey->priority > modinfo->priority) { 2780 /* inform what the new active module will be */ 2781 errno = 0; 2782 INFO(sh, 2783 "%s module at priority %d is now active.", 2784 modinfo->name, 2785 modinfo->priority); 2786 } 2787 } 2788 2789 cleanup: 2790 semanage_module_key_destroy(sh, &modkey_tmp); 2791 2792 semanage_module_info_destroy(sh, modinfo); 2793 free(modinfo); 2794 2795 return status; 2796 } 2797 2798