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