1/* Author: Joshua Brindle <jbrindle@tresys.co
2 *	   Jason Tang	  <jtang@tresys.com>
3 *
4 * Copyright (C) 2004-2005 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/* This file implements only the publicly-visible handle functions to libsemanage. */
23
24#include <selinux/selinux.h>
25
26#include <ctype.h>
27#include <stdarg.h>
28#include <assert.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <sys/time.h>
33
34#include "direct_api.h"
35#include "handle.h"
36#include "debug.h"
37#include "semanage_conf.h"
38#include "semanage_store.h"
39
40#define SEMANAGE_COMMIT_READ_WAIT 5
41
42static char *private_semanage_root = NULL;
43
44int semanage_set_root(const char *root)
45{
46	free(private_semanage_root);
47	private_semanage_root = strdup(root);
48	return 0;
49}
50
51hidden_def(semanage_set_root);
52
53const char * semanage_root(void)
54{
55	if (private_semanage_root == NULL) {
56		return "";
57	}
58	return private_semanage_root;
59}
60
61semanage_handle_t *semanage_handle_create(void)
62{
63	semanage_handle_t *sh = NULL;
64	char *conf_name = NULL;
65
66	/* Allocate handle */
67	if ((sh = calloc(1, sizeof(semanage_handle_t))) == NULL)
68		goto err;
69
70	if ((conf_name = semanage_conf_path()) == NULL)
71		goto err;
72
73	if ((sh->conf = semanage_conf_parse(conf_name)) == NULL)
74		goto err;
75
76	/* Link to sepol handle */
77	sh->sepolh = sepol_handle_create();
78	if (!sh->sepolh)
79		goto err;
80	sepol_msg_set_callback(sh->sepolh, semanage_msg_relay_handler, sh);
81
82	/* Default priority is 400 */
83	sh->priority = 400;
84
85	/* By default do not rebuild the policy on commit
86	 * If any changes are made, this flag is ignored */
87	sh->do_rebuild = 0;
88
89	/* By default always reload policy after commit if SELinux is enabled. */
90	sh->do_reload = (is_selinux_enabled() > 0);
91
92	/* By default always check the file contexts file. */
93	sh->do_check_contexts = 1;
94
95	/* By default do not create store */
96	sh->create_store = 0;
97
98	/* Set timeout: some default value for now, later use config */
99	sh->timeout = SEMANAGE_COMMIT_READ_WAIT;
100
101	/* Set callback */
102	sh->msg_callback = semanage_msg_default_handler;
103	sh->msg_callback_arg = NULL;
104
105	free(conf_name);
106
107	return sh;
108
109      err:
110	free(conf_name);
111	semanage_handle_destroy(sh);
112	return NULL;
113}
114
115void semanage_set_rebuild(semanage_handle_t * sh, int do_rebuild)
116{
117
118	assert(sh != NULL);
119
120	sh->do_rebuild = do_rebuild;
121	return;
122}
123
124void semanage_set_reload(semanage_handle_t * sh, int do_reload)
125{
126
127	assert(sh != NULL);
128
129	sh->do_reload = do_reload;
130	return;
131}
132
133int semanage_get_hll_compiler_path(semanage_handle_t *sh,
134				char *lang_ext,
135				char **compiler_path)
136{
137	assert(sh != NULL);
138	assert(lang_ext != NULL);
139
140	int i;
141	int status = 0;
142	int num_printed = 0;
143	size_t len;
144	char *compiler = NULL;
145	char *lower_lang_ext = NULL;
146
147	lower_lang_ext = strdup(lang_ext);
148	if (lower_lang_ext == NULL) {
149		ERR(sh, "Could not create copy of lang_ext. Out of memory.\n");
150		status = -1;
151		goto cleanup;
152	}
153	/* Set lang_ext to lowercase in case a file with a mixed case extension was passed to libsemanage */
154	for (i = 0; lower_lang_ext[i] != '\0'; i++) {
155		lower_lang_ext[i] = tolower(lower_lang_ext[i]);
156	}
157
158	len = strlen(sh->conf->compiler_directory_path) + strlen("/") + strlen(lower_lang_ext) + 1;
159
160	compiler = malloc(len * sizeof(*compiler));
161	if (compiler == NULL) {
162		ERR(sh, "Error allocating space for compiler path.");
163		status = -1;
164		goto cleanup;
165	}
166
167	num_printed = snprintf(compiler, len, "%s/%s", sh->conf->compiler_directory_path, lower_lang_ext);
168	if (num_printed < 0 || (int)num_printed >= (int)len) {
169		ERR(sh, "Error creating compiler path.");
170		status = -1;
171		goto cleanup;
172	}
173
174	*compiler_path = compiler;
175	status = 0;
176
177cleanup:
178	free(lower_lang_ext);
179	if (status != 0) {
180		free(compiler);
181	}
182
183	return status;
184}
185
186void semanage_set_create_store(semanage_handle_t * sh, int create_store)
187{
188
189	assert(sh != NULL);
190
191	sh->create_store = create_store;
192	return;
193}
194
195int semanage_get_disable_dontaudit(semanage_handle_t * sh)
196{
197	assert(sh != NULL);
198
199	return sepol_get_disable_dontaudit(sh->sepolh);
200}
201
202void semanage_set_disable_dontaudit(semanage_handle_t * sh, int disable_dontaudit)
203{
204	assert(sh != NULL);
205
206	sepol_set_disable_dontaudit(sh->sepolh, disable_dontaudit);
207	return;
208}
209
210int semanage_get_preserve_tunables(semanage_handle_t * sh)
211{
212	assert(sh != NULL);
213	return sepol_get_preserve_tunables(sh->sepolh);
214}
215
216void semanage_set_preserve_tunables(semanage_handle_t * sh,
217				    int preserve_tunables)
218{
219	assert(sh != NULL);
220	sepol_set_preserve_tunables(sh->sepolh, preserve_tunables);
221}
222
223int semanage_get_ignore_module_cache(semanage_handle_t *sh)
224{
225	assert(sh != NULL);
226	return sh->conf->ignore_module_cache;
227}
228
229void semanage_set_ignore_module_cache(semanage_handle_t *sh,
230				    int ignore_module_cache)
231{
232	assert(sh != NULL);
233	sh->conf->ignore_module_cache = ignore_module_cache;
234}
235
236void semanage_set_check_contexts(semanage_handle_t * sh, int do_check_contexts)
237{
238
239	assert(sh != NULL);
240
241	sh->do_check_contexts = do_check_contexts;
242	return;
243}
244
245uint16_t semanage_get_default_priority(semanage_handle_t *sh)
246{
247	assert(sh != NULL);
248	return sh->priority;
249}
250
251int semanage_set_default_priority(semanage_handle_t *sh, uint16_t priority)
252{
253	assert(sh != NULL);
254
255	/* Verify priority */
256	if (semanage_module_validate_priority(priority) < 0) {
257		ERR(sh, "Priority %d is invalid.", priority);
258		return -1;
259	}
260
261	sh->priority = priority;
262	return 0;
263}
264
265int semanage_is_connected(semanage_handle_t * sh)
266{
267	assert(sh != NULL);
268	return sh->is_connected;
269}
270
271void semanage_select_store(semanage_handle_t * sh, char *storename,
272			   enum semanage_connect_type storetype)
273{
274
275	assert(sh != NULL);
276
277	/* This just sets the storename to what the user requests, no
278	   verification of existance will be done until connect */
279	free(sh->conf->store_path);
280	sh->conf->store_path = strdup(storename);
281	assert(sh->conf->store_path); /* no way to return failure */
282	sh->conf->store_type = storetype;
283
284	return;
285}
286
287void semanage_set_store_root(semanage_handle_t *sh, const char *store_root)
288{
289	assert(sh != NULL);
290
291	free(sh->conf->store_root_path);
292	sh->conf->store_root_path = strdup(store_root);
293	assert(sh->conf->store_root_path); /* no way to return failure */
294
295	return;
296}
297
298int semanage_is_managed(semanage_handle_t * sh)
299{
300	assert(sh != NULL);
301	if (sh->is_connected) {
302		ERR(sh, "Already connected.");
303		return -1;
304	}
305	switch (sh->conf->store_type) {
306	case SEMANAGE_CON_DIRECT:
307		return semanage_direct_is_managed(sh);
308	default:
309		ERR(sh,
310		    "The connection type specified within your semanage.conf file has not been implemented yet.");
311		/* fall through */
312	}
313	return -1;
314}
315
316int semanage_mls_enabled(semanage_handle_t * sh)
317{
318	assert(sh != NULL);
319	switch (sh->conf->store_type) {
320	case SEMANAGE_CON_DIRECT:
321		return semanage_direct_mls_enabled(sh);
322	default:
323		ERR(sh,
324		    "The connection type specified within your semanage.conf file has not been implemented yet.");
325		/* fall through */
326	}
327	return -1;
328}
329
330int semanage_connect(semanage_handle_t * sh)
331{
332	assert(sh != NULL);
333	switch (sh->conf->store_type) {
334	case SEMANAGE_CON_DIRECT:{
335			if (semanage_direct_connect(sh) < 0) {
336				return -1;
337			}
338			break;
339		}
340	default:{
341			ERR(sh,
342			    "The connection type specified within your semanage.conf file has not been implemented yet.");
343			return -1;
344		}
345	}
346	sh->is_connected = 1;
347	return 0;
348}
349
350int semanage_access_check(semanage_handle_t * sh)
351{
352	assert(sh != NULL);
353	switch (sh->conf->store_type) {
354	case SEMANAGE_CON_DIRECT:
355		return semanage_direct_access_check(sh);
356	default:
357		return -1;
358	}
359
360	return -1;		/* unreachable */
361}
362
363hidden_def(semanage_access_check)
364
365int semanage_disconnect(semanage_handle_t * sh)
366{
367	assert(sh != NULL && sh->funcs != NULL
368	       && sh->funcs->disconnect != NULL);
369	if (!sh->is_connected) {
370		return 0;
371	}
372	if (sh->funcs->disconnect(sh) < 0) {
373		return -1;
374	}
375	sh->is_in_transaction = 0;
376	sh->is_connected = 0;
377	sh->modules_modified = 0;
378	return 0;
379}
380
381void semanage_handle_destroy(semanage_handle_t * sh)
382{
383	if (sh == NULL)
384		return;
385
386	if (sh->funcs != NULL && sh->funcs->destroy != NULL)
387		sh->funcs->destroy(sh);
388	semanage_conf_destroy(sh->conf);
389	sepol_handle_destroy(sh->sepolh);
390	free(sh);
391}
392
393hidden_def(semanage_handle_destroy)
394
395/********************* public transaction functions *********************/
396int semanage_begin_transaction(semanage_handle_t * sh)
397{
398	assert(sh != NULL && sh->funcs != NULL
399	       && sh->funcs->begin_trans != NULL);
400	if (!sh->is_connected) {
401		ERR(sh, "Not connected.");
402		return -1;
403	}
404	if (sh->is_in_transaction) {
405		return 0;
406	}
407
408	if (sh->funcs->begin_trans(sh) < 0) {
409		return -1;
410	}
411	sh->is_in_transaction = 1;
412	return 0;
413}
414
415hidden_def(semanage_begin_transaction)
416
417int semanage_commit(semanage_handle_t * sh)
418{
419	int retval;
420	assert(sh != NULL && sh->funcs != NULL && sh->funcs->commit != NULL);
421	if (!sh->is_in_transaction) {
422		ERR(sh,
423		    "Will not commit because caller does not have a transaction lock yet.");
424		return -1;
425	}
426	retval = sh->funcs->commit(sh);
427	sh->is_in_transaction = 0;
428	sh->modules_modified = 0;
429	return retval;
430}
431