direct_api.c revision 654dcb897e49908a958dae55cf29793412c4b390
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 <selinux/selinux.h>
25
26#include <assert.h>
27#include <fcntl.h>
28#include <stdio.h>
29#include <stdio_ext.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <limits.h>
36#include <errno.h>
37
38#include "user_internal.h"
39#include "seuser_internal.h"
40#include "port_internal.h"
41#include "iface_internal.h"
42#include "boolean_internal.h"
43#include "fcontext_internal.h"
44#include "node_internal.h"
45#include "genhomedircon.h"
46
47#include "debug.h"
48#include "handle.h"
49#include "modules.h"
50#include "direct_api.h"
51#include "semanage_store.h"
52#include "database_policydb.h"
53#include "policy.h"
54#include <sys/mman.h>
55
56static void semanage_direct_destroy(semanage_handle_t * sh);
57static int semanage_direct_disconnect(semanage_handle_t * sh);
58static int semanage_direct_begintrans(semanage_handle_t * sh);
59static int semanage_direct_commit(semanage_handle_t * sh);
60static int semanage_direct_install(semanage_handle_t * sh, char *data,
61				   size_t data_len);
62static int semanage_direct_install_file(semanage_handle_t * sh, const char *module_name);
63static int semanage_direct_upgrade(semanage_handle_t * sh, char *data,
64				   size_t data_len);
65static int semanage_direct_upgrade_file(semanage_handle_t * sh, const char *module_name);
66static int semanage_direct_install_base(semanage_handle_t * sh, char *base_data,
67					size_t data_len);
68static int semanage_direct_install_base_file(semanage_handle_t * sh, const char *module_name);
69static int semanage_direct_enable(semanage_handle_t * sh, char *module_name);
70static int semanage_direct_disable(semanage_handle_t * sh, char *module_name);
71static int semanage_direct_remove(semanage_handle_t * sh, char *module_name);
72static int semanage_direct_list(semanage_handle_t * sh,
73				semanage_module_info_t ** modinfo,
74				int *num_modules);
75
76static struct semanage_policy_table direct_funcs = {
77	.get_serial = semanage_direct_get_serial,
78	.destroy = semanage_direct_destroy,
79	.disconnect = semanage_direct_disconnect,
80	.begin_trans = semanage_direct_begintrans,
81	.commit = semanage_direct_commit,
82	.install = semanage_direct_install,
83	.install_file = semanage_direct_install_file,
84	.upgrade = semanage_direct_upgrade,
85	.upgrade_file = semanage_direct_upgrade_file,
86	.install_base = semanage_direct_install_base,
87	.install_base_file = semanage_direct_install_base_file,
88	.enable = semanage_direct_enable,
89	.disable = semanage_direct_disable,
90	.remove = semanage_direct_remove,
91	.list = semanage_direct_list
92};
93
94int semanage_direct_is_managed(semanage_handle_t * sh)
95{
96	char polpath[PATH_MAX];
97
98	snprintf(polpath, PATH_MAX, "%s%s", selinux_path(),
99		 sh->conf->store_path);
100
101	if (semanage_check_init(polpath))
102		goto err;
103
104	if (semanage_access_check(sh) < 0)
105		return 0;
106
107	return 1;
108
109      err:
110	ERR(sh, "could not check whether policy is managed");
111	return STATUS_ERR;
112}
113
114/* Check that the module store exists, creating it if necessary.
115 */
116int semanage_direct_connect(semanage_handle_t * sh)
117{
118	char polpath[PATH_MAX];
119	const char *path;
120
121	snprintf(polpath, PATH_MAX, "%s%s", selinux_path(),
122		 sh->conf->store_path);
123
124	if (semanage_check_init(polpath))
125		goto err;
126
127	if (sh->create_store)
128		if (semanage_create_store(sh, 1))
129			goto err;
130
131	if (semanage_access_check(sh) < SEMANAGE_CAN_READ)
132		goto err;
133
134	sh->u.direct.translock_file_fd = -1;
135	sh->u.direct.activelock_file_fd = -1;
136
137	/* set up function pointers */
138	sh->funcs = &direct_funcs;
139
140	/* Object databases: local modifications */
141	if (user_base_file_dbase_init(sh,
142				      semanage_fname(SEMANAGE_USERS_BASE_LOCAL),
143				      semanage_user_base_dbase_local(sh)) < 0)
144		goto err;
145
146	if (user_extra_file_dbase_init(sh,
147				       semanage_fname
148				       (SEMANAGE_USERS_EXTRA_LOCAL),
149				       semanage_user_extra_dbase_local(sh)) < 0)
150		goto err;
151
152	if (user_join_dbase_init(sh,
153				 semanage_user_base_dbase_local(sh),
154				 semanage_user_extra_dbase_local(sh),
155				 semanage_user_dbase_local(sh)) < 0)
156		goto err;
157
158	if (port_file_dbase_init(sh,
159				 semanage_fname(SEMANAGE_PORTS_LOCAL),
160				 semanage_port_dbase_local(sh)) < 0)
161		goto err;
162
163	if (iface_file_dbase_init(sh,
164				  semanage_fname(SEMANAGE_INTERFACES_LOCAL),
165				  semanage_iface_dbase_local(sh)) < 0)
166		goto err;
167
168	if (bool_file_dbase_init(sh,
169				 semanage_fname(SEMANAGE_BOOLEANS_LOCAL),
170				 semanage_bool_dbase_local(sh)) < 0)
171		goto err;
172
173	if (fcontext_file_dbase_init(sh,
174				     semanage_fname(SEMANAGE_FC_LOCAL),
175				     semanage_fcontext_dbase_local(sh)) < 0)
176		goto err;
177
178	if (seuser_file_dbase_init(sh,
179				   semanage_fname(SEMANAGE_SEUSERS_LOCAL),
180				   semanage_seuser_dbase_local(sh)) < 0)
181		goto err;
182
183	if (node_file_dbase_init(sh,
184				 semanage_fname(SEMANAGE_NODES_LOCAL),
185				 semanage_node_dbase_local(sh)) < 0)
186		goto err;
187
188	/* Object databases: local modifications + policy */
189	if (user_base_policydb_dbase_init(sh,
190					  semanage_user_base_dbase_policy(sh)) <
191	    0)
192		goto err;
193
194	if (user_extra_file_dbase_init(sh,
195				       semanage_fname(SEMANAGE_USERS_EXTRA),
196				       semanage_user_extra_dbase_policy(sh)) <
197	    0)
198		goto err;
199
200	if (user_join_dbase_init(sh,
201				 semanage_user_base_dbase_policy(sh),
202				 semanage_user_extra_dbase_policy(sh),
203				 semanage_user_dbase_policy(sh)) < 0)
204		goto err;
205
206	if (port_policydb_dbase_init(sh, semanage_port_dbase_policy(sh)) < 0)
207		goto err;
208
209	if (iface_policydb_dbase_init(sh, semanage_iface_dbase_policy(sh)) < 0)
210		goto err;
211
212	if (bool_policydb_dbase_init(sh, semanage_bool_dbase_policy(sh)) < 0)
213		goto err;
214
215	if (fcontext_file_dbase_init(sh,
216				     semanage_fname(SEMANAGE_FC),
217				     semanage_fcontext_dbase_policy(sh)) < 0)
218		goto err;
219
220	if (seuser_file_dbase_init(sh,
221				   semanage_fname(SEMANAGE_SEUSERS),
222				   semanage_seuser_dbase_policy(sh)) < 0)
223		goto err;
224
225	if (node_policydb_dbase_init(sh, semanage_node_dbase_policy(sh)) < 0)
226		goto err;
227
228	/* Active kernel policy */
229	if (bool_activedb_dbase_init(sh, semanage_bool_dbase_active(sh)) < 0)
230		goto err;
231
232	/* set the disable dontaudit value */
233	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_DISABLE_DONTAUDIT);
234	if (access(path, F_OK) == 0)
235		sepol_set_disable_dontaudit(sh->sepolh, 1);
236	else
237		sepol_set_disable_dontaudit(sh->sepolh, 0);
238
239	return STATUS_SUCCESS;
240
241      err:
242	ERR(sh, "could not establish direct connection");
243	return STATUS_ERR;
244}
245
246static void semanage_direct_destroy(semanage_handle_t * sh)
247{
248	/* do nothing */
249	sh = NULL;
250}
251
252static int semanage_direct_disconnect(semanage_handle_t * sh)
253{
254	/* destroy transaction */
255	if (sh->is_in_transaction) {
256		/* destroy sandbox */
257		if (semanage_remove_directory
258		    (semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL)) < 0) {
259			ERR(sh, "Could not cleanly remove sandbox %s.",
260			    semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL));
261			return -1;
262		}
263		semanage_release_trans_lock(sh);
264	}
265
266	/* Release object databases: local modifications */
267	user_base_file_dbase_release(semanage_user_base_dbase_local(sh));
268	user_extra_file_dbase_release(semanage_user_extra_dbase_local(sh));
269	user_join_dbase_release(semanage_user_dbase_local(sh));
270	port_file_dbase_release(semanage_port_dbase_local(sh));
271	iface_file_dbase_release(semanage_iface_dbase_local(sh));
272	bool_file_dbase_release(semanage_bool_dbase_local(sh));
273	fcontext_file_dbase_release(semanage_fcontext_dbase_local(sh));
274	seuser_file_dbase_release(semanage_seuser_dbase_local(sh));
275	node_file_dbase_release(semanage_node_dbase_local(sh));
276
277	/* Release object databases: local modifications + policy */
278	user_base_policydb_dbase_release(semanage_user_base_dbase_policy(sh));
279	user_extra_file_dbase_release(semanage_user_extra_dbase_policy(sh));
280	user_join_dbase_release(semanage_user_dbase_policy(sh));
281	port_policydb_dbase_release(semanage_port_dbase_policy(sh));
282	iface_policydb_dbase_release(semanage_iface_dbase_policy(sh));
283	bool_policydb_dbase_release(semanage_bool_dbase_policy(sh));
284	fcontext_file_dbase_release(semanage_fcontext_dbase_policy(sh));
285	seuser_file_dbase_release(semanage_seuser_dbase_policy(sh));
286	node_policydb_dbase_release(semanage_node_dbase_policy(sh));
287
288	/* Release object databases: active kernel policy */
289	bool_activedb_dbase_release(semanage_bool_dbase_active(sh));
290
291	return 0;
292}
293
294static int semanage_direct_begintrans(semanage_handle_t * sh)
295{
296
297	if (semanage_access_check(sh) != SEMANAGE_CAN_WRITE) {
298		return -1;
299	}
300	if (semanage_get_trans_lock(sh) < 0) {
301		return -1;
302	}
303	if ((semanage_make_sandbox(sh)) < 0) {
304		return -1;
305	}
306	return 0;
307}
308
309/********************* utility functions *********************/
310
311/* Takes a module stored in 'module_data' and parses its headers.
312 * Sets reference variables 'filename' to module's fully qualified
313 * path name into the sandbox, 'module_name' to module's name, and
314 * 'version' to module's version.  The caller is responsible for
315 * free()ing 'filename', 'module_name', and 'version'; they will be
316 * set to NULL upon entering this function.  Returns 0 on success, -1
317 * if out of memory, or -2 if data did not represent a module.
318 */
319static int parse_module_headers(semanage_handle_t * sh, char *module_data,
320				size_t data_len, char **module_name,
321				char **version, char **filename)
322{
323	struct sepol_policy_file *pf;
324	int file_type;
325	const char *module_path;
326	*module_name = *version = *filename = NULL;
327
328	if (sepol_policy_file_create(&pf)) {
329		ERR(sh, "Out of memory!");
330		return -1;
331	}
332	sepol_policy_file_set_mem(pf, module_data, data_len);
333	sepol_policy_file_set_handle(pf, sh->sepolh);
334	if (module_data == NULL ||
335	    data_len == 0 ||
336	    sepol_module_package_info(pf, &file_type, module_name,
337				      version) == -1) {
338		sepol_policy_file_free(pf);
339		ERR(sh, "Could not parse module data.");
340		return -2;
341	}
342	sepol_policy_file_free(pf);
343	if (file_type != SEPOL_POLICY_MOD) {
344		if (file_type == SEPOL_POLICY_BASE)
345			ERR(sh,
346			    "Received a base module, expected a non-base module.");
347		else
348			ERR(sh, "Data did not represent a module.");
349		return -2;
350	}
351	if ((module_path =
352	     semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES)) == NULL) {
353		return -1;
354	}
355	if (asprintf(filename, "%s/%s.pp%s", module_path, *module_name, DISABLESTR) == -1) {
356		ERR(sh, "Out of memory!");
357		return -1;
358	}
359
360	if (access(*filename, F_OK) == -1) {
361		char *ptr = *filename;
362		int len = strlen(ptr) - strlen(DISABLESTR);
363		if (len > 0) ptr[len]='\0';
364	}
365
366	return 0;
367}
368
369/* Takes a base module stored in 'module_data' and parse its headers.
370 * Returns 0 on success, -1 if out of memory, or -2 if data did not
371 * represent a module.
372 */
373static int parse_base_headers(semanage_handle_t * sh,
374			      char *module_data, size_t data_len)
375{
376	struct sepol_policy_file *pf;
377	char *module_name = NULL, *version = NULL;
378	int file_type;
379
380	if (sepol_policy_file_create(&pf)) {
381		ERR(sh, "Out of memory!");
382		return -1;
383	}
384	sepol_policy_file_set_mem(pf, module_data, data_len);
385	sepol_policy_file_set_handle(pf, sh->sepolh);
386	if (module_data == NULL ||
387	    data_len == 0 ||
388	    sepol_module_package_info(pf, &file_type,
389				      &module_name, &version) == -1) {
390		sepol_policy_file_free(pf);
391		ERR(sh, "Could not parse base module data.");
392		return -2;
393	}
394	sepol_policy_file_free(pf);
395	free(module_name);
396	free(version);
397	if (file_type != SEPOL_POLICY_BASE) {
398		if (file_type == SEPOL_POLICY_MOD)
399			ERR(sh,
400			    "Received a non-base module, expected a base module.");
401		else
402			ERR(sh, "Data did not represent a module.");
403		return -2;
404	}
405	return 0;
406}
407
408#include <stdlib.h>
409#include <bzlib.h>
410#include <string.h>
411#include <sys/sendfile.h>
412
413/* bzip() a data to a file, returning the total number of compressed bytes
414 * in the file.  Returns -1 if file could not be compressed. */
415static ssize_t bzip(semanage_handle_t *sh, const char *filename, char *data,
416			size_t num_bytes)
417{
418	BZFILE* b;
419	size_t  size = 1<<16;
420	int     bzerror;
421	size_t  total = 0;
422	size_t len = 0;
423	FILE *f;
424
425	if ((f = fopen(filename, "wb")) == NULL) {
426		return -1;
427	}
428
429	if (!sh->conf->bzip_blocksize) {
430		if (fwrite(data, 1, num_bytes, f) < num_bytes) {
431			fclose(f);
432			return -1;
433		}
434		fclose(f);
435		return num_bytes;
436	}
437
438	b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
439	if (bzerror != BZ_OK) {
440		BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
441		return -1;
442	}
443
444	while ( num_bytes > total ) {
445		if (num_bytes - total > size) {
446			len = size;
447		} else {
448			len = num_bytes - total;
449		}
450		BZ2_bzWrite ( &bzerror, b, &data[total], len );
451		if (bzerror == BZ_IO_ERROR) {
452			BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
453			return -1;
454		}
455		total += len;
456	}
457
458	BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
459	fclose(f);
460	if (bzerror == BZ_IO_ERROR) {
461		return -1;
462	}
463	return total;
464}
465
466#define BZ2_MAGICSTR "BZh"
467#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
468
469/* bunzip() a file to '*data', returning the total number of uncompressed bytes
470 * in the file.  Returns -1 if file could not be decompressed. */
471ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data)
472{
473	BZFILE* b;
474	size_t  nBuf;
475	char    buf[1<<18];
476	size_t  size = sizeof(buf);
477	int     bzerror;
478	size_t  total=0;
479
480	if (!sh->conf->bzip_blocksize) {
481		bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
482		rewind(f);
483		if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN))
484			return -1;
485		/* fall through */
486	}
487
488	b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
489	if ( bzerror != BZ_OK ) {
490		BZ2_bzReadClose ( &bzerror, b );
491		return -1;
492	}
493
494	char *uncompress = realloc(NULL, size);
495
496	while ( bzerror == BZ_OK) {
497		nBuf = BZ2_bzRead ( &bzerror, b, buf, sizeof(buf));
498		if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
499			if (total + nBuf > size) {
500				size *= 2;
501				uncompress = realloc(uncompress, size);
502			}
503			memcpy(&uncompress[total], buf, nBuf);
504			total += nBuf;
505		}
506	}
507	if ( bzerror != BZ_STREAM_END ) {
508		BZ2_bzReadClose ( &bzerror, b );
509		free(uncompress);
510		return -1;
511	}
512	BZ2_bzReadClose ( &bzerror, b );
513
514	*data = uncompress;
515	return  total;
516}
517
518/* mmap() a file to '*data',
519 *  If the file is bzip compressed map_file will uncompress
520 * the file into '*data'.
521 * Returns the total number of bytes in memory .
522 * Returns -1 if file could not be opened or mapped. */
523static ssize_t map_file(semanage_handle_t *sh, int fd, char **data,
524			int *compressed)
525{
526	ssize_t size = -1;
527	char *uncompress;
528	if ((size = bunzip(sh, fdopen(fd, "r"), &uncompress)) > 0) {
529		*data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
530		if (*data == MAP_FAILED) {
531			free(uncompress);
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	return size;
551}
552
553static int dupfile( const char *dest, int src_fd) {
554	int dest_fd = -1;
555	int retval = 0;
556	int cnt;
557	char    buf[1<<18];
558
559	if (lseek(src_fd, 0, SEEK_SET)  == -1 ) return -1;
560
561	if ((dest_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC,
562			   S_IRUSR | S_IWUSR)) == -1) {
563		return -1;
564	}
565
566	while (( retval == 0 ) &&
567	       ( cnt = read(src_fd, buf, sizeof(buf)))> 0 ) {
568		if (write(dest_fd, buf, cnt) < cnt) retval = -1;
569	}
570	close(dest_fd);
571	return retval;
572}
573
574/* Writes a block of data to a file.  Returns 0 on success, -1 on
575 * error. */
576static int write_file(semanage_handle_t * sh,
577		      const char *filename, char *data, size_t num_bytes)
578{
579	int out;
580
581	if ((out =
582	     open(filename, O_WRONLY | O_CREAT | O_TRUNC,
583		  S_IRUSR | S_IWUSR)) == -1) {
584		ERR(sh, "Could not open %s for writing.", filename);
585		return -1;
586	}
587	if (write(out, data, num_bytes) == -1) {
588		ERR(sh, "Error while writing to %s.", filename);
589		close(out);
590		return -1;
591	}
592	close(out);
593	return 0;
594}
595
596/* Writes a module (or a base) to the file given by a fully-qualified
597 * 'filename'.	Returns 0 on success, -1 if file could not be written.
598 */
599static int semanage_write_module(semanage_handle_t * sh,
600				 const char *filename,
601				 sepol_module_package_t * package)
602{
603	struct sepol_policy_file *pf;
604	FILE *outfile;
605	int retval;
606	if (sepol_policy_file_create(&pf)) {
607		ERR(sh, "Out of memory!");
608		return -1;
609	}
610	if ((outfile = fopen(filename, "wb")) == NULL) {
611		sepol_policy_file_free(pf);
612		ERR(sh, "Could not open %s for writing.", filename);
613		return -1;
614	}
615	__fsetlocking(outfile, FSETLOCKING_BYCALLER);
616	sepol_policy_file_set_fp(pf, outfile);
617	sepol_policy_file_set_handle(pf, sh->sepolh);
618	retval = sepol_module_package_write(package, pf);
619	fclose(outfile);
620	sepol_policy_file_free(pf);
621	if (retval == -1) {
622		ERR(sh, "Error while writing module to %s.", filename);
623		return -1;
624	}
625	return 0;
626}
627static int semanage_direct_update_user_extra(semanage_handle_t * sh, sepol_module_package_t *base ) {
628	const char *ofilename = NULL;
629	int retval = -1;
630
631	dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
632
633	if (sepol_module_package_get_user_extra_len(base)) {
634		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA);
635		if (ofilename == NULL) {
636			return retval;
637		}
638		retval = write_file(sh, ofilename,
639				    sepol_module_package_get_user_extra(base),
640				    sepol_module_package_get_user_extra_len(base));
641		if (retval < 0)
642			return retval;
643
644		pusers_extra->dtable->drop_cache(pusers_extra->dbase);
645
646	} else {
647		retval =  pusers_extra->dtable->clear(sh, pusers_extra->dbase);
648	}
649
650	return retval;
651}
652
653
654static int semanage_direct_update_seuser(semanage_handle_t * sh, sepol_module_package_t *base ) {
655
656	const char *ofilename = NULL;
657	int retval = -1;
658
659	dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
660
661	if (sepol_module_package_get_seusers_len(base)) {
662		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS);
663		if (ofilename == NULL) {
664			return -1;
665		}
666		retval = write_file(sh, ofilename,
667				    sepol_module_package_get_seusers(base),
668				    sepol_module_package_get_seusers_len(base));
669		if (retval < 0)
670			return retval;
671
672		pseusers->dtable->drop_cache(pseusers->dbase);
673
674	} else {
675		retval = pseusers->dtable->clear(sh, pseusers->dbase);
676	}
677	return retval;
678}
679
680/********************* direct API functions ********************/
681
682/* Commits all changes in sandbox to the actual kernel policy.
683 * Returns commit number on success, -1 on error.
684 */
685static int semanage_direct_commit(semanage_handle_t * sh)
686{
687	char **mod_filenames = NULL;
688	char *sorted_fc_buffer = NULL, *sorted_nc_buffer = NULL;
689	size_t sorted_fc_buffer_len = 0, sorted_nc_buffer_len = 0;
690	const char *linked_filename = NULL, *ofilename = NULL, *path;
691	sepol_module_package_t *base = NULL;
692	int retval = -1, num_modfiles = 0, i;
693	sepol_policydb_t *out = NULL;
694
695	/* Declare some variables */
696	int modified = 0, fcontexts_modified, ports_modified,
697	    seusers_modified, users_extra_modified, dontaudit_modified;
698	dbase_config_t *users = semanage_user_dbase_local(sh);
699	dbase_config_t *users_base = semanage_user_base_dbase_local(sh);
700	dbase_config_t *pusers_base = semanage_user_base_dbase_policy(sh);
701	dbase_config_t *users_extra = semanage_user_extra_dbase_local(sh);
702	dbase_config_t *ports = semanage_port_dbase_local(sh);
703	dbase_config_t *pports = semanage_port_dbase_policy(sh);
704	dbase_config_t *bools = semanage_bool_dbase_local(sh);
705	dbase_config_t *pbools = semanage_bool_dbase_policy(sh);
706	dbase_config_t *ifaces = semanage_iface_dbase_local(sh);
707	dbase_config_t *pifaces = semanage_iface_dbase_policy(sh);
708	dbase_config_t *nodes = semanage_node_dbase_local(sh);
709	dbase_config_t *pnodes = semanage_node_dbase_policy(sh);
710	dbase_config_t *fcontexts = semanage_fcontext_dbase_local(sh);
711	dbase_config_t *pfcontexts = semanage_fcontext_dbase_policy(sh);
712	dbase_config_t *seusers = semanage_seuser_dbase_local(sh);
713
714	/* Create or remove the disable_dontaudit flag file. */
715	path = semanage_path(SEMANAGE_TMP, SEMANAGE_DISABLE_DONTAUDIT);
716	if (access(path, F_OK) == 0)
717		dontaudit_modified = !(sepol_get_disable_dontaudit(sh->sepolh) == 1);
718	else
719		dontaudit_modified = (sepol_get_disable_dontaudit(sh->sepolh) == 1);
720	if (sepol_get_disable_dontaudit(sh->sepolh) == 1) {
721		FILE *touch;
722		touch = fopen(path, "w");
723		if (touch != NULL) {
724			if (fclose(touch) != 0) {
725				ERR(sh, "Error attempting to create disable_dontaudit flag.");
726				goto cleanup;
727			}
728		} else {
729			ERR(sh, "Error attempting to create disable_dontaudit flag.");
730			goto cleanup;
731		}
732	} else {
733		if (remove(path) == -1 && errno != ENOENT) {
734			ERR(sh, "Error removing the disable_dontaudit flag.");
735			goto cleanup;
736		}
737	}
738
739	/* Before we do anything else, flush the join to its component parts.
740	 * This *does not* flush to disk automatically */
741	if (users->dtable->is_modified(users->dbase)) {
742		retval = users->dtable->flush(sh, users->dbase);
743		if (retval < 0)
744			goto cleanup;
745	}
746
747	/* Decide if anything was modified */
748	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
749	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
750	users_extra_modified =
751	    users_extra->dtable->is_modified(users_extra->dbase);
752	ports_modified = ports->dtable->is_modified(ports->dbase);
753
754	modified = sh->modules_modified;
755	modified |= ports_modified;
756	modified |= users->dtable->is_modified(users_base->dbase);
757	modified |= bools->dtable->is_modified(bools->dbase);
758	modified |= ifaces->dtable->is_modified(ifaces->dbase);
759	modified |= nodes->dtable->is_modified(nodes->dbase);
760	modified |= dontaudit_modified;
761
762	/* If there were policy changes, or explicitly requested, rebuild the policy */
763	if (sh->do_rebuild || modified) {
764
765		/* =================== Module expansion =============== */
766
767		/* link all modules in the sandbox to the base module */
768		retval = semanage_get_modules_names(sh, &mod_filenames, &num_modfiles);
769		if (retval < 0)
770			goto cleanup;
771		retval = semanage_verify_modules(sh, mod_filenames, num_modfiles);
772		if (retval < 0)
773			goto cleanup;
774		retval = semanage_link_sandbox(sh, &base);
775		if (retval < 0)
776			goto cleanup;
777
778		/* write the linked base if we want to save or we have a
779		 * verification program that wants it. */
780		linked_filename = semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED);
781		if (linked_filename == NULL) {
782			retval = -1;
783			goto cleanup;
784		}
785		if (sh->conf->save_linked || sh->conf->linked_prog) {
786			retval = semanage_write_module(sh, linked_filename, base);
787			if (retval < 0)
788				goto cleanup;
789			retval = semanage_verify_linked(sh);
790			if (retval < 0)
791				goto cleanup;
792			/* remove the linked policy if we only wrote it for the
793			 * verification program. */
794			if (!sh->conf->save_linked) {
795				retval = unlink(linked_filename);
796				if (retval < 0) {
797					ERR(sh, "could not remove linked base %s",
798					    linked_filename);
799					goto cleanup;
800				}
801			}
802		} else {
803			/* Try to delete the linked copy - this is needed if
804			 * the save_link option has changed to prevent the
805			 * old linked copy from being copied forever. No error
806			 * checking is done because this is likely to fail because
807			 * the file does not exist - which is not an error. */
808			unlink(linked_filename);
809			errno = 0;
810		}
811
812		/* ==================== File-backed ================== */
813
814		/* File Contexts */
815		/* Sort the file contexts. */
816		retval = semanage_fc_sort(sh, sepol_module_package_get_file_contexts(base),
817					  sepol_module_package_get_file_contexts_len(base),
818					  &sorted_fc_buffer, &sorted_fc_buffer_len);
819		if (retval < 0)
820			goto cleanup;
821
822		/* Write the contexts (including template contexts) to a single file.
823		 * The buffer returned by the sort function has a trailing \0 character,
824		 * which we do NOT want to write out to disk, so we pass sorted_fc_buffer_len-1. */
825		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL);
826		if (ofilename == NULL) {
827			retval = -1;
828			goto cleanup;
829		}
830		retval = write_file(sh, ofilename, sorted_fc_buffer,
831				    sorted_fc_buffer_len - 1);
832		if (retval < 0)
833			goto cleanup;
834
835		/* Split complete and template file contexts into their separate files. */
836		retval = semanage_split_fc(sh);
837		if (retval < 0)
838			goto cleanup;
839
840		pfcontexts->dtable->drop_cache(pfcontexts->dbase);
841
842		retval = semanage_direct_update_seuser(sh, base );
843		if (retval < 0)
844			goto cleanup;
845
846		retval = semanage_direct_update_user_extra(sh, base );
847		if (retval < 0)
848			goto cleanup;
849
850		/* Netfilter Contexts */
851		/* Sort the netfilter contexts. */
852		retval = semanage_nc_sort
853		    (sh, sepol_module_package_get_netfilter_contexts(base),
854		     sepol_module_package_get_netfilter_contexts_len(base),
855		     &sorted_nc_buffer, &sorted_nc_buffer_len);
856
857		if (retval < 0)
858			goto cleanup;
859
860		/* Write the contexts to a single file.  The buffer returned by
861		 * the sort function has a trailing \0 character, which we do
862		 * NOT want to write out to disk, so we pass sorted_fc_buffer_len-1. */
863		ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_NC);
864		retval = write_file
865		    (sh, ofilename, sorted_nc_buffer, sorted_nc_buffer_len - 1);
866
867		if (retval < 0)
868			goto cleanup;
869
870		/* ==================== Policydb-backed ================ */
871
872		/* Create new policy object, then attach to policy databases
873		 * that work with a policydb */
874		retval = semanage_expand_sandbox(sh, base, &out);
875		if (retval < 0)
876			goto cleanup;
877
878		sepol_module_package_free(base);
879		base = NULL;
880
881		dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase,
882				      out);
883		dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
884		dbase_policydb_attach((dbase_policydb_t *) pifaces->dbase, out);
885		dbase_policydb_attach((dbase_policydb_t *) pbools->dbase, out);
886		dbase_policydb_attach((dbase_policydb_t *) pnodes->dbase, out);
887
888		/* ============= Apply changes, and verify  =============== */
889
890		retval = semanage_base_merge_components(sh);
891		if (retval < 0)
892			goto cleanup;
893
894		retval = semanage_write_policydb(sh, out);
895		if (retval < 0)
896			goto cleanup;
897
898		retval = semanage_verify_kernel(sh);
899		if (retval < 0)
900			goto cleanup;
901	} else {
902		retval = sepol_policydb_create(&out);
903		if (retval < 0)
904			goto cleanup;
905
906		retval = semanage_read_policydb(sh, out);
907		if (retval < 0)
908			goto cleanup;
909
910		if (seusers_modified || users_extra_modified) {
911			retval = semanage_link_base(sh, &base);
912			if (retval < 0)
913				goto cleanup;
914
915			if (seusers_modified) {
916				retval = semanage_direct_update_seuser(sh, base );
917				if (retval < 0)
918					goto cleanup;
919			}
920			if (users_extra_modified) {
921				/* Users_extra */
922				retval = semanage_direct_update_user_extra(sh, base );
923				if (retval < 0)
924					goto cleanup;
925			}
926
927			sepol_module_package_free(base);
928			base = NULL;
929		}
930
931		retval = semanage_base_merge_components(sh);
932		if (retval < 0)
933		  goto cleanup;
934
935	}
936	/* ======= Post-process: Validate non-policydb components ===== */
937
938	/* Validate local modifications to file contexts.
939	 * Note: those are still cached, even though they've been
940	 * merged into the main file_contexts. We won't check the
941	 * large file_contexts - checked at compile time */
942	if (sh->do_rebuild || modified || fcontexts_modified) {
943		retval = semanage_fcontext_validate_local(sh, out);
944		if (retval < 0)
945			goto cleanup;
946	}
947
948	/* Validate local seusers against policy */
949	if (sh->do_rebuild || modified || seusers_modified) {
950		retval = semanage_seuser_validate_local(sh, out);
951		if (retval < 0)
952			goto cleanup;
953	}
954
955	/* Validate local ports for overlap */
956	if (sh->do_rebuild || ports_modified) {
957		retval = semanage_port_validate_local(sh);
958		if (retval < 0)
959			goto cleanup;
960	}
961
962	/* ================== Write non-policydb components ========= */
963
964	/* Commit changes to components */
965	retval = semanage_commit_components(sh);
966	if (retval < 0)
967		goto cleanup;
968
969	/* run genhomedircon if its enabled, this should be the last operation
970	 * which requires the out policydb */
971	if (!sh->conf->disable_genhomedircon) {
972		if (out && (retval =
973		     semanage_genhomedircon(sh, out, sh->conf->usepasswd)) != 0) {
974			ERR(sh, "semanage_genhomedircon returned error code %d.",
975			    retval);
976			goto cleanup;
977		}
978	} else {
979		WARN(sh, "WARNING: genhomedircon is disabled. \
980                               See /etc/selinux/semanage.conf if you need to enable it.");
981        }
982
983	/* free out, if we don't free it before calling semanage_install_sandbox
984	 * then fork() may fail on low memory machines */
985	sepol_policydb_free(out);
986	out = NULL;
987
988	if (sh->do_rebuild || modified ||
989	    seusers_modified || fcontexts_modified || users_extra_modified) {
990		retval = semanage_install_sandbox(sh);
991	}
992
993      cleanup:
994	for (i = 0; mod_filenames != NULL && i < num_modfiles; i++) {
995		free(mod_filenames[i]);
996	}
997
998	if (modified) {
999		/* Detach from policydb, so it can be freed */
1000		dbase_policydb_detach((dbase_policydb_t *) pusers_base->dbase);
1001		dbase_policydb_detach((dbase_policydb_t *) pports->dbase);
1002		dbase_policydb_detach((dbase_policydb_t *) pifaces->dbase);
1003		dbase_policydb_detach((dbase_policydb_t *) pnodes->dbase);
1004		dbase_policydb_detach((dbase_policydb_t *) pbools->dbase);
1005	}
1006
1007	free(mod_filenames);
1008	sepol_policydb_free(out);
1009	semanage_release_trans_lock(sh);
1010
1011	free(sorted_fc_buffer);
1012	free(sorted_nc_buffer);
1013
1014	/* regardless if the commit was successful or not, remove the
1015	   sandbox if it is still there */
1016	semanage_remove_directory(semanage_path
1017				  (SEMANAGE_TMP, SEMANAGE_TOPLEVEL));
1018	return retval;
1019}
1020
1021/* Writes a module to the sandbox's module directory, overwriting any
1022 * previous module stored within.  Note that module data are not
1023 * free()d by this function; caller is responsible for deallocating it
1024 * if necessary.  Returns 0 on success, -1 if out of memory, -2 if the
1025 * data does not represent a valid module file, -3 if error while
1026 * writing file. */
1027static int semanage_direct_install(semanage_handle_t * sh,
1028				   char *data, size_t data_len)
1029{
1030
1031	int retval;
1032	char *module_name = NULL, *version = NULL, *filename = NULL;
1033	if ((retval = parse_module_headers(sh, data, data_len,
1034					   &module_name, &version,
1035					   &filename)) != 0) {
1036		goto cleanup;
1037	}
1038	if (bzip(sh, filename, data, data_len) <= 0) {
1039		ERR(sh, "Error while writing to %s.", filename);
1040		retval = -3;
1041		goto cleanup;
1042	}
1043	retval = 0;
1044      cleanup:
1045	free(version);
1046	free(filename);
1047	free(module_name);
1048	return retval;
1049}
1050
1051/* Attempts to link a module to the sandbox's module directory, unlinking any
1052 * previous module stored within.  Returns 0 on success, -1 if out of memory, -2 if the
1053 * data does not represent a valid module file, -3 if error while
1054 * writing file. */
1055
1056static int semanage_direct_install_file(semanage_handle_t * sh,
1057					const char *install_filename)
1058{
1059
1060	int retval = -1;
1061	char *data = NULL;
1062	ssize_t data_len = 0;
1063	int compressed = 0;
1064	int in_fd = -1;
1065
1066	if ((in_fd = open(install_filename, O_RDONLY)) == -1) {
1067		return -1;
1068	}
1069
1070	if ((data_len = map_file(sh, in_fd, &data, &compressed)) <= 0) {
1071		goto cleanup;
1072	}
1073
1074	if (compressed) {
1075		char *module_name = NULL, *version = NULL, *filename = NULL;
1076		if ((retval = parse_module_headers(sh, data, data_len,
1077						   &module_name, &version,
1078						   &filename)) != 0) {
1079			goto cleanup;
1080		}
1081
1082		if (data_len > 0) munmap(data, data_len);
1083		data_len = 0;
1084		retval = dupfile(filename, in_fd);
1085		free(version);
1086		free(filename);
1087		free(module_name);
1088
1089	} else {
1090		retval = semanage_direct_install(sh, data, data_len);
1091	}
1092
1093      cleanup:
1094	close(in_fd);
1095	if (data_len > 0) munmap(data, data_len);
1096
1097	return retval;
1098}
1099
1100
1101static int get_direct_upgrade_filename(semanage_handle_t * sh,
1102				       char *data, size_t data_len, char **outfilename) {
1103	int i, retval, num_modules = 0;
1104	char *module_name = NULL, *version = NULL, *filename = NULL;
1105	semanage_module_info_t *modinfo = NULL;
1106	if ((retval = parse_module_headers(sh, data, data_len,
1107					   &module_name, &version,
1108					   &filename)) != 0) {
1109		goto cleanup;
1110	}
1111	if (semanage_direct_list(sh, &modinfo, &num_modules) < 0) {
1112		goto cleanup;
1113	}
1114	retval = -5;
1115	for (i = 0; i < num_modules; i++) {
1116		semanage_module_info_t *m =
1117		    semanage_module_list_nth(modinfo, i);
1118		if (strcmp(semanage_module_get_name(m), module_name) == 0) {
1119			if (strverscmp(version, semanage_module_get_version(m))
1120			    > 0) {
1121				retval = 0;
1122				break;
1123			} else {
1124				ERR(sh, "Previous module %s is same or newer.",
1125				    module_name);
1126				retval = -4;
1127				goto cleanup;
1128			}
1129		}
1130	}
1131      cleanup:
1132	free(version);
1133	free(module_name);
1134	for (i = 0; modinfo != NULL && i < num_modules; i++) {
1135		semanage_module_info_t *m =
1136		    semanage_module_list_nth(modinfo, i);
1137		semanage_module_info_datum_destroy(m);
1138	}
1139	free(modinfo);
1140	if (retval == 0) {
1141		*outfilename = filename;
1142	} else {
1143		free(filename);
1144	}
1145	return retval;
1146}
1147
1148/* Similar to semanage_direct_install(), except that it checks that
1149 * there already exists a module with the same name and that the
1150 * module is an older version then the one in 'data'.  Returns 0 on
1151 * success, -1 if out of memory, -2 if the data does not represent a
1152 * valid module file, -3 if error while writing file or reading
1153 * modules directory, -4 if the previous module is same or newer than 'data',
1154 * -5 if there does not exist an older module.
1155 */
1156static int semanage_direct_upgrade(semanage_handle_t * sh,
1157				   char *data, size_t data_len)
1158{
1159	char *filename = NULL;
1160	int retval = get_direct_upgrade_filename(sh,
1161						 data, data_len,
1162						 &filename);
1163	if (retval == 0) {
1164		if (bzip(sh, filename, data, data_len) <= 0) {
1165			ERR(sh, "Error while writing to %s.", filename);
1166			retval = -3;
1167		}
1168		free(filename);
1169	}
1170	return retval;
1171}
1172
1173/* Attempts to link a module to the sandbox's module directory, unlinking any
1174 * previous module stored within.
1175 * Returns 0 on success, -1 if out of memory, -2 if the
1176 * data does not represent a valid module file, -3 if error while
1177 * writing file. */
1178
1179static int semanage_direct_upgrade_file(semanage_handle_t * sh,
1180					const char *module_filename)
1181{
1182	int retval = -1;
1183	char *data = NULL;
1184	ssize_t data_len = 0;
1185	int compressed = 0;
1186	int in_fd = -1;
1187
1188	if ((in_fd = open(module_filename, O_RDONLY)) == -1) {
1189		return -1;
1190	}
1191
1192	if ((data_len = map_file(sh, in_fd, &data, &compressed)) <= 0) {
1193		goto cleanup;
1194	}
1195
1196	if (compressed) {
1197		char *filename = NULL;
1198		retval = get_direct_upgrade_filename(sh,
1199					 	     data, data_len,
1200						     &filename);
1201
1202		if (retval != 0)  goto cleanup;
1203
1204		retval = dupfile(filename, in_fd);
1205		free(filename);
1206	} else {
1207		retval = semanage_direct_upgrade(sh, data, data_len);
1208	}
1209
1210      cleanup:
1211	close(in_fd);
1212	if (data_len > 0) munmap(data, data_len);
1213
1214	return retval;
1215}
1216
1217/* Writes a base module into a sandbox, overwriting any previous base
1218 * module.  Note that 'module_data' is not free()d by this function;
1219 * caller is responsible for deallocating it if necessary.  Returns 0
1220 * on success, -1 if out of memory, -2 if the data does not represent
1221 * a valid base module file, -3 if error while writing file.
1222 */
1223static int semanage_direct_install_base(semanage_handle_t * sh,
1224					char *base_data, size_t data_len)
1225{
1226	int retval = -1;
1227	const char *filename = NULL;
1228	if ((retval = parse_base_headers(sh, base_data, data_len)) != 0) {
1229		goto cleanup;
1230	}
1231	if ((filename = semanage_path(SEMANAGE_TMP, SEMANAGE_BASE)) == NULL) {
1232		goto cleanup;
1233	}
1234	if (bzip(sh, filename, base_data, data_len) <= 0) {
1235		ERR(sh, "Error while writing to %s.", filename);
1236		retval = -3;
1237		goto cleanup;
1238	}
1239	retval = 0;
1240      cleanup:
1241	return retval;
1242}
1243
1244/* Writes a base module into a sandbox, overwriting any previous base
1245 * module.
1246 * Returns 0 on success, -1 if out of memory, -2 if the data does not represent
1247 * a valid base module file, -3 if error while writing file.
1248 */
1249static int semanage_direct_install_base_file(semanage_handle_t * sh,
1250					     const char *install_filename)
1251{
1252	int retval = -1;
1253	char *data = NULL;
1254	ssize_t data_len = 0;
1255	int compressed = 0;
1256	int in_fd;
1257
1258	if ((in_fd = open(install_filename, O_RDONLY)) == -1) {
1259		return -1;
1260	}
1261
1262	if ((data_len = map_file(sh, in_fd, &data, &compressed)) <= 0) {
1263		goto cleanup;
1264	}
1265
1266	if (compressed) {
1267		const char *filename = NULL;
1268		if ((retval = parse_base_headers(sh, data, data_len)) != 0) {
1269			goto cleanup;
1270		}
1271		if ((filename = semanage_path(SEMANAGE_TMP, SEMANAGE_BASE)) == NULL) {
1272			goto cleanup;
1273		}
1274
1275		retval = dupfile(filename, in_fd);
1276	} else {
1277		retval = semanage_direct_install_base(sh, data, data_len);
1278	}
1279
1280      cleanup:
1281	close(in_fd);
1282	if (data_len > 0) munmap(data, data_len);
1283
1284	return retval;
1285}
1286
1287/* Enables a module from the sandbox.  Returns 0 on success, -1 if out
1288 * of memory, -2 if module not found or could not be enabled. */
1289static int semanage_direct_enable(semanage_handle_t * sh, char *module_name)
1290{
1291	int i, retval = -1;
1292	char **module_filenames = NULL;
1293	int num_mod_files;
1294	size_t name_len = strlen(module_name);
1295	if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) ==
1296	    -1) {
1297		return -1;
1298	}
1299	for (i = 0; i < num_mod_files; i++) {
1300		char *base = strrchr(module_filenames[i], '/');
1301		if (base == NULL) {
1302			ERR(sh, "Could not read module names.");
1303			retval = -2;
1304			goto cleanup;
1305		}
1306		base++;
1307		if (memcmp(module_name, base, name_len) == 0 &&
1308		    strcmp(base + name_len + 3, DISABLESTR) == 0) {
1309			int len = strlen(module_filenames[i]) - strlen(DISABLESTR);
1310			char *enabled_name = calloc(1, len+1);
1311			if (!enabled_name) {
1312				ERR(sh, "Could not allocate memory");
1313				retval = -1;
1314				goto cleanup;
1315			}
1316
1317			strncpy(enabled_name, module_filenames[i],len);
1318
1319			if (rename(module_filenames[i], enabled_name) == -1) {
1320				ERR(sh, "Could not enable module file %s.",
1321				    enabled_name);
1322				retval = -2;
1323			}
1324			retval = 0;
1325			free(enabled_name);
1326			goto cleanup;
1327		}
1328	}
1329	ERR(sh, "Module %s was not found.", module_name);
1330	retval = -2;		/* module not found */
1331      cleanup:
1332	for (i = 0; module_filenames != NULL && i < num_mod_files; i++) {
1333		free(module_filenames[i]);
1334	}
1335	free(module_filenames);
1336	return retval;
1337}
1338
1339/* Enables a module from the sandbox.  Returns 0 on success, -1 if out
1340 * of memory, -2 if module not found or could not be enabled. */
1341static int semanage_direct_disable(semanage_handle_t * sh, char *module_name)
1342{
1343	int i, retval = -1;
1344	char **module_filenames = NULL;
1345	int num_mod_files;
1346	size_t name_len = strlen(module_name);
1347	if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) ==
1348	    -1) {
1349		return -1;
1350	}
1351	for (i = 0; i < num_mod_files; i++) {
1352		char *base = strrchr(module_filenames[i], '/');
1353		if (base == NULL) {
1354			ERR(sh, "Could not read module names.");
1355			retval = -2;
1356			goto cleanup;
1357		}
1358		base++;
1359		if (memcmp(module_name, base, name_len) == 0 &&
1360		    strcmp(base + name_len, ".pp") == 0) {
1361			char disabled_name[PATH_MAX];
1362			if (snprintf(disabled_name, PATH_MAX, "%s%s",
1363				     module_filenames[i], DISABLESTR) == PATH_MAX) {
1364				ERR(sh, "Could not disable module file %s.",
1365				    module_filenames[i]);
1366				retval = -2;
1367				goto cleanup;
1368			}
1369			if (rename(module_filenames[i], disabled_name) == -1) {
1370				ERR(sh, "Could not disable module file %s.",
1371				    module_filenames[i]);
1372				retval = -2;
1373			}
1374			retval = 0;
1375			goto cleanup;
1376		}
1377	}
1378	ERR(sh, "Module %s was not found.", module_name);
1379	retval = -2;		/* module not found */
1380      cleanup:
1381	for (i = 0; module_filenames != NULL && i < num_mod_files; i++) {
1382		free(module_filenames[i]);
1383	}
1384	free(module_filenames);
1385	return retval;
1386}
1387
1388/* Removes a module from the sandbox.  Returns 0 on success, -1 if out
1389 * of memory, -2 if module not found or could not be removed. */
1390static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
1391{
1392	int i, retval = -1;
1393	char **module_filenames = NULL;
1394	int num_mod_files;
1395	size_t name_len = strlen(module_name);
1396	if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) ==
1397	    -1) {
1398		return -1;
1399	}
1400	for (i = 0; i < num_mod_files; i++) {
1401		char *base = strrchr(module_filenames[i], '/');
1402		if (base == NULL) {
1403			ERR(sh, "Could not read module names.");
1404			retval = -2;
1405			goto cleanup;
1406		}
1407		base++;
1408		if (memcmp(module_name, base, name_len) == 0) {
1409			if (unlink(module_filenames[i]) == -1) {
1410				ERR(sh, "Could not remove module file %s.",
1411				    module_filenames[i]);
1412				retval = -2;
1413			}
1414			retval = 0;
1415			goto cleanup;
1416		}
1417	}
1418	ERR(sh, "Module %s was not found.", module_name);
1419	retval = -2;		/* module not found */
1420      cleanup:
1421	for (i = 0; module_filenames != NULL && i < num_mod_files; i++) {
1422		free(module_filenames[i]);
1423	}
1424	free(module_filenames);
1425	return retval;
1426}
1427
1428/* Allocate an array of module_info structures for each readable
1429 * module within the store.  Note that if the calling program has
1430 * already begun a transaction then this function will get a list of
1431 * modules within the sandbox.	The caller is responsible for calling
1432 * semanage_module_info_datum_destroy() on each element of the array
1433 * as well as free()ing the entire list.
1434 */
1435static int semanage_direct_list(semanage_handle_t * sh,
1436				semanage_module_info_t ** modinfo,
1437				int *num_modules)
1438{
1439	struct sepol_policy_file *pf = NULL;
1440	int i, retval = -1;
1441	char **module_filenames = NULL;
1442	int num_mod_files;
1443	*modinfo = NULL;
1444	*num_modules = 0;
1445
1446	/* get the read lock when reading from the active
1447	   (non-transaction) directory */
1448	if (!sh->is_in_transaction)
1449		if (semanage_get_active_lock(sh) < 0)
1450			return -1;
1451
1452	if (semanage_get_modules_names(sh, &module_filenames, &num_mod_files) ==
1453	    -1) {
1454		goto cleanup;
1455	}
1456	if (num_mod_files == 0) {
1457		retval = semanage_direct_get_serial(sh);
1458		goto cleanup;
1459	}
1460
1461	if (sepol_policy_file_create(&pf)) {
1462		ERR(sh, "Out of memory!");
1463		goto cleanup;
1464	}
1465	sepol_policy_file_set_handle(pf, sh->sepolh);
1466
1467	if ((*modinfo = calloc(num_mod_files, sizeof(**modinfo))) == NULL) {
1468		ERR(sh, "Out of memory!");
1469		goto cleanup;
1470	}
1471
1472	for (i = 0; i < num_mod_files; i++) {
1473		FILE *fp;
1474		char *name = NULL, *version = NULL;
1475		int type;
1476		if ((fp = fopen(module_filenames[i], "rb")) == NULL) {
1477			/* could not open this module file, so don't
1478			 * report it */
1479			continue;
1480		}
1481		ssize_t size;
1482		char *data = NULL;
1483		int enabled = semanage_module_enabled(module_filenames[i]);
1484
1485		if ((size = bunzip(sh, fp, &data)) > 0) {
1486			sepol_policy_file_set_mem(pf, data, size);
1487		} else {
1488			rewind(fp);
1489			__fsetlocking(fp, FSETLOCKING_BYCALLER);
1490			sepol_policy_file_set_fp(pf, fp);
1491		}
1492		if (sepol_module_package_info(pf, &type, &name, &version)) {
1493			fclose(fp);
1494			free(data);
1495			free(name);
1496			free(version);
1497			continue;
1498		}
1499		fclose(fp);
1500		free(data);
1501		if (type == SEPOL_POLICY_MOD) {
1502			(*modinfo)[*num_modules].name = name;
1503			(*modinfo)[*num_modules].version = version;
1504			(*modinfo)[*num_modules].enabled = enabled;
1505			(*num_modules)++;
1506		} else {
1507			/* file was not a module, so don't report it */
1508			free(name);
1509			free(version);
1510		}
1511	}
1512	retval = semanage_direct_get_serial(sh);
1513
1514      cleanup:
1515	sepol_policy_file_free(pf);
1516	for (i = 0; module_filenames != NULL && i < num_mod_files; i++) {
1517		free(module_filenames[i]);
1518	}
1519	free(module_filenames);
1520	if (!sh->is_in_transaction) {
1521		semanage_release_active_lock(sh);
1522	}
1523	return retval;
1524}
1525
1526int semanage_direct_access_check(semanage_handle_t * sh)
1527{
1528	char polpath[PATH_MAX];
1529
1530	snprintf(polpath, PATH_MAX, "%s%s", selinux_path(),
1531		 sh->conf->store_path);
1532
1533	if (semanage_check_init(polpath))
1534		return -1;
1535
1536	return semanage_store_access_check(sh);
1537}
1538
1539int semanage_direct_mls_enabled(semanage_handle_t * sh)
1540{
1541	sepol_policydb_t *p = NULL;
1542	int retval;
1543
1544	retval = sepol_policydb_create(&p);
1545	if (retval < 0)
1546		goto cleanup;
1547
1548	retval = semanage_read_policydb(sh, p);
1549	if (retval < 0)
1550		goto cleanup;
1551
1552	retval = sepol_policydb_mls_enabled(p);
1553cleanup:
1554	sepol_policydb_free(p);
1555	return retval;
1556}
1557