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