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