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