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