1 /* Author: Joshua Brindle <jbrindle@tresys.co
2  *	   Jason Tang	  <jtang@tresys.com>
3  *	   Caleb Case	  <ccase@tresys.com>
4  *
5  * Copyright (C) 2004-2005,2009 Tresys Technology, LLC
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 module functions to libsemanage. */
23 
24 #include "direct_api.h"
25 #include "semanage_conf.h"
26 #include "semanage_store.h"
27 
28 #include <stdarg.h>
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 #include <ctype.h>
39 
40 #include "handle.h"
41 #include "modules.h"
42 #include "debug.h"
43 
44 asm(".symver semanage_module_get_enabled_1_1,semanage_module_get_enabled@@LIBSEMANAGE_1.1");
45 asm(".symver semanage_module_get_enabled_1_0,semanage_module_get_enabled@LIBSEMANAGE_1.0");
46 asm(".symver semanage_module_install_pp,semanage_module_install@LIBSEMANAGE_1.0");
47 asm(".symver semanage_module_install_hll,semanage_module_install@@LIBSEMANAGE_1.1");
48 
49 /* Takes a module stored in 'module_data' and parses its headers.
50  * Sets reference variables 'module_name' to module's name and
51  * 'version' to module's version. The caller is responsible for
52  * free()ing 'module_name' and 'version'; they will be
53  * set to NULL upon entering this function.  Returns 0 on success, -1
54  * if out of memory, or -2 if data did not represent a module.
55  */
parse_module_headers(semanage_handle_t * sh,char * module_data,size_t data_len,char ** module_name,char ** version)56 static int parse_module_headers(semanage_handle_t * sh, char *module_data,
57 				size_t data_len, char **module_name, char **version)
58 {
59 	struct sepol_policy_file *pf;
60 	int file_type;
61 	*version = NULL;
62 
63 	if (sepol_policy_file_create(&pf)) {
64 		ERR(sh, "Out of memory!");
65 		return -1;
66 	}
67 	sepol_policy_file_set_mem(pf, module_data, data_len);
68 	sepol_policy_file_set_handle(pf, sh->sepolh);
69 	if (module_data == NULL ||
70 	    data_len == 0 ||
71 	    sepol_module_package_info(pf, &file_type, module_name, version) == -1) {
72 		sepol_policy_file_free(pf);
73 		ERR(sh, "Could not parse module data.");
74 		return -2;
75 	}
76 	sepol_policy_file_free(pf);
77 	if (file_type != SEPOL_POLICY_MOD) {
78 		ERR(sh, "Data did not represent a pp module. Please upgrade to the latest version of libsemanage to support hll modules.");
79 		return -2;
80 	}
81 
82 	return 0;
83 }
84 
85 /* This function is used to preserve ABI compatibility with
86  * versions of semodule using LIBSEMANAGE_1.0
87  */
semanage_module_install_pp(semanage_handle_t * sh,char * module_data,size_t data_len)88 int semanage_module_install_pp(semanage_handle_t * sh,
89 			    char *module_data, size_t data_len)
90 {
91 	char *name = NULL;
92 	char *version = NULL;
93 	int status;
94 
95 	if ((status = parse_module_headers(sh, module_data, data_len, &name, &version)) != 0) {
96 		goto cleanup;
97 	}
98 
99 	status = semanage_module_install_hll(sh, module_data, data_len, name, "pp");
100 
101 cleanup:
102 	free(name);
103 	free(version);
104 	return status;
105 }
106 
semanage_module_install_hll(semanage_handle_t * sh,char * module_data,size_t data_len,const char * name,const char * ext_lang)107 int semanage_module_install_hll(semanage_handle_t * sh,
108 			    char *module_data, size_t data_len, const char *name, const char *ext_lang)
109 {
110 	if (sh->funcs->install == NULL) {
111 		ERR(sh,
112 		    "No install function defined for this connection type.");
113 		return -1;
114 	} else if (!sh->is_connected) {
115 		ERR(sh, "Not connected.");
116 		return -1;
117 	} else if (!sh->is_in_transaction) {
118 		if (semanage_begin_transaction(sh) < 0) {
119 			return -1;
120 		}
121 	}
122 	sh->modules_modified = 1;
123 	return sh->funcs->install(sh, module_data, data_len, name, ext_lang);
124 }
125 
semanage_module_install_file(semanage_handle_t * sh,const char * module_name)126 int semanage_module_install_file(semanage_handle_t * sh,
127 				 const char *module_name) {
128 
129 	if (sh->funcs->install_file == NULL) {
130 		ERR(sh,
131 		    "No install function defined for this connection type.");
132 		return -1;
133 	} else if (!sh->is_connected) {
134 		ERR(sh, "Not connected.");
135 		return -1;
136 	} else if (!sh->is_in_transaction) {
137 		if (semanage_begin_transaction(sh) < 0) {
138 			return -1;
139 		}
140 	}
141 	sh->modules_modified = 1;
142 	return sh->funcs->install_file(sh, module_name);
143 }
144 
145 /* Legacy function that remains to preserve ABI
146  * compatibility. Please use semanage_module_install instead.
147  */
semanage_module_upgrade(semanage_handle_t * sh,char * module_data,size_t data_len)148 int semanage_module_upgrade(semanage_handle_t * sh,
149 			    char *module_data, size_t data_len)
150 {
151 	return semanage_module_install_pp(sh, module_data, data_len);
152 
153 }
154 
155 /* Legacy function that remains to preserve ABI
156  * compatibility. Please use semanage_module_install_file instead.
157  */
semanage_module_upgrade_file(semanage_handle_t * sh,const char * module_name)158 int semanage_module_upgrade_file(semanage_handle_t * sh,
159 				 const char *module_name)
160 {
161 	return semanage_module_install_file(sh, module_name);
162 }
163 
164 /* Legacy function that remains to preserve ABI
165  * compatibility. Please use semanage_module_install instead.
166  */
semanage_module_install_base(semanage_handle_t * sh,char * module_data,size_t data_len)167 int semanage_module_install_base(semanage_handle_t * sh,
168 				 char *module_data, size_t data_len)
169 {
170 	return semanage_module_install_pp(sh, module_data, data_len);
171 }
172 
173 /* Legacy function that remains to preserve ABI
174  * compatibility. Please use semanage_module_install_file instead.
175  */
semanage_module_install_base_file(semanage_handle_t * sh,const char * module_name)176 int semanage_module_install_base_file(semanage_handle_t * sh,
177 				 const char *module_name)
178 {
179 	return semanage_module_install_file(sh, module_name);
180 }
181 
semanage_module_remove(semanage_handle_t * sh,char * module_name)182 int semanage_module_remove(semanage_handle_t * sh, char *module_name)
183 {
184 	if (sh->funcs->remove == NULL) {
185 		ERR(sh, "No remove function defined for this connection type.");
186 		return -1;
187 	} else if (!sh->is_connected) {
188 		ERR(sh, "Not connected.");
189 		return -1;
190 	} else if (!sh->is_in_transaction) {
191 		if (semanage_begin_transaction(sh) < 0) {
192 			return -1;
193 		}
194 	}
195 	sh->modules_modified = 1;
196 	return sh->funcs->remove(sh, module_name);
197 }
198 
semanage_module_list(semanage_handle_t * sh,semanage_module_info_t ** modinfo,int * num_modules)199 int semanage_module_list(semanage_handle_t * sh,
200 			 semanage_module_info_t ** modinfo, int *num_modules)
201 {
202 	if (sh->funcs->list == NULL) {
203 		ERR(sh, "No list function defined for this connection type.");
204 		return -1;
205 	} else if (!sh->is_connected) {
206 		ERR(sh, "Not connected.");
207 		return -1;
208 	}
209 	return sh->funcs->list(sh, modinfo, num_modules);
210 }
211 
semanage_module_info_datum_destroy(semanage_module_info_t * modinfo)212 void semanage_module_info_datum_destroy(semanage_module_info_t * modinfo)
213 {
214 	if (modinfo != NULL) {
215 		modinfo->priority = 0;
216 
217 		free(modinfo->name);
218 		modinfo->name = NULL;
219 
220 		free(modinfo->lang_ext);
221 		modinfo->lang_ext = NULL;
222 
223 		modinfo->enabled = -1;
224 	}
225 }
226 
hidden_def(semanage_module_info_datum_destroy)227 hidden_def(semanage_module_info_datum_destroy)
228 
229 semanage_module_info_t *semanage_module_list_nth(semanage_module_info_t * list,
230 						 int n)
231 {
232 	return list + n;
233 }
234 
hidden_def(semanage_module_list_nth)235 hidden_def(semanage_module_list_nth)
236 
237 const char *semanage_module_get_name(semanage_module_info_t * modinfo)
238 {
239 	return modinfo->name;
240 }
241 
hidden_def(semanage_module_get_name)242 hidden_def(semanage_module_get_name)
243 
244 /* Legacy function that remains to preserve ABI
245  * compatibility.
246  */
247 const char *semanage_module_get_version(semanage_module_info_t * modinfo
248 				__attribute__ ((unused)))
249 {
250 	return "";
251 }
252 
semanage_module_info_create(semanage_handle_t * sh,semanage_module_info_t ** modinfo)253 int semanage_module_info_create(semanage_handle_t *sh,
254 				semanage_module_info_t **modinfo)
255 {
256 	assert(sh);
257 	assert(modinfo);
258 
259 	*modinfo = malloc(sizeof(semanage_module_info_t));
260 	if (*modinfo == NULL) return -1;
261 
262 	return semanage_module_info_init(sh, *modinfo);
263 }
264 
hidden_def(semanage_module_info_create)265 hidden_def(semanage_module_info_create)
266 
267 int semanage_module_info_destroy(semanage_handle_t *sh,
268 				 semanage_module_info_t *modinfo)
269 {
270 	assert(sh);
271 
272 	if (!modinfo) {
273 		return 0;
274 	}
275 
276 	free(modinfo->name);
277 	free(modinfo->lang_ext);
278 
279 	return semanage_module_info_init(sh, modinfo);
280 }
281 
hidden_def(semanage_module_info_destroy)282 hidden_def(semanage_module_info_destroy)
283 
284 int semanage_module_info_init(semanage_handle_t *sh,
285 			      semanage_module_info_t *modinfo)
286 {
287 	assert(sh);
288 	assert(modinfo);
289 
290 	modinfo->priority = 0;
291 	modinfo->name = NULL;
292 	modinfo->lang_ext = NULL;
293 	modinfo->enabled = -1;
294 
295 	return 0;
296 }
297 
semanage_module_info_clone(semanage_handle_t * sh,const semanage_module_info_t * source,semanage_module_info_t * target)298 int semanage_module_info_clone(semanage_handle_t *sh,
299 			       const semanage_module_info_t *source,
300 			       semanage_module_info_t *target)
301 {
302 	assert(sh);
303 	assert(source);
304 	assert(target);
305 
306 	int status = 0;
307 	int ret = 0;
308 
309 	ret = semanage_module_info_destroy(sh, target);
310 	if (ret != 0) {
311 		status = -1;
312 		goto cleanup;
313 	}
314 
315 	ret = semanage_module_info_set_priority(sh, target, source->priority);
316 	if (ret != 0) {
317 		status = -1;
318 		goto cleanup;
319 	}
320 
321 	ret = semanage_module_info_set_name(sh, target, source->name);
322 	if (ret != 0) {
323 		status = -1;
324 		goto cleanup;
325 	}
326 
327 	ret = semanage_module_info_set_lang_ext(sh, target, source->lang_ext);
328 	if (ret != 0) {
329 		status = -1;
330 		goto cleanup;
331 	}
332 
333 	ret = semanage_module_info_set_enabled(sh, target, source->enabled);
334 	if (ret != 0) {
335 		status = -1;
336 		goto cleanup;
337 	}
338 
339 cleanup:
340 	if (status != 0) semanage_module_info_destroy(sh, target);
341 	return status;
342 }
343 
semanage_module_info_get_priority(semanage_handle_t * sh,semanage_module_info_t * modinfo,uint16_t * priority)344 int semanage_module_info_get_priority(semanage_handle_t *sh,
345 				      semanage_module_info_t *modinfo,
346 				      uint16_t *priority)
347 {
348 	assert(sh);
349 	assert(modinfo);
350 	assert(priority);
351 
352 	*priority = modinfo->priority;
353 
354 	return 0;
355 }
356 
hidden_def(semanage_module_info_get_priority)357 hidden_def(semanage_module_info_get_priority)
358 
359 int semanage_module_info_get_name(semanage_handle_t *sh,
360 				  semanage_module_info_t *modinfo,
361 				  const char **name)
362 {
363 	assert(sh);
364 	assert(modinfo);
365 	assert(name);
366 
367 	*name = modinfo->name;
368 
369 	return 0;
370 }
371 
hidden_def(semanage_module_info_get_name)372 hidden_def(semanage_module_info_get_name)
373 
374 int semanage_module_info_get_lang_ext(semanage_handle_t *sh,
375 				      semanage_module_info_t *modinfo,
376 				      const char **lang_ext)
377 {
378 	assert(sh);
379 	assert(modinfo);
380 	assert(lang_ext);
381 
382 	*lang_ext = modinfo->lang_ext;
383 
384 	return 0;
385 }
386 
hidden_def(semanage_module_info_get_lang_ext)387 hidden_def(semanage_module_info_get_lang_ext)
388 
389 int semanage_module_info_get_enabled(semanage_handle_t *sh,
390 				     semanage_module_info_t *modinfo,
391 				     int *enabled)
392 {
393 	assert(sh);
394 	assert(modinfo);
395 	assert(enabled);
396 
397 	*enabled = modinfo->enabled;
398 
399 	return 0;
400 }
401 
hidden_def(semanage_module_info_get_enabled)402 hidden_def(semanage_module_info_get_enabled)
403 
404 int semanage_module_info_set_priority(semanage_handle_t *sh,
405 				      semanage_module_info_t *modinfo,
406 				      uint16_t priority)
407 {
408 	assert(sh);
409 	assert(modinfo);
410 
411 	/* Verify priority */
412 	if (semanage_module_validate_priority(priority) < 0) {
413 		errno = 0;
414 		ERR(sh, "Priority %d is invalid.", priority);
415 		return -1;
416 	}
417 
418 	modinfo->priority = priority;
419 
420 	return 0;
421 }
422 
hidden_def(semanage_module_info_set_priority)423 hidden_def(semanage_module_info_set_priority)
424 
425 int semanage_module_info_set_name(semanage_handle_t *sh,
426 				  semanage_module_info_t *modinfo,
427 				  const char *name)
428 {
429 	assert(sh);
430 	assert(modinfo);
431 	assert(name);
432 
433 	char * tmp;
434 
435 	/* Verify name */
436 	if (semanage_module_validate_name(name) < 0) {
437 		errno = 0;
438 		ERR(sh, "Name %s is invalid.", name);
439 		return -1;
440 	}
441 
442 	tmp = strdup(name);
443 	if (!tmp) {
444 		ERR(sh, "No memory available for strdup");
445 		return -1;
446 	}
447 
448 	free(modinfo->name);
449 	modinfo->name = tmp;
450 
451 	return 0;
452 }
453 
hidden_def(semanage_module_info_set_name)454 hidden_def(semanage_module_info_set_name)
455 
456 int semanage_module_info_set_lang_ext(semanage_handle_t *sh,
457 				      semanage_module_info_t *modinfo,
458 				      const char *lang_ext)
459 {
460 	assert(sh);
461 	assert(modinfo);
462 	assert(lang_ext);
463 
464 	char * tmp;
465 
466 	/* Verify extension */
467 	if (semanage_module_validate_lang_ext(lang_ext) < 0) {
468 		errno = 0;
469 		ERR(sh, "Language extensions %s is invalid.", lang_ext);
470 		return -1;
471 	}
472 
473 	tmp = strdup(lang_ext);
474 	if (!tmp) {
475 		ERR(sh, "No memory available for strdup");
476 		return -1;
477 	}
478 
479 	free(modinfo->lang_ext);
480 	modinfo->lang_ext = tmp;
481 
482 	return 0;
483 }
484 
hidden_def(semanage_module_info_set_lang_ext)485 hidden_def(semanage_module_info_set_lang_ext)
486 
487 int semanage_module_info_set_enabled(semanage_handle_t *sh,
488 				     semanage_module_info_t *modinfo,
489 				     int enabled)
490 {
491 	assert(sh);
492 	assert(modinfo);
493 
494 	/* Verify enabled */
495 	if (semanage_module_validate_enabled(enabled) < 0) {
496 		errno = 0;
497 		ERR(sh, "Enabled status %d is invalid.", enabled);
498 		return -1;
499 	}
500 
501 	modinfo->enabled = enabled;
502 
503 	return 0;
504 }
505 
hidden_def(semanage_module_info_set_enabled)506 hidden_def(semanage_module_info_set_enabled)
507 
508 int semanage_module_get_path(semanage_handle_t *sh,
509 			     const semanage_module_info_t *modinfo,
510 			     enum semanage_module_path_type type,
511 			     char *path,
512 			     size_t len)
513 {
514 	assert(sh);
515 	assert(modinfo);
516 	assert(path);
517 
518 	int status = 0;
519 	int ret = 0;
520 
521 	const char *modules_path = NULL;
522 	const char *file = NULL;
523 
524 	modules_path = sh->is_in_transaction ?
525 		semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES):
526 		semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
527 
528 	switch (type) {
529 		case SEMANAGE_MODULE_PATH_PRIORITY:
530 			/* verify priority */
531 			ret = semanage_module_validate_priority(modinfo->priority);
532 			if (ret < 0) {
533 				errno = 0;
534 				ERR(sh,
535 				    "Priority %d is invalid.",
536 				    modinfo->priority);
537 				status = ret;
538 				goto cleanup;
539 			}
540 
541 			ret = snprintf(path,
542 				       len,
543 				       "%s/%03u",
544 				       modules_path,
545 				       modinfo->priority);
546 			if (ret < 0 || (size_t)ret >= len) {
547 				ERR(sh, "Unable to compose priority path.");
548 				status = -1;
549 				goto cleanup;
550 			}
551 			break;
552 		case SEMANAGE_MODULE_PATH_NAME:
553 			/* verify priority and name */
554 			ret = semanage_module_validate_priority(modinfo->priority);
555 			if (ret < 0) {
556 				errno = 0;
557 				ERR(sh,
558 				    "Priority %d is invalid.",
559 				    modinfo->priority);
560 				status = -1;
561 				goto cleanup;
562 			}
563 
564 			ret = semanage_module_validate_name(modinfo->name);
565 			if (ret < 0) {
566 				errno = 0;
567 				ERR(sh, "Name %s is invalid.", modinfo->name);
568 				status = -1;
569 				goto cleanup;
570 			}
571 
572 			ret = snprintf(path,
573 				       len,
574 				       "%s/%03u/%s",
575 				       modules_path,
576 				       modinfo->priority,
577 				       modinfo->name);
578 			if (ret < 0 || (size_t)ret >= len) {
579 				ERR(sh, "Unable to compose name path.");
580 				status = -1;
581 				goto cleanup;
582 			}
583 			break;
584 		case SEMANAGE_MODULE_PATH_HLL:
585 			if (file == NULL) file = "hll";
586 		case SEMANAGE_MODULE_PATH_CIL:
587 			if (file == NULL) file = "cil";
588 		case SEMANAGE_MODULE_PATH_LANG_EXT:
589 			if (file == NULL) file = "lang_ext";
590 
591 			/* verify priority and name */
592 			ret = semanage_module_validate_priority(modinfo->priority);
593 			if (ret < 0) {
594 				errno = 0;
595 				ERR(sh,
596 				    "Priority %d is invalid.",
597 				    modinfo->priority);
598 				status = -1;
599 				goto cleanup;
600 			}
601 
602 			ret = semanage_module_validate_name(modinfo->name);
603 			if (ret < 0) {
604 				errno = 0;
605 				ERR(sh, "Name %s is invalid.", modinfo->name);
606 				status = -1;
607 				goto cleanup;
608 			}
609 
610 			ret = snprintf(path,
611 				       len,
612 				       "%s/%03u/%s/%s",
613 				       modules_path,
614 				       modinfo->priority,
615 				       modinfo->name,
616 				       file);
617 			if (ret < 0 || (size_t)ret >= len) {
618 				ERR(sh,
619 				    "Unable to compose path for %s file.",
620 				    file);
621 				status = -1;
622 				goto cleanup;
623 			}
624 			break;
625 		case SEMANAGE_MODULE_PATH_DISABLED:
626 			/* verify name */
627 			ret = semanage_module_validate_name(modinfo->name);
628 			if (ret < 0) {
629 				errno = 0;
630 				ERR(sh, "Name %s is invalid.", modinfo->name);
631 				status = -1;
632 				goto cleanup;
633 			}
634 
635 			ret = snprintf(path,
636 				       len,
637 				       "%s/disabled/%s",
638 				       modules_path,
639 				       modinfo->name);
640 			if (ret < 0 || (size_t)ret >= len) {
641 				ERR(sh,
642 				    "Unable to compose disabled status path.");
643 				status = -1;
644 				goto cleanup;
645 			}
646 			break;
647 		default:
648 			ERR(sh, "Invalid module path type %d.", type);
649 			status = -1;
650 			goto cleanup;
651 	}
652 
653 cleanup:
654 	return status;
655 }
656 
semanage_module_key_create(semanage_handle_t * sh,semanage_module_key_t ** modkey)657 int semanage_module_key_create(semanage_handle_t *sh,
658 			       semanage_module_key_t **modkey)
659 {
660 	assert(sh);
661 	assert(modkey);
662 
663 	*modkey = malloc(sizeof(semanage_module_key_t));
664 	if (*modkey == NULL) return -1;
665 
666 	return semanage_module_key_init(sh, *modkey);
667 }
668 
hidden_def(semanage_module_key_create)669 hidden_def(semanage_module_key_create)
670 
671 int semanage_module_key_destroy(semanage_handle_t *sh,
672 				semanage_module_key_t *modkey)
673 {
674 	assert(sh);
675 
676 	if (modkey) {
677 		free(modkey->name);
678 	}
679 
680 	return semanage_module_key_init(sh, modkey);
681 }
682 
hidden_def(semanage_module_key_destroy)683 hidden_def(semanage_module_key_destroy)
684 
685 int semanage_module_key_init(semanage_handle_t *sh,
686 			     semanage_module_key_t *modkey)
687 {
688 	assert(sh);
689 	assert(modkey);
690 
691 	modkey->name = NULL;
692 	modkey->priority = 0;
693 
694 	return 0;
695 }
696 
semanage_module_key_get_name(semanage_handle_t * sh,semanage_module_key_t * modkey,const char ** name)697 int semanage_module_key_get_name(semanage_handle_t *sh,
698 				 semanage_module_key_t *modkey,
699 				 const char **name)
700 {
701 	assert(sh);
702 	assert(modkey);
703 	assert(name);
704 
705 	*name = modkey->name;
706 
707 	return 0;
708 }
709 
hidden_def(semanage_module_key_get_name)710 hidden_def(semanage_module_key_get_name)
711 
712 int semanage_module_key_get_priority(semanage_handle_t *sh,
713 				     semanage_module_key_t *modkey,
714 				     uint16_t *priority)
715 {
716 	assert(sh);
717 	assert(modkey);
718 	assert(priority);
719 
720 	*priority = modkey->priority;
721 
722 	return 0;
723 }
724 
hidden_def(semanage_module_key_get_priority)725 hidden_def(semanage_module_key_get_priority)
726 
727 int semanage_module_key_set_name(semanage_handle_t *sh,
728 				 semanage_module_key_t *modkey,
729 				 const char *name)
730 {
731 	assert(sh);
732 	assert(modkey);
733 	assert(name);
734 
735 	int status = 0;
736 	char *tmp = NULL;
737 
738 	if (semanage_module_validate_name(name) < 0) {
739 		errno = 0;
740 		ERR(sh, "Name %s is invalid.", name);
741 		return -1;
742 	}
743 
744 	tmp = strdup(name);
745 	if (tmp == NULL) {
746 		ERR(sh, "No memory available for strdup");
747 		status = -1;
748 		goto cleanup;
749 	}
750 
751 	free(modkey->name);
752 	modkey->name = tmp;
753 
754 cleanup:
755 	return status;
756 }
757 
hidden_def(semanage_module_key_set_name)758 hidden_def(semanage_module_key_set_name)
759 
760 int semanage_module_key_set_priority(semanage_handle_t *sh,
761 				     semanage_module_key_t *modkey,
762 				     uint16_t priority)
763 {
764 	assert(sh);
765 	assert(modkey);
766 
767 	if (semanage_module_validate_priority(priority) < 0) {
768 		errno = 0;
769 		ERR(sh, "Priority %d is invalid.", priority);
770 		return -1;
771 	}
772 
773 	modkey->priority = priority;
774 
775 	return 0;
776 }
777 
hidden_def(semanage_module_key_set_priority)778 hidden_def(semanage_module_key_set_priority)
779 
780 int semanage_module_get_enabled_1_1(semanage_handle_t *sh,
781 				const semanage_module_key_t *modkey,
782 				int *enabled)
783 {
784 	assert(sh);
785 	assert(modkey);
786 	assert(enabled);
787 
788 	if (sh->funcs->get_enabled == NULL) {
789 		ERR(sh,
790 		    "No get_enabled function defined for this connection type.");
791 		return -1;
792 	} else if (!sh->is_connected) {
793 		ERR(sh, "Not connected.");
794 		return -1;
795 	}
796 
797 	return sh->funcs->get_enabled(sh, modkey, enabled);
798 }
799 
semanage_module_get_enabled_1_0(semanage_module_info_t * modinfo)800 int semanage_module_get_enabled_1_0(semanage_module_info_t *modinfo)
801 {
802 	return modinfo->enabled;
803 }
804 
semanage_module_set_enabled(semanage_handle_t * sh,const semanage_module_key_t * modkey,int enabled)805 int semanage_module_set_enabled(semanage_handle_t *sh,
806 				const semanage_module_key_t *modkey,
807 				int enabled)
808 {
809 	assert(sh);
810 	assert(modkey);
811 
812 	if (sh->funcs->set_enabled == NULL) {
813 		ERR(sh,
814 		    "No set_enabled function defined for this connection type.");
815 		return -1;
816 	} else if (!sh->is_connected) {
817 		ERR(sh, "Not connected.");
818 		return -1;
819 	} else if (!sh->is_in_transaction) {
820 		if (semanage_begin_transaction(sh) < 0) {
821 			return -1;
822 		}
823 	}
824 
825 	sh->modules_modified = 1;
826 	return sh->funcs->set_enabled(sh, modkey, enabled);
827 }
828 
hidden_def(semanage_module_set_enabled)829 hidden_def(semanage_module_set_enabled)
830 
831 /* This function exists only for ABI compatability. It has been deprecated and
832  * should not be used. Instead, use semanage_module_set_enabled() */
833 int semanage_module_enable(semanage_handle_t *sh, char *module_name)
834 {
835 	int rc = -1;
836 	semanage_module_key_t *modkey = NULL;
837 
838 	rc = semanage_module_key_create(sh, &modkey);
839 	if (rc != 0)
840 		goto exit;
841 
842 	rc = semanage_module_key_set_name(sh, modkey, module_name);
843 	if (rc != 0)
844 		goto exit;
845 
846 	rc = semanage_module_set_enabled(sh, modkey, 1);
847 	if (rc != 0)
848 		goto exit;
849 
850 	rc = 0;
851 
852 exit:
853 	semanage_module_key_destroy(sh, modkey);
854 	free(modkey);
855 
856 	return rc;
857 }
858 
859 /* This function exists only for ABI compatability. It has been deprecated and
860  * should not be used. Instead, use semanage_module_set_enabled() */
semanage_module_disable(semanage_handle_t * sh,char * module_name)861 int semanage_module_disable(semanage_handle_t *sh, char *module_name)
862 {
863 	int rc = -1;
864 	semanage_module_key_t *modkey = NULL;
865 
866 	rc = semanage_module_key_create(sh, &modkey);
867 	if (rc != 0)
868 		goto exit;
869 
870 	rc = semanage_module_key_set_name(sh, modkey, module_name);
871 	if (rc != 0)
872 		goto exit;
873 
874 	rc = semanage_module_set_enabled(sh, modkey, 0);
875 	if (rc != 0)
876 		goto exit;
877 
878 	rc = 0;
879 
880 exit:
881 	semanage_module_key_destroy(sh, modkey);
882 	free(modkey);
883 
884 	return rc;
885 }
886 
887 /* Converts a string to a priority
888  *
889  * returns -1 if str is not a valid priority.
890  * returns 0 and sets priority if str is a valid priority
891  */
semanage_string_to_priority(const char * str,uint16_t * priority)892 int semanage_string_to_priority(const char *str, uint16_t *priority)
893 {
894 	unsigned long val;
895 	char *endptr = NULL;
896 	int status = -1;
897 
898 	if (str == NULL || priority == NULL) {
899 		goto exit;
900 	}
901 
902 	errno = 0;
903 
904 	val = strtoul(str, &endptr, 10);
905 
906 	if (errno != 0 || endptr == str || *endptr != '\0' || val > UINT16_MAX) {
907 		goto exit;
908 	}
909 
910 	if (semanage_module_validate_priority((uint16_t)val) < 0) {
911 		goto exit;
912 	}
913 
914 	*priority = val;
915 	status = 0;
916 
917 exit:
918 	return status;
919 }
920 
921 /* Validates a module info struct.
922  *
923  * Returns -1 if module is invalid, 0 otherwise.
924  */
semanage_module_info_validate(const semanage_module_info_t * modinfo)925 int semanage_module_info_validate(const semanage_module_info_t *modinfo)
926 {
927 	if (semanage_module_validate_priority(modinfo->priority) != 0 ||
928 	    semanage_module_validate_name(modinfo->name) != 0 ||
929 	    semanage_module_validate_lang_ext(modinfo->lang_ext) != 0 ||
930 	    semanage_module_validate_enabled(modinfo->enabled) != 0) {
931 		return -1;
932 	}
933 	return 0;
934 }
935 
936 #define PRIORITY_MIN 1
937 #define PRIORITY_MAX 999
938 
939 /* Validates priority.
940  *
941  * returns -1 if priority is not in the valid range, returns 0 otherwise
942  */
semanage_module_validate_priority(uint16_t priority)943 int semanage_module_validate_priority(uint16_t priority)
944 {
945 	if (priority >= PRIORITY_MIN && priority <= PRIORITY_MAX) {
946 		return 0;
947 	}
948 
949 	return -1;
950 }
951 
952 /* Validates module name.
953  *
954  * A module name must match one of the following regular expressions
955  * to be considered valid:
956  *
957  * ^[a-zA-Z](\.?[a-zA-Z0-9_-])*$
958  *
959  * returns -1 if name is not valid, returns 0 otherwise
960  */
semanage_module_validate_name(const char * name)961 int semanage_module_validate_name(const char * name)
962 {
963 	int status = 0;
964 
965 	if (name == NULL) {
966 		status = -1;
967 		goto exit;
968 	}
969 
970 	if (!isalpha(*name)) {
971 		status = -1;
972 		goto exit;
973 	}
974 
975 #define ISVALIDCHAR(c) (isalnum(c) || c == '_' || c == '-')
976 
977 	for (name++; *name; name++) {
978 		if (ISVALIDCHAR(*name)) {
979 			continue;
980 		}
981 		if (*name == '.' && name++ && ISVALIDCHAR(*name)) {
982 			continue;
983 		}
984 		status = -1;
985 		goto exit;
986 	}
987 
988 #undef ISVALIDCHAR
989 
990 exit:
991 	return status;
992 }
993 
994 /* Validates module enabled status.
995  *
996  * Valid enabled values are 1, 0, and -1.
997  *
998  * returns 0 if enabled is a valid value, returns -1 otherwise.
999  */
semanage_module_validate_enabled(int enabled)1000 int semanage_module_validate_enabled(int enabled)
1001 {
1002 	if (enabled == 1 || enabled == 0 || enabled == -1) {
1003 		return 0;
1004 	}
1005 
1006 	return -1;
1007 }
1008 
1009 /* Validate extension.
1010  *
1011  * An extension must match the following regular expression to be
1012  * considered valid:
1013  *
1014  * ^[a-zA-Z0-9][a-zA-Z0-9_-]*$
1015  *
1016  * returns 0 if ext is a valid value, returns -1 otherwise.
1017  */
semanage_module_validate_lang_ext(const char * ext)1018 int semanage_module_validate_lang_ext(const char *ext)
1019 {
1020 	int status = 0;
1021 
1022 	if (ext == NULL) {
1023 		status = -1;
1024 		goto exit;
1025 	}
1026 
1027 	if (!isalnum(*ext)) {
1028 		status = -1;
1029 		goto exit;
1030 	}
1031 
1032 #define ISVALIDCHAR(c) (isalnum(c) || c == '_' || c == '-')
1033 
1034 	for (ext++; *ext; ext++) {
1035 		if (ISVALIDCHAR(*ext)) {
1036 			continue;
1037 		}
1038 		status = -1;
1039 		goto exit;
1040 	}
1041 
1042 #undef ISVALIDCHAR
1043 
1044 exit:
1045 	return status;
1046 }
1047 
semanage_module_get_module_info(semanage_handle_t * sh,const semanage_module_key_t * modkey,semanage_module_info_t ** modinfo)1048 int semanage_module_get_module_info(semanage_handle_t *sh,
1049 				    const semanage_module_key_t *modkey,
1050 				    semanage_module_info_t **modinfo)
1051 {
1052 	assert(sh);
1053 	assert(modkey);
1054 	assert(modinfo);
1055 
1056 	if (sh->funcs->get_module_info == NULL) {
1057 		ERR(sh,
1058 		    "No get module info function defined for this connection type.");
1059 		return -1;
1060 	} else if (!sh->is_connected) {
1061 		ERR(sh, "Not connected.");
1062 		return -1;
1063 	}
1064 
1065 	return sh->funcs->get_module_info(sh, modkey, modinfo);
1066 }
1067 
semanage_module_list_all(semanage_handle_t * sh,semanage_module_info_t ** modinfos,int * modinfos_len)1068 int semanage_module_list_all(semanage_handle_t *sh,
1069 			     semanage_module_info_t **modinfos,
1070 			     int *modinfos_len)
1071 {
1072 	assert(sh);
1073 	assert(modinfos);
1074 	assert(modinfos_len);
1075 
1076 	if (sh->funcs->list_all == NULL) {
1077 		ERR(sh,
1078 		    "No list all function defined for this connection type.");
1079 		return -1;
1080 	} else if (!sh->is_connected) {
1081 		ERR(sh, "Not connected.");
1082 		return -1;
1083 	}
1084 
1085 	return sh->funcs->list_all(sh, modinfos, modinfos_len);
1086 }
1087 
semanage_module_install_info(semanage_handle_t * sh,const semanage_module_info_t * modinfo,char * data,size_t data_len)1088 int semanage_module_install_info(semanage_handle_t *sh,
1089 				 const semanage_module_info_t *modinfo,
1090 				 char *data,
1091 				 size_t data_len)
1092 {
1093 	if (sh->funcs->install_info == NULL) {
1094 		ERR(sh,
1095 		    "No install info function defined for this connection type.");
1096 		return -1;
1097 	} else if (!sh->is_connected) {
1098 		ERR(sh, "Not connected.");
1099 		return -1;
1100 	} else if (!sh->is_in_transaction) {
1101 		if (semanage_begin_transaction(sh) < 0) {
1102 			return -1;
1103 		}
1104 	}
1105 	sh->modules_modified = 1;
1106 	return sh->funcs->install_info(sh, modinfo, data, data_len);
1107 }
1108 
semanage_module_remove_key(semanage_handle_t * sh,const semanage_module_key_t * modkey)1109 int semanage_module_remove_key(semanage_handle_t *sh,
1110 			       const semanage_module_key_t *modkey)
1111 {
1112 	if (sh->funcs->remove_key== NULL) {
1113 		ERR(sh,
1114 		    "No remove key function defined for this connection type.");
1115 		return -1;
1116 	} else if (!sh->is_connected) {
1117 		ERR(sh, "Not connected.");
1118 		return -1;
1119 	} else if (!sh->is_in_transaction) {
1120 		if (semanage_begin_transaction(sh) < 0) {
1121 			return -1;
1122 		}
1123 	}
1124 	sh->modules_modified = 1;
1125 	return sh->funcs->remove_key(sh, modkey);
1126 }
1127 
1128