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