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