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