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