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