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
44asm(".symver semanage_module_get_enabled_1_1,semanage_module_get_enabled@@LIBSEMANAGE_1.1");
45asm(".symver semanage_module_get_enabled_1_0,semanage_module_get_enabled@LIBSEMANAGE_1.0");
46asm(".symver semanage_module_install_pp,semanage_module_install@LIBSEMANAGE_1.0");
47asm(".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 */
56static 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 */
88int 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
101cleanup:
102	free(name);
103	free(version);
104	return status;
105}
106
107int 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
126int 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 */
148int 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 */
158int 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 */
167int 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 */
176int 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
182int 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
199int 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
212void 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
227hidden_def(semanage_module_info_datum_destroy)
228
229semanage_module_info_t *semanage_module_list_nth(semanage_module_info_t * list,
230						 int n)
231{
232	return list + n;
233}
234
235hidden_def(semanage_module_list_nth)
236
237const char *semanage_module_get_name(semanage_module_info_t * modinfo)
238{
239	return modinfo->name;
240}
241
242hidden_def(semanage_module_get_name)
243
244/* Legacy function that remains to preserve ABI
245 * compatibility.
246 */
247const char *semanage_module_get_version(semanage_module_info_t * modinfo
248				__attribute__ ((unused)))
249{
250	return "";
251}
252
253int 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
265hidden_def(semanage_module_info_create)
266
267int 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
282hidden_def(semanage_module_info_destroy)
283
284int 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
298int 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
339cleanup:
340	if (status != 0) semanage_module_info_destroy(sh, target);
341	return status;
342}
343
344int 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
357hidden_def(semanage_module_info_get_priority)
358
359int 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
372hidden_def(semanage_module_info_get_name)
373
374int 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
387hidden_def(semanage_module_info_get_lang_ext)
388
389int 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
402hidden_def(semanage_module_info_get_enabled)
403
404int 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
423hidden_def(semanage_module_info_set_priority)
424
425int 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
454hidden_def(semanage_module_info_set_name)
455
456int 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
485hidden_def(semanage_module_info_set_lang_ext)
486
487int 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
506hidden_def(semanage_module_info_set_enabled)
507
508int 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
653cleanup:
654	return status;
655}
656
657int 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
669hidden_def(semanage_module_key_create)
670
671int 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
683hidden_def(semanage_module_key_destroy)
684
685int 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
697int 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
710hidden_def(semanage_module_key_get_name)
711
712int 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
725hidden_def(semanage_module_key_get_priority)
726
727int 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
754cleanup:
755	return status;
756}
757
758hidden_def(semanage_module_key_set_name)
759
760int 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
778hidden_def(semanage_module_key_set_priority)
779
780int 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
800int semanage_module_get_enabled_1_0(semanage_module_info_t *modinfo)
801{
802	return modinfo->enabled;
803}
804
805int 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
829hidden_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() */
833int 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
852exit:
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() */
861int 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
880exit:
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 */
892int 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
917exit:
918	return status;
919}
920
921/* Validates a module info struct.
922 *
923 * Returns -1 if module is invalid, 0 otherwise.
924 */
925int 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 */
943int 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 */
961int 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
990exit:
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 */
1000int 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 */
1018int 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
1044exit:
1045	return status;
1046}
1047
1048int 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
1068int 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
1088int 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
1109int 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