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