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