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