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