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