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