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