kernel_to_conf.c revision 0a08fd1e69797d6ab315ee17d797ef12dae25ce9
1#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <inttypes.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9#include <arpa/inet.h>
10#include <netinet/in.h>
11#ifndef IPPROTO_DCCP
12#define IPPROTO_DCCP 33
13#endif
14
15#include <sepol/policydb/avtab.h>
16#include <sepol/policydb/conditional.h>
17#include <sepol/policydb/flask.h>
18#include <sepol/policydb/hashtab.h>
19#include <sepol/policydb/polcaps.h>
20#include <sepol/policydb/policydb.h>
21#include <sepol/policydb/services.h>
22#include <sepol/policydb/util.h>
23
24#include "kernel_to_common.h"
25
26
27static char *cond_expr_to_str(struct policydb *pdb, struct cond_expr *expr)
28{
29	struct cond_expr *curr;
30	struct strs *stack;
31	char *new_val;
32	char *str = NULL;
33	int rc;
34
35	rc = stack_init(&stack);
36	if (rc != 0) {
37		goto exit;
38	}
39
40	for (curr = expr; curr != NULL; curr = curr->next) {
41		if (curr->expr_type == COND_BOOL) {
42			char *val1 = pdb->p_bool_val_to_name[curr->bool - 1];
43			new_val = create_str("%s", 1, val1);
44		} else {
45			const char *op;
46			uint32_t num_params;
47			char *val1 = NULL;
48			char *val2 = NULL;
49
50			switch(curr->expr_type) {
51			case COND_NOT:	op = "!";  num_params = 1; break;
52			case COND_OR:	op = "||"; num_params = 2; break;
53			case COND_AND:	op = "&&"; num_params = 2; break;
54			case COND_XOR:	op = "^";  num_params = 2; break;
55			case COND_EQ:	op = "=="; num_params = 2; break;
56			case COND_NEQ:	op = "!="; num_params = 2; break;
57			default:
58				sepol_log_err("Unknown conditional operator: %i", curr->expr_type);
59				goto exit;
60			}
61
62			if (num_params == 2) {
63				val2 = stack_pop(stack);
64				if (!val2) {
65					sepol_log_err("Invalid conditional expression");
66					goto exit;
67				}
68			}
69			val1 = stack_pop(stack);
70			if (!val1) {
71				sepol_log_err("Invalid conditional expression");
72				free(val2);
73				goto exit;
74			}
75			if (num_params == 2) {
76				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
77				free(val2);
78			} else {
79				new_val = create_str("%s %s", 2, op, val1);
80			}
81			free(val1);
82		}
83		if (!new_val) {
84			sepol_log_err("Invalid conditional expression");
85			goto exit;
86		}
87		rc = stack_push(stack, new_val);
88		if (rc != 0) {
89			sepol_log_err("Out of memory");
90			goto exit;
91		}
92	}
93
94	new_val = stack_pop(stack);
95	if (!new_val || !stack_empty(stack)) {
96		sepol_log_err("Invalid conditional expression");
97		goto exit;
98	}
99
100	str = new_val;
101
102	stack_destroy(&stack);
103	return str;
104
105exit:
106	while ((new_val = stack_pop(stack)) != NULL) {
107		free(new_val);
108	}
109	stack_destroy(&stack);
110
111	return NULL;
112}
113
114static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr *expr, int *use_mls)
115{
116	struct constraint_expr *curr;
117	struct strs *stack = NULL;
118	char *new_val = NULL;
119	const char *op;
120	char *str = NULL;
121	int rc;
122
123	*use_mls = 0;
124
125	rc = stack_init(&stack);
126	if (rc != 0) {
127		goto exit;
128	}
129
130	for (curr = expr; curr; curr = curr->next) {
131		if (curr->expr_type == CEXPR_ATTR || curr->expr_type == CEXPR_NAMES) {
132			const char *attr1 = NULL;
133			const char *attr2 = NULL;
134
135			switch (curr->op) {
136			case CEXPR_EQ:      op = "==";     break;
137			case CEXPR_NEQ:     op = "!=";    break;
138			case CEXPR_DOM:     op = "dom";    break;
139			case CEXPR_DOMBY:   op = "domby";  break;
140			case CEXPR_INCOMP:  op = "incomp"; break;
141			default:
142				sepol_log_err("Unknown constraint operator: %i", curr->op);
143				goto exit;
144			}
145
146			switch (curr->attr) {
147			case CEXPR_USER:                 attr1 ="u1"; attr2 ="u2"; break;
148			case CEXPR_USER | CEXPR_TARGET:  attr1 ="u2"; attr2 ="";   break;
149			case CEXPR_USER | CEXPR_XTARGET: attr1 ="u3"; attr2 ="";   break;
150			case CEXPR_ROLE:                 attr1 ="r1"; attr2 ="r2"; break;
151			case CEXPR_ROLE | CEXPR_TARGET:  attr1 ="r2"; attr2 ="";   break;
152			case CEXPR_ROLE | CEXPR_XTARGET: attr1 ="r3"; attr2 ="";   break;
153			case CEXPR_TYPE:                 attr1 ="t1"; attr2 ="t2"; break;
154			case CEXPR_TYPE | CEXPR_TARGET:  attr1 ="t2"; attr2 ="";   break;
155			case CEXPR_TYPE | CEXPR_XTARGET: attr1 ="t3"; attr2 ="";   break;
156			case CEXPR_L1L2:                 attr1 ="l1"; attr2 ="l2"; break;
157			case CEXPR_L1H2:                 attr1 ="l1"; attr2 ="h2"; break;
158			case CEXPR_H1L2:                 attr1 ="h1"; attr2 ="l2"; break;
159			case CEXPR_H1H2:                 attr1 ="h1"; attr2 ="h2"; break;
160			case CEXPR_L1H1:                 attr1 ="l1"; attr2 ="h1"; break;
161			case CEXPR_L2H2:                 attr1 ="l2"; attr2 ="h2"; break;
162			default:
163				sepol_log_err("Unknown constraint attribute: %i", curr->attr);
164				goto exit;
165			}
166
167			if (curr->attr >= CEXPR_XTARGET) {
168				*use_mls = 1;
169			}
170
171			if (curr->expr_type == CEXPR_ATTR) {
172				new_val = create_str("%s %s %s", 3, attr1, op, attr2);
173			} else {
174				char *names = NULL;
175				if (curr->attr & CEXPR_TYPE) {
176					struct type_set *ts = curr->type_names;
177					names = ebitmap_to_str(&ts->types, pdb->p_type_val_to_name, 1);
178				} else if (curr->attr & CEXPR_USER) {
179					names = ebitmap_to_str(&curr->names, pdb->p_user_val_to_name, 1);
180				} else if (curr->attr & CEXPR_ROLE) {
181					names = ebitmap_to_str(&curr->names, pdb->p_role_val_to_name, 1);
182				}
183				if (!names) {
184					goto exit;
185				}
186				new_val = create_str("%s %s %s", 3, attr1, op, names);
187				free(names);
188			}
189		} else {
190			uint32_t num_params;
191			char *val1 = NULL;
192			char *val2 = NULL;
193
194			switch (curr->expr_type) {
195			case CEXPR_NOT: op = "not"; num_params = 1; break;
196			case CEXPR_AND: op = "and"; num_params = 2; break;
197			case CEXPR_OR:  op = "or";  num_params = 2; break;
198			default:
199				sepol_log_err("Unknown constraint expression type: %i", curr->expr_type);
200				goto exit;
201			}
202
203			if (num_params == 2) {
204				val2 = stack_pop(stack);
205				if (!val2) {
206					sepol_log_err("Invalid constraint expression");
207					goto exit;
208				}
209			}
210			val1 = stack_pop(stack);
211			if (!val1) {
212				sepol_log_err("Invalid constraint expression");
213				goto exit;
214			}
215
216			if (num_params == 2) {
217				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
218				free(val2);
219			} else {
220				new_val = create_str("%s (%s)", 2, op, val1);
221			}
222			free(val1);
223		}
224		if (!new_val) {
225			goto exit;
226		}
227		rc = stack_push(stack, new_val);
228		if (rc != 0) {
229			sepol_log_err("Out of memory");
230			goto exit;
231		}
232	}
233
234	new_val = stack_pop(stack);
235	if (!new_val || !stack_empty(stack)) {
236		sepol_log_err("Invalid constraint expression");
237		goto exit;
238	}
239
240	str = new_val;
241
242	stack_destroy(&stack);
243
244	return str;
245
246exit:
247	while ((new_val = stack_pop(stack)) != NULL) {
248		free(new_val);
249	}
250	stack_destroy(&stack);
251
252	return NULL;
253}
254
255static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
256					  class_datum_t *class,
257					  struct constraint_node *constraint_rules,
258					  struct strs *mls_list,
259					  struct strs *non_mls_list)
260{
261	struct constraint_node *curr;
262	struct strs *strs;
263	const char *format_str, *flavor;
264	char *perms, *expr;
265	int is_mls;
266	int rc = 0;
267
268	for (curr = constraint_rules; curr != NULL; curr = curr->next) {
269		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
270		if (!expr) {
271			rc = -1;
272			goto exit;
273		}
274
275		perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
276		if (strchr(perms, ' ')) {
277			format_str = "%s %s { %s } %s;";
278		} else {
279			format_str = "%s %s %s %s";
280		}
281		if (is_mls) {
282			flavor = "mlsconstrain";
283			strs = mls_list;
284		} else {
285			flavor = "constrain";
286			strs = non_mls_list;
287		}
288
289		rc = strs_create_and_add(strs, format_str, 4,
290					 flavor, classkey, perms+1, expr);
291		free(expr);
292		if (rc != 0) {
293			goto exit;
294		}
295	}
296
297	return 0;
298exit:
299	sepol_log_err("Error gathering constraint rules\n");
300	return rc;
301}
302
303static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classkey,
304					     struct constraint_node *validatetrans_rules,
305					     struct strs *mls_list,
306					     struct strs *non_mls_list)
307{
308	struct constraint_node *curr;
309	struct strs *strs;
310	const char *flavor;
311	char *expr;
312	int is_mls;
313	int rc = 0;
314
315	for (curr = validatetrans_rules; curr != NULL; curr = curr->next) {
316		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
317		if (!expr) {
318			rc = -1;
319			goto exit;
320		}
321
322		if (is_mls) {
323			flavor = "mlsvalidatetrans";
324			strs = mls_list;
325		} else {
326			flavor = "validatetrans";
327			strs = non_mls_list;
328		}
329
330		rc = strs_create_and_add(strs, "%s %s %s;", 3, flavor, classkey, expr);
331		free(expr);
332		if (rc != 0) {
333			goto exit;
334		}
335	}
336
337exit:
338	return rc;
339}
340
341static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
342{
343	class_datum_t *class;
344	char *name;
345	unsigned i;
346	int rc = 0;
347
348	for (i=0; i < pdb->p_classes.nprim; i++) {
349		class = pdb->class_val_to_struct[i];
350		if (class->constraints) {
351			name = pdb->p_class_val_to_name[i];
352			rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
353			if (rc != 0) {
354				goto exit;
355			}
356		}
357	}
358
359	strs_sort(mls_strs);
360	strs_sort(non_mls_strs);
361
362exit:
363	return rc;
364}
365
366static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
367{
368	class_datum_t *class;
369	char *name;
370	unsigned i;
371	int rc = 0;
372
373	for (i=0; i < pdb->p_classes.nprim; i++) {
374		class = pdb->class_val_to_struct[i];
375		if (class->validatetrans) {
376			name = pdb->p_class_val_to_name[i];
377			rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
378			if (rc != 0) {
379				goto exit;
380			}
381		}
382	}
383
384	strs_sort(mls_strs);
385	strs_sort(non_mls_strs);
386
387exit:
388	return rc;
389}
390
391static int write_handle_unknown_to_conf(FILE *out, struct policydb *pdb)
392{
393	const char *action;
394
395	switch (pdb->handle_unknown) {
396	case SEPOL_DENY_UNKNOWN:
397		action = "deny";
398		break;
399	case SEPOL_REJECT_UNKNOWN:
400		action = "reject";
401		break;
402	case SEPOL_ALLOW_UNKNOWN:
403		action = "allow";
404		break;
405	default:
406		sepol_log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
407		return -1;
408	}
409
410	sepol_printf(out, "# handle_unknown %s\n", action);
411
412	return 0;
413}
414
415static int write_class_decl_rules_to_conf(FILE *out, struct policydb *pdb)
416{
417	char *name;
418	unsigned i;
419
420	for (i=0; i < pdb->p_classes.nprim; i++) {
421		name = pdb->p_class_val_to_name[i];
422		sepol_printf(out, "class %s\n", name);
423	}
424
425	return 0;
426}
427
428static int write_sids_to_conf(FILE *out, const char *const *sid_to_str, struct ocontext *isids)
429{
430	struct ocontext *isid;
431	struct strs *strs;
432	char *sid;
433	unsigned i;
434	int rc;
435
436	rc = strs_init(&strs, SECINITSID_NUM+1);
437	if (rc != 0) {
438		goto exit;
439	}
440
441	for (isid = isids; isid != NULL; isid = isid->next) {
442		i = isid->sid[0];
443		rc = strs_add_at_index(strs, (char *)sid_to_str[i], i);
444		if (rc != 0) {
445			goto exit;
446		}
447	}
448
449	for (i=0; i<strs_num_items(strs); i++) {
450		sid = strs_read_at_index(strs, i);
451		if (!sid) {
452			continue;
453		}
454		sepol_printf(out, "sid %s\n", sid);
455	}
456
457exit:
458	strs_destroy(&strs);
459	if (rc != 0) {
460		sepol_log_err("Error writing sid rules to policy.conf\n");
461	}
462
463	return rc;
464}
465
466static int write_sid_decl_rules_to_conf(FILE *out, struct policydb *pdb)
467{
468	int rc = 0;
469
470	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
471		rc = write_sids_to_conf(out, selinux_sid_to_str, pdb->ocontexts[0]);
472	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
473		rc = write_sids_to_conf(out, xen_sid_to_str, pdb->ocontexts[0]);
474	} else {
475		sepol_log_err("Unknown target platform: %i", pdb->target_platform);
476		rc = -1;
477	}
478
479	return rc;
480}
481static char *class_or_common_perms_to_str(symtab_t *permtab)
482{
483	struct strs *strs;
484	char *perms = NULL;
485	int rc = 0;
486
487	rc = strs_init(&strs, permtab->nprim);
488	if (rc != 0) {
489		goto exit;
490	}
491
492	rc = hashtab_map(permtab->table, hashtab_ordered_to_strs, strs);
493	if (rc != 0) {
494		goto exit;
495	}
496
497	if (strs_num_items(strs) > 0) {
498		perms = strs_to_str(strs);
499	}
500
501exit:
502	strs_destroy(&strs);
503
504	return perms;
505}
506
507static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb)
508{
509	class_datum_t *class;
510	common_datum_t *common;
511	int *used;
512	char *name, *perms;
513	unsigned i;
514	int rc = 0;
515
516	/* common */
517	used = calloc(pdb->p_commons.nprim, sizeof(*used));
518	if (!used) {
519		sepol_log_err("Out of memory");
520		rc = -1;
521		goto exit;
522	}
523	for (i=0; i < pdb->p_classes.nprim; i++) {
524		class = pdb->class_val_to_struct[i];
525		name = class->comkey;
526		if (!name) continue;
527		common = hashtab_search(pdb->p_commons.table, name);
528		if (!common) {
529			rc = -1;
530			free(used);
531			goto exit;
532		}
533		/* Only write common rule once */
534		if (!used[common->s.value-1]) {
535			perms = class_or_common_perms_to_str(&common->permissions);
536			if (!perms) {
537				rc = -1;
538				free(used);
539				goto exit;
540			}
541			sepol_printf(out, "common %s { %s }\n", name, perms);
542			free(perms);
543			used[common->s.value-1] = 1;
544		}
545	}
546	free(used);
547
548	/* class */
549	for (i=0; i < pdb->p_classes.nprim; i++) {
550		class = pdb->class_val_to_struct[i];
551		name = pdb->p_class_val_to_name[i];
552		sepol_printf(out, "class %s", name);
553		if (class->comkey) {
554			sepol_printf(out, " inherits %s", class->comkey);
555		}
556		perms = class_or_common_perms_to_str(&class->permissions);
557		if (perms) {
558			sepol_printf(out, " { %s }", perms);
559			free(perms);
560		}
561		sepol_printf(out, "\n");
562	}
563
564exit:
565	if (rc != 0) {
566		sepol_log_err("Error writing class rules to policy.conf\n");
567	}
568
569	return rc;
570}
571
572static int write_default_user_to_conf(FILE *out, char *class_name, class_datum_t *class)
573{
574	const char *dft;
575
576	switch (class->default_user) {
577	case DEFAULT_SOURCE:
578		dft = "source";
579		break;
580	case DEFAULT_TARGET:
581		dft = "target";
582		break;
583	default:
584		sepol_log_err("Unknown default role value: %i", class->default_user);
585		return -1;
586	}
587	sepol_printf(out, "default_user { %s } %s;\n", class_name, dft);
588
589	return 0;
590}
591
592static int write_default_role_to_conf(FILE *out, char *class_name, class_datum_t *class)
593{
594	const char *dft;
595
596	switch (class->default_role) {
597	case DEFAULT_SOURCE:
598		dft = "source";
599		break;
600	case DEFAULT_TARGET:
601		dft = "target";
602		break;
603	default:
604		sepol_log_err("Unknown default role value: %i", class->default_role);
605		return -1;
606	}
607	sepol_printf(out, "default_role { %s } %s;\n", class_name, dft);
608
609	return 0;
610}
611
612static int write_default_type_to_conf(FILE *out, char *class_name, class_datum_t *class)
613{
614	const char *dft;
615
616	switch (class->default_type) {
617	case DEFAULT_SOURCE:
618		dft = "source";
619		break;
620	case DEFAULT_TARGET:
621		dft = "target";
622		break;
623	default:
624		sepol_log_err("Unknown default type value: %i", class->default_type);
625		return -1;
626	}
627	sepol_printf(out, "default_type { %s } %s;\n", class_name, dft);
628
629	return 0;
630}
631
632static int write_default_range_to_conf(FILE *out, char *class_name, class_datum_t *class)
633{
634	const char *dft;
635
636	switch (class->default_range) {
637	case DEFAULT_SOURCE_LOW:
638		dft = "source low";
639		break;
640	case DEFAULT_SOURCE_HIGH:
641		dft = "source high";
642		break;
643	case DEFAULT_SOURCE_LOW_HIGH:
644		dft = "source low-high";
645		break;
646	case DEFAULT_TARGET_LOW:
647		dft = "target low";
648		break;
649	case DEFAULT_TARGET_HIGH:
650		dft = "target high";
651		break;
652	case DEFAULT_TARGET_LOW_HIGH:
653		dft = "target low-high";
654		break;
655	default:
656		sepol_log_err("Unknown default type value: %i", class->default_range);
657		return -1;
658	}
659	sepol_printf(out, "default_range { %s } %s;\n", class_name, dft);
660
661	return 0;
662}
663
664static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
665{
666	class_datum_t *class;
667	unsigned i;
668	int rc = 0;
669
670	/* default_user */
671	for (i=0; i < pdb->p_classes.nprim; i++) {
672		class = pdb->class_val_to_struct[i];
673		if (class->default_user != 0) {
674			rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class);
675			if (rc != 0) {
676				goto exit;
677			}
678		}
679	}
680
681	/* default_role */
682	for (i=0; i < pdb->p_classes.nprim; i++) {
683		class = pdb->class_val_to_struct[i];
684		if (class->default_role != 0) {
685			rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class);
686			if (rc != 0) {
687				goto exit;
688			}
689		}
690	}
691
692	/* default_type */
693	for (i=0; i < pdb->p_classes.nprim; i++) {
694		class = pdb->class_val_to_struct[i];
695		if (class->default_type != 0) {
696			rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class);
697			if (rc != 0) {
698				goto exit;
699			}
700		}
701	}
702
703	if (!pdb->mls) {
704		return 0;
705	}
706
707	/* default_range */
708	for (i=0; i < pdb->p_classes.nprim; i++) {
709		class = pdb->class_val_to_struct[i];
710		if (class->default_range != 0) {
711			rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class);
712			if (rc != 0) {
713				goto exit;
714			}
715		}
716	}
717
718exit:
719	if (rc != 0) {
720		sepol_log_err("Error writing default rules to policy.conf\n");
721	}
722
723	return rc;
724}
725
726static int map_sensitivity_aliases_to_strs(char *key, void *data, void *args)
727{
728	level_datum_t *sens = data;
729	struct strs *strs = args;
730	int rc = 0;
731
732	if (sens->isalias) {
733		rc = strs_add(strs, key);
734	}
735
736	return rc;
737}
738
739static int write_sensitivity_rules_to_conf(FILE *out, struct policydb *pdb)
740{
741	level_datum_t *level;
742	struct strs *strs;
743	char **sens_alias_map = NULL;
744	char *name, *prev, *alias;
745	unsigned i, j, num;
746	int rc = 0;
747
748	rc = strs_init(&strs, pdb->p_levels.nprim);
749	if (rc != 0) {
750		goto exit;
751	}
752
753	rc = hashtab_map(pdb->p_levels.table, map_sensitivity_aliases_to_strs, strs);
754	if (rc != 0) {
755		goto exit;
756	}
757
758	num = strs_num_items(strs);
759
760	if (num > 0) {
761		sens_alias_map = calloc(sizeof(*sens_alias_map), pdb->p_levels.nprim);
762		if (!sens_alias_map) {
763			rc = -1;
764			goto exit;
765		}
766
767		/* map aliases to sensitivities */
768		for (i=0; i < num; i++) {
769			name = strs_read_at_index(strs, i);
770			level = hashtab_search(pdb->p_levels.table, name);
771			if (!level) {
772				rc = -1;
773				goto exit;
774			}
775			j = level->level->sens - 1;
776			if (!sens_alias_map[j]) {
777				sens_alias_map[j] = strdup(name);
778			} else {
779				alias = sens_alias_map[j];
780				sens_alias_map[j] = create_str("%s %s", 2, alias, name);
781				free(alias);
782				if (!sens_alias_map[j]) {
783					rc = -1;
784					goto exit;
785				}
786			}
787		}
788	}
789
790	/* sensitivities */
791	for (i=0; i < pdb->p_levels.nprim; i++) {
792		name = pdb->p_sens_val_to_name[i];
793		if (!name) continue;
794		level = hashtab_search(pdb->p_levels.table, name);
795		if (!level) {
796			rc = -1;
797			goto exit;
798		}
799		if (level->isalias) continue;
800
801		if (sens_alias_map && sens_alias_map[i]) {
802			alias = sens_alias_map[i];
803			if (strchr(alias, ' ')) {
804				sepol_printf(out, "sensitivity %s alias { %s };\n", name, alias);
805			} else {
806				sepol_printf(out, "sensitivity %s alias %s;\n", name, alias);
807			}
808		} else {
809			sepol_printf(out, "sensitivity %s;\n", name);
810		}
811	}
812
813	/* dominance */
814	sepol_printf(out, "dominance { ");
815	prev = NULL;
816	for (i=0; i < pdb->p_levels.nprim; i++) {
817		name = pdb->p_sens_val_to_name[i];
818		if (!name) continue;
819		level = hashtab_search(pdb->p_levels.table, name);
820		if (!level) {
821			rc = -1;
822			goto exit;
823		}
824		if (level->isalias) continue;
825
826		if (prev) {
827			sepol_printf(out, "%s ", prev);
828		}
829		prev = name;
830	}
831	if (prev) {
832		sepol_printf(out, "%s", prev);
833	}
834	sepol_printf(out, " }\n");
835
836exit:
837	if (sens_alias_map) {
838		for (i=0; i < pdb->p_levels.nprim; i++) {
839			free(sens_alias_map[i]);
840		}
841		free(sens_alias_map);
842	}
843
844	strs_destroy(&strs);
845
846	if (rc != 0) {
847		sepol_log_err("Error writing sensitivity rules to CIL\n");
848	}
849
850	return rc;
851}
852
853static int map_category_aliases_to_strs(char *key, void *data, void *args)
854{
855	cat_datum_t *cat = data;
856	struct strs *strs = args;
857	int rc = 0;
858
859	if (cat->isalias) {
860		rc = strs_add(strs, key);
861	}
862
863	return rc;
864}
865
866static int write_category_rules_to_conf(FILE *out, struct policydb *pdb)
867{
868	cat_datum_t *cat;
869	struct strs *strs;
870	char **cat_alias_map = NULL;
871	char *name, *alias;
872	unsigned i, j, num;
873	int rc = 0;
874
875	rc = strs_init(&strs, pdb->p_levels.nprim);
876	if (rc != 0) {
877		goto exit;
878	}
879
880	rc = hashtab_map(pdb->p_cats.table, map_category_aliases_to_strs, strs);
881	if (rc != 0) {
882		goto exit;
883	}
884
885	num = strs_num_items(strs);
886
887	if (num > 0) {
888		cat_alias_map = calloc(sizeof(*cat_alias_map), pdb->p_cats.nprim);
889		if (!cat_alias_map) {
890			rc = -1;
891			goto exit;
892		}
893
894		/* map aliases to categories */
895		for (i=0; i < num; i++) {
896			name = strs_read_at_index(strs, i);
897			cat = hashtab_search(pdb->p_cats.table, name);
898			if (!cat) {
899				rc = -1;
900				goto exit;
901			}
902			j = cat->s.value - 1;
903			if (!cat_alias_map[j]) {
904				cat_alias_map[j] = strdup(name);
905			} else {
906				alias = cat_alias_map[j];
907				cat_alias_map[j] = create_str("%s %s", 2, alias, name);
908				free(alias);
909				if (!cat_alias_map[j]) {
910					rc = -1;
911					goto exit;
912				}
913			}
914		}
915	}
916
917	/* categories */
918	for (i=0; i < pdb->p_cats.nprim; i++) {
919		name = pdb->p_cat_val_to_name[i];
920		if (!name) continue;
921		cat = hashtab_search(pdb->p_cats.table, name);
922		if (!cat) {
923			rc = -1;
924			goto exit;
925		}
926		if (cat->isalias) continue;
927
928		if (cat_alias_map && cat_alias_map[i]) {
929			alias = cat_alias_map[i];
930			if (strchr(alias, ' ')) {
931				sepol_printf(out, "category %s alias { %s };\n", name, alias);
932			} else {
933				sepol_printf(out, "category %s alias %s;\n", name, alias);
934			}
935		} else {
936			sepol_printf(out, "category %s;\n", name);
937		}
938	}
939
940exit:
941	if (cat_alias_map) {
942		for (i=0; i < pdb->p_cats.nprim; i++) {
943			free(cat_alias_map[i]);
944		}
945		free(cat_alias_map);
946	}
947
948	strs_destroy(&strs);
949
950	if (rc != 0) {
951		sepol_log_err("Error writing category rules to policy.conf\n");
952	}
953
954	return rc;
955}
956
957static size_t cats_ebitmap_len(struct ebitmap *cats, char **val_to_name)
958{
959	struct ebitmap_node *node;
960	uint32_t i, start, range;
961	size_t len = 0;
962
963	range = 0;
964	ebitmap_for_each_bit(cats, node, i) {
965		if (!ebitmap_get_bit(cats, i))
966			continue;
967
968		if (range == 0)
969			start = i;
970
971		range++;
972
973		if (ebitmap_get_bit(cats, i+1))
974			continue;
975
976		len += strlen(val_to_name[start]) + 1;
977		if (range > 1) {
978			len += strlen(val_to_name[i]) + 1;
979		}
980
981		range = 0;
982	}
983
984	return len;
985}
986
987static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
988{
989	struct ebitmap_node *node;
990	uint32_t i, start, range, first;
991	char *catsbuf, *p;
992	const char *fmt;
993	char sep;
994	int len, remaining;
995
996	remaining = (int)cats_ebitmap_len(cats, val_to_name);
997	catsbuf = malloc(remaining);
998	if (!catsbuf) {
999		goto exit;
1000	}
1001
1002	p = catsbuf;
1003
1004	first = 1;
1005	range = 0;
1006	ebitmap_for_each_bit(cats, node, i) {
1007		if (!ebitmap_get_bit(cats, i))
1008			continue;
1009
1010		if (range == 0)
1011			start = i;
1012
1013		range++;
1014
1015		if (ebitmap_get_bit(cats, i+1))
1016			continue;
1017
1018		if (range > 1) {
1019			sep = (range == 2) ? ',' : '.';
1020			fmt = first ? "%s%c%s" : ",%s%c%s";
1021			len = snprintf(p, remaining, fmt,
1022				       val_to_name[start], sep, val_to_name[i]);
1023		} else {
1024			fmt = first ? "%s" : ",%s";
1025			len = snprintf(p, remaining, fmt, val_to_name[start]);
1026
1027		}
1028		if (len < 0 || len >= remaining) {
1029			goto exit;
1030		}
1031		p += len;
1032		remaining -= len;
1033		first = 0;
1034		range = 0;
1035	}
1036
1037	*p = '\0';
1038
1039	return catsbuf;
1040
1041exit:
1042	free(catsbuf);
1043	return NULL;
1044}
1045
1046static int write_level_rules_to_conf(FILE *out, struct policydb *pdb)
1047{
1048	level_datum_t *level;
1049	char *name, *cats;
1050	unsigned i;
1051	int rc = 0;
1052
1053	for (i=0; i < pdb->p_levels.nprim; i++) {
1054		name = pdb->p_sens_val_to_name[i];
1055		if (!name) continue;
1056		level = hashtab_search(pdb->p_levels.table, name);
1057		if (!level) {
1058			rc = -1;
1059			goto exit;
1060		}
1061		if (level->isalias) continue;
1062
1063		if (ebitmap_cardinality(&level->level->cat) > 0) {
1064			cats = cats_ebitmap_to_str(&level->level->cat, pdb->p_cat_val_to_name);
1065			sepol_printf(out, "level %s:%s;\n", name, cats);
1066			free(cats);
1067		} else {
1068			sepol_printf(out, "level %s;\n", name);
1069		}
1070	}
1071
1072exit:
1073	if (rc != 0) {
1074		sepol_log_err("Error writing level rules to policy.conf\n");
1075	}
1076
1077	return rc;
1078}
1079
1080static int write_mls_rules_to_conf(FILE *out, struct policydb *pdb)
1081{
1082	int rc = 0;
1083
1084	if (!pdb->mls) {
1085		return 0;
1086	}
1087
1088	rc = write_sensitivity_rules_to_conf(out, pdb);
1089	if (rc != 0) {
1090		goto exit;
1091	}
1092
1093	rc = write_category_rules_to_conf(out, pdb);
1094	if (rc != 0) {
1095		goto exit;
1096	}
1097
1098	rc = write_level_rules_to_conf(out, pdb);
1099	if (rc != 0) {
1100		goto exit;
1101	}
1102
1103exit:
1104	if (rc != 0) {
1105		sepol_log_err("Error writing mls rules to policy.conf\n");
1106	}
1107
1108	return rc;
1109}
1110
1111static int write_polcap_rules_to_conf(FILE *out, struct policydb *pdb)
1112{
1113	struct strs *strs;
1114	struct ebitmap_node *node;
1115	const char *name;
1116	uint32_t i;
1117	int rc = 0;
1118
1119	rc = strs_init(&strs, 32);
1120	if (rc != 0) {
1121		goto exit;
1122	}
1123
1124	ebitmap_for_each_bit(&pdb->policycaps, node, i) {
1125		if (!ebitmap_get_bit(&pdb->policycaps, i)) continue;
1126
1127		name = sepol_polcap_getname(i);
1128		if (name == NULL) {
1129			sepol_log_err("Unknown policy capability id: %i", i);
1130			rc = -1;
1131			goto exit;
1132		}
1133
1134		rc = strs_create_and_add(strs, "policycap %s;", 1, name);
1135		if (rc != 0) {
1136			goto exit;
1137		}
1138	}
1139
1140	strs_sort(strs);
1141	strs_write_each(strs, out);
1142
1143exit:
1144	strs_free_all(strs);
1145	strs_destroy(&strs);
1146
1147	if (rc != 0) {
1148		sepol_log_err("Error writing polcap rules to policy.conf\n");
1149	}
1150
1151	return rc;
1152}
1153
1154static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
1155{
1156	type_datum_t *type;
1157	char *name;
1158	struct strs *strs;
1159	unsigned i, num;
1160	int rc = 0;
1161
1162	rc = strs_init(&strs, pdb->p_types.nprim);
1163	if (rc != 0) {
1164		goto exit;
1165	}
1166
1167	for (i=0; i < pdb->p_types.nprim; i++) {
1168		type = pdb->type_val_to_struct[i];
1169		if (type->flavor == TYPE_ATTRIB) {
1170			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1171			if (rc != 0) {
1172				goto exit;
1173			}
1174		}
1175	}
1176
1177	strs_sort(strs);
1178
1179	num = strs_num_items(strs);
1180	for (i = 0; i < num; i++) {
1181		name = strs_read_at_index(strs, i);
1182		if (!name) {
1183			rc = -1;
1184			goto exit;
1185		}
1186		sepol_printf(out, "attribute %s;\n", name);
1187	}
1188
1189exit:
1190	strs_destroy(&strs);
1191
1192	if (rc != 0) {
1193		sepol_log_err("Error writing typeattribute rules to policy.conf\n");
1194	}
1195
1196	return rc;
1197}
1198
1199static int write_role_attributes_to_conf(FILE *out, struct policydb *pdb)
1200{
1201	role_datum_t *role;
1202	char *name;
1203	struct strs *strs;
1204	unsigned i, num;
1205	int rc = 0;
1206
1207	rc = strs_init(&strs, pdb->p_roles.nprim);
1208	if (rc != 0) {
1209		goto exit;
1210	}
1211
1212	for (i=0; i < pdb->p_roles.nprim; i++) {
1213		role = pdb->role_val_to_struct[i];
1214		if (role && role->flavor == ROLE_ATTRIB) {
1215			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
1216			if (rc != 0) {
1217				goto exit;
1218			}
1219		}
1220	}
1221
1222	strs_sort(strs);
1223
1224	num = strs_num_items(strs);
1225	for (i=0; i<num; i++) {
1226		name = strs_read_at_index(strs, i);
1227		if (!name) {
1228			rc = -1;
1229			goto exit;
1230		}
1231		sepol_printf(out, "attribute_role %s;\n", name);
1232	}
1233
1234exit:
1235	strs_destroy(&strs);
1236
1237	if (rc != 0) {
1238		sepol_log_err("Error writing roleattribute rules to policy.conf\n");
1239	}
1240
1241	return rc;
1242}
1243
1244static int map_boolean_to_strs(char *key, void *data, void *args)
1245{
1246	struct strs *strs = (struct strs *)args;
1247	struct cond_bool_datum *boolean = data;
1248	const char *value;
1249
1250	value = boolean->state ? "true" : "false";
1251
1252	return strs_create_and_add(strs, "bool %s %s;", 2, key, value);
1253}
1254
1255static int write_boolean_decl_rules_to_conf(FILE *out, struct policydb *pdb)
1256{
1257	struct strs *strs;
1258	int rc = 0;
1259
1260	rc = strs_init(&strs, 32);
1261	if (rc != 0) {
1262		goto exit;
1263	}
1264
1265	rc = hashtab_map(pdb->p_bools.table, map_boolean_to_strs, strs);
1266	if (rc != 0) {
1267		goto exit;
1268	}
1269
1270	strs_sort(strs);
1271	strs_write_each(strs, out);
1272
1273exit:
1274	strs_free_all(strs);
1275	strs_destroy(&strs);
1276
1277	if (rc != 0) {
1278		sepol_log_err("Error writing boolean declarations to policy.conf\n");
1279	}
1280
1281	return rc;
1282}
1283
1284static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
1285{
1286	type_datum_t *type;
1287	struct strs *strs;
1288	char *name;
1289	unsigned i, num;
1290	int rc = 0;
1291
1292	rc = strs_init(&strs, pdb->p_types.nprim);
1293	if (rc != 0) {
1294		goto exit;
1295	}
1296
1297	for (i=0; i < pdb->p_types.nprim; i++) {
1298		type = pdb->type_val_to_struct[i];
1299		if (type->flavor == TYPE_TYPE && type->primary) {
1300			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1301			if (rc != 0) {
1302				goto exit;
1303			}
1304		}
1305	}
1306
1307	strs_sort(strs);
1308
1309	num = strs_num_items(strs);
1310	for (i=0; i<num; i++) {
1311		name = strs_read_at_index(strs, i);
1312		if (!name) {
1313			rc = -1;
1314			goto exit;
1315		}
1316		sepol_printf(out, "type %s;\n", name);
1317	}
1318
1319exit:
1320	strs_destroy(&strs);
1321
1322	if (rc != 0) {
1323		sepol_log_err("Error writing type declarations to policy.con\n");
1324	}
1325
1326	return rc;
1327}
1328
1329static int write_type_alias_rules_to_conf(FILE *out, struct policydb *pdb)
1330{
1331	type_datum_t *alias;
1332	struct strs *strs;
1333	char *name;
1334	char *type;
1335	unsigned i, num;
1336	int rc = 0;
1337
1338	rc = strs_init(&strs, pdb->p_types.nprim);
1339	if (rc != 0) {
1340		goto exit;
1341	}
1342
1343	for (i=0; i < pdb->p_types.nprim; i++) {
1344		alias = pdb->type_val_to_struct[i];
1345		if (!alias->primary) {
1346			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1347			if (rc != 0) {
1348				goto exit;
1349			}
1350		}
1351	}
1352
1353	strs_sort(strs);
1354
1355	num = strs_num_items(strs);
1356
1357	for (i=0; i<num; i++) {
1358		name = strs_read_at_index(strs, i);
1359		if (!name) {
1360			rc = -1;
1361			goto exit;
1362		}
1363		alias = hashtab_search(pdb->p_types.table, name);
1364		if (!alias) {
1365			rc = -1;
1366			goto exit;
1367		}
1368		type = pdb->p_type_val_to_name[alias->s.value - 1];
1369		sepol_printf(out, "typealias %s %s;\n", type, name);
1370	}
1371
1372exit:
1373	strs_destroy(&strs);
1374
1375	if (rc != 0) {
1376		sepol_log_err("Error writing type alias rules to policy.conf\n");
1377	}
1378
1379	return rc;
1380}
1381
1382static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
1383{
1384	type_datum_t *type;
1385	struct strs *strs;
1386	char *parent;
1387	char *child;
1388	unsigned i, num;
1389	int rc = 0;
1390
1391	rc = strs_init(&strs, pdb->p_types.nprim);
1392	if (rc != 0) {
1393		goto exit;
1394	}
1395
1396	for (i=0; i < pdb->p_types.nprim; i++) {
1397		type = pdb->type_val_to_struct[i];
1398		if (type->flavor == TYPE_TYPE) {
1399			if (type->bounds > 0) {
1400				rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1401				if (rc != 0) {
1402					goto exit;
1403				}
1404			}
1405		}
1406	}
1407
1408	strs_sort(strs);
1409
1410	num = strs_num_items(strs);
1411	for (i=0; i<num; i++) {
1412		child = strs_read_at_index(strs, i);
1413		if (!child) {
1414			rc = -1;
1415			goto exit;
1416		}
1417		type = hashtab_search(pdb->p_types.table, child);
1418		if (!type) {
1419			rc = -1;
1420			goto exit;
1421		}
1422		parent = pdb->p_type_val_to_name[type->bounds - 1];
1423		sepol_printf(out, "typebounds %s %s;\n", parent, child);
1424	}
1425
1426exit:
1427	strs_destroy(&strs);
1428
1429	if (rc != 0) {
1430		sepol_log_err("Error writing type bounds rules to policy.conf\n");
1431	}
1432
1433	return rc;
1434}
1435
1436static char *attr_strs_to_str(struct strs *strs)
1437{
1438	char *str = NULL;
1439	size_t len = 0;
1440	char *p;
1441	unsigned i;
1442	int rc;
1443
1444	if (strs->num == 0) {
1445		goto exit;
1446	}
1447
1448	/* 2*strs->num - 1 because ", " follows all but last attr (followed by '\0') */
1449	len = strs_len_items(strs) + 2*strs->num - 1;
1450	str = malloc(len);
1451	if (!str) {
1452		sepol_log_err("Out of memory");
1453		goto exit;
1454	}
1455
1456	p = str;
1457	for (i=0; i<strs->num; i++) {
1458		if (!strs->list[i]) continue;
1459		len = strlen(strs->list[i]);
1460		rc = snprintf(p, len+1, "%s", strs->list[i]);
1461		if (rc < 0 || rc > (int)len) {
1462			free(str);
1463			str = NULL;
1464			goto exit;
1465		}
1466		p += len;
1467		if (i < strs->num - 1) {
1468			*p++ = ',';
1469			*p++ = ' ';
1470		}
1471	}
1472
1473	*p = '\0';
1474
1475exit:
1476	return str;
1477}
1478
1479static char *attrmap_to_str(struct ebitmap *map, char **val_to_name)
1480{
1481	struct strs *strs;
1482	char *str = NULL;
1483	int rc;
1484
1485	rc = strs_init(&strs, 32);
1486	if (rc != 0) {
1487		goto exit;
1488	}
1489
1490	rc = ebitmap_to_strs(map, strs, val_to_name);
1491	if (rc != 0) {
1492		goto exit;
1493	}
1494
1495	strs_sort(strs);
1496
1497	str = attr_strs_to_str(strs);
1498
1499exit:
1500	strs_destroy(&strs);
1501
1502	return str;
1503}
1504
1505static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
1506{
1507	type_datum_t *type;
1508	struct strs *strs;
1509	ebitmap_t attrmap;
1510	char *name, *attrs;
1511	unsigned i;
1512	int rc;
1513
1514	rc = strs_init(&strs, pdb->p_types.nprim);
1515	if (rc != 0) {
1516		goto exit;
1517	}
1518
1519	for (i=0; i < pdb->p_types.nprim; i++) {
1520		type = pdb->type_val_to_struct[i];
1521		if (type->flavor != TYPE_TYPE || !type->primary) continue;
1522		if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
1523
1524		rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
1525		if (rc != 0) {
1526			goto exit;
1527		}
1528		rc = ebitmap_set_bit(&attrmap, i, 0);
1529		if (rc != 0) {
1530			ebitmap_destroy(&attrmap);
1531			goto exit;
1532		}
1533		name = pdb->p_type_val_to_name[i];
1534		attrs = attrmap_to_str(&attrmap, pdb->p_type_val_to_name);
1535		ebitmap_destroy(&attrmap);
1536		if (!attrs) {
1537			rc = -1;
1538			goto exit;
1539		}
1540
1541		rc = strs_create_and_add(strs, "typeattribute %s %s;",
1542					 2, name, attrs);
1543		free(attrs);
1544		if (rc != 0) {
1545			goto exit;
1546		}
1547	}
1548
1549	strs_sort(strs);
1550	strs_write_each(strs, out);
1551
1552exit:
1553	strs_free_all(strs);
1554	strs_destroy(&strs);
1555
1556	if (rc != 0) {
1557		sepol_log_err("Error writing typeattributeset rules to policy.conf\n");
1558	}
1559
1560	return rc;
1561}
1562
1563static int write_type_permissive_rules_to_conf(FILE *out, struct policydb *pdb)
1564{
1565	type_datum_t *type;
1566	struct strs *strs;
1567	char *name;
1568	unsigned i, num;
1569	int rc = 0;
1570
1571	rc = strs_init(&strs, pdb->p_types.nprim);
1572	if (rc != 0) {
1573		goto exit;
1574	}
1575
1576	for (i=0; i < pdb->p_types.nprim; i++) {
1577		type = pdb->type_val_to_struct[i];
1578		if (type->flavor == TYPE_TYPE && (type->flags & TYPE_FLAGS_PERMISSIVE)) {
1579			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1580			if (rc != 0) {
1581				goto exit;
1582			}
1583		}
1584	}
1585
1586	strs_sort(strs);
1587
1588	num = strs_num_items(strs);
1589	for (i=0; i<num; i++) {
1590		name = strs_read_at_index(strs, i);
1591		if (!name) {
1592			rc = -1;
1593			goto exit;
1594		}
1595		sepol_printf(out, "permissive %s;\n", name);
1596	}
1597
1598exit:
1599	strs_destroy(&strs);
1600
1601	if (rc != 0) {
1602		sepol_log_err("Error writing typepermissive rules to policy.conf\n");
1603	}
1604
1605	return rc;
1606}
1607
1608static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum)
1609{
1610	uint32_t data = datum->data;
1611	type_datum_t *type;
1612	const char *flavor, *src, *tgt, *class, *perms, *new;
1613	char *rule = NULL;
1614
1615	switch (0xFFF & key->specified) {
1616	case AVTAB_ALLOWED:
1617		flavor = "allow";
1618		break;
1619	case AVTAB_AUDITALLOW:
1620		flavor = "auditallow";
1621		break;
1622	case AVTAB_AUDITDENY:
1623		flavor = "dontaudit";
1624		data = ~data;
1625		break;
1626	case AVTAB_XPERMS_ALLOWED:
1627		flavor = "allowxperm";
1628		break;
1629	case AVTAB_XPERMS_AUDITALLOW:
1630		flavor = "auditallowxperm";
1631		break;
1632	case AVTAB_XPERMS_DONTAUDIT:
1633		flavor = "dontauditxperm";
1634		break;
1635	case AVTAB_TRANSITION:
1636		flavor = "type_transition";
1637		break;
1638	case AVTAB_MEMBER:
1639		flavor = "type_member";
1640		break;
1641	case AVTAB_CHANGE:
1642		flavor = "type_change";
1643		break;
1644	default:
1645		sepol_log_err("Unknown avtab type: %i", key->specified);
1646		goto exit;
1647	}
1648
1649	src = pdb->p_type_val_to_name[key->source_type - 1];
1650	tgt = pdb->p_type_val_to_name[key->target_type - 1];
1651	if (key->source_type == key->target_type && !(key->specified & AVTAB_TYPE)) {
1652		type = pdb->type_val_to_struct[key->source_type - 1];
1653		if (type->flavor != TYPE_ATTRIB) {
1654			tgt = "self";
1655		}
1656	}
1657	class = pdb->p_class_val_to_name[key->target_class - 1];
1658
1659	if (key->specified & AVTAB_AV) {
1660		perms = sepol_av_to_string(pdb, key->target_class, data);
1661		if (perms == NULL) {
1662			sepol_log_err("Failed to generate permission string");
1663			goto exit;
1664		}
1665		rule = create_str("%s %s %s:%s { %s };", 5,
1666				  flavor, src, tgt, class, perms+1);
1667	} else if (key->specified & AVTAB_XPERMS) {
1668		perms = sepol_extended_perms_to_string(datum->xperms);
1669		if (perms == NULL) {
1670			sepol_log_err("Failed to generate extended permission string");
1671			goto exit;
1672		}
1673
1674		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms);
1675	} else {
1676		new = pdb->p_type_val_to_name[data - 1];
1677
1678		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, new);
1679	}
1680
1681	if (!rule) {
1682		goto exit;
1683	}
1684
1685	return rule;
1686
1687exit:
1688	return NULL;
1689}
1690
1691struct map_avtab_args {
1692	struct policydb *pdb;
1693	uint32_t flavor;
1694	struct strs *strs;
1695};
1696
1697static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void *args)
1698{
1699	struct map_avtab_args *map_args = args;
1700	uint32_t flavor = map_args->flavor;
1701	struct policydb *pdb = map_args->pdb;
1702	struct strs *strs = map_args->strs;
1703	char *rule;
1704	int rc = 0;
1705
1706	if (key->specified & flavor) {
1707		rule = avtab_node_to_str(pdb, key, datum);
1708		if (!rule) {
1709			rc = -1;
1710			goto exit;
1711		}
1712		rc = strs_add(strs, rule);
1713		if (rc != 0) {
1714			free(rule);
1715			goto exit;
1716		}
1717	}
1718
1719exit:
1720	return rc;
1721}
1722
1723static int write_avtab_flavor_to_conf(FILE *out, struct policydb *pdb, uint32_t flavor, int indent)
1724{
1725	struct map_avtab_args args;
1726	struct strs *strs;
1727	int rc = 0;
1728
1729	rc = strs_init(&strs, 1000);
1730	if (rc != 0) {
1731		goto exit;
1732	}
1733
1734	args.pdb = pdb;
1735	args.flavor = flavor;
1736	args.strs = strs;
1737
1738	rc = avtab_map(&pdb->te_avtab, map_avtab_write_helper, &args);
1739	if (rc != 0) {
1740		goto exit;
1741	}
1742
1743	strs_sort(strs);
1744	strs_write_each_indented(strs, out, indent);
1745
1746exit:
1747	strs_free_all(strs);
1748	strs_destroy(&strs);
1749
1750	return rc;
1751}
1752
1753static int write_avtab_to_conf(FILE *out, struct policydb *pdb, int indent)
1754{
1755	unsigned i;
1756	int rc = 0;
1757
1758	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
1759		rc = write_avtab_flavor_to_conf(out, pdb, avtab_flavors[i], indent);
1760		if (rc != 0) {
1761			goto exit;
1762		}
1763	}
1764
1765exit:
1766	if (rc != 0) {
1767		sepol_log_err("Error writing avtab rules to policy.conf\n");
1768	}
1769
1770	return rc;
1771}
1772
1773struct map_filename_trans_args {
1774	struct policydb *pdb;
1775	struct strs *strs;
1776};
1777
1778static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
1779{
1780	filename_trans_t *ft = (filename_trans_t *)key;
1781	filename_trans_datum_t *datum = data;
1782	struct map_filename_trans_args *map_args = arg;
1783	struct policydb *pdb = map_args->pdb;
1784	struct strs *strs = map_args->strs;
1785	char *src, *tgt, *class, *filename, *new;
1786
1787	src = pdb->p_type_val_to_name[ft->stype - 1];
1788	tgt = pdb->p_type_val_to_name[ft->ttype - 1];
1789	class = pdb->p_class_val_to_name[ft->tclass - 1];
1790	filename = ft->name;
1791	new =  pdb->p_type_val_to_name[datum->otype - 1];
1792
1793	return strs_create_and_add(strs, "type_transition %s %s:%s %s \"%s\";", 5,
1794				   src, tgt, class, new, filename);
1795}
1796
1797static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
1798{
1799	struct map_filename_trans_args args;
1800	struct strs *strs;
1801	int rc = 0;
1802
1803	rc = strs_init(&strs, 100);
1804	if (rc != 0) {
1805		goto exit;
1806	}
1807
1808	args.pdb = pdb;
1809	args.strs = strs;
1810
1811	rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
1812	if (rc != 0) {
1813		goto exit;
1814	}
1815
1816	strs_sort(strs);
1817	strs_write_each(strs, out);
1818
1819exit:
1820	strs_free_all(strs);
1821	strs_destroy(&strs);
1822
1823	if (rc != 0) {
1824		sepol_log_err("Error writing filename typetransition rules to policy.conf\n");
1825	}
1826
1827	return rc;
1828}
1829
1830static char *level_to_str(struct policydb *pdb, struct mls_level *level)
1831{
1832	ebitmap_t *cats = &level->cat;
1833	char *level_str = NULL;
1834	char *sens_str = pdb->p_sens_val_to_name[level->sens - 1];
1835	char *cats_str;
1836
1837	if (ebitmap_cardinality(cats) > 0) {
1838		cats_str = cats_ebitmap_to_str(cats, pdb->p_cat_val_to_name);
1839		level_str = create_str("%s:%s", 2, sens_str, cats_str);
1840		free(cats_str);
1841	} else {
1842		level_str = create_str("%s", 1, sens_str);
1843	}
1844
1845	return level_str;
1846}
1847
1848static char *range_to_str(struct policydb *pdb, mls_range_t *range)
1849{
1850	char *low = NULL;
1851	char *high = NULL;
1852	char *range_str = NULL;
1853
1854	low = level_to_str(pdb, &range->level[0]);
1855	if (!low) {
1856		goto exit;
1857	}
1858
1859	high = level_to_str(pdb, &range->level[1]);
1860	if (!high) {
1861		goto exit;
1862	}
1863
1864	range_str = create_str("%s - %s", 2, low, high);
1865
1866exit:
1867	free(low);
1868	free(high);
1869
1870	return range_str;
1871}
1872
1873struct map_range_trans_args {
1874	struct policydb *pdb;
1875	struct strs *strs;
1876};
1877
1878static int map_range_trans_to_str(hashtab_key_t key, void *data, void *arg)
1879{
1880	range_trans_t *rt = (range_trans_t *)key;
1881	mls_range_t *mls_range = data;
1882	struct map_range_trans_args *map_args = arg;
1883	struct policydb *pdb = map_args->pdb;
1884	struct strs *strs = map_args->strs;
1885	char *src, *tgt, *class, *range;
1886	int rc;
1887
1888	src = pdb->p_type_val_to_name[rt->source_type - 1];
1889	tgt = pdb->p_type_val_to_name[rt->target_type - 1];
1890	class = pdb->p_class_val_to_name[rt->target_class - 1];
1891	range = range_to_str(pdb, mls_range);
1892	if (!range) {
1893		rc = -1;
1894		goto exit;
1895	}
1896
1897	rc = strs_create_and_add(strs, "range_transition %s %s:%s %s;", 4,
1898				 src, tgt, class, range);
1899	free(range);
1900	if (rc != 0) {
1901		goto exit;
1902	}
1903
1904exit:
1905	return rc;
1906}
1907
1908static int write_range_trans_rules_to_conf(FILE *out, struct policydb *pdb)
1909{
1910	struct map_range_trans_args args;
1911	struct strs *strs;
1912	int rc = 0;
1913
1914	rc = strs_init(&strs, 100);
1915	if (rc != 0) {
1916		goto exit;
1917	}
1918
1919	args.pdb = pdb;
1920	args.strs = strs;
1921
1922	rc = hashtab_map(pdb->range_tr, map_range_trans_to_str, &args);
1923	if (rc != 0) {
1924		goto exit;
1925	}
1926
1927	strs_sort(strs);
1928	strs_write_each(strs, out);
1929
1930exit:
1931	strs_free_all(strs);
1932	strs_destroy(&strs);
1933
1934	if (rc != 0) {
1935		sepol_log_err("Error writing range transition rules to policy.conf\n");
1936	}
1937
1938	return rc;
1939}
1940
1941static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_list_t *cond_list, int indent)
1942{
1943	cond_av_list_t *cond_av;
1944	avtab_ptr_t node;
1945	uint32_t flavor;
1946	avtab_key_t *key;
1947	avtab_datum_t *datum;
1948	struct strs *strs;
1949	char *rule;
1950	unsigned i;
1951	int rc;
1952
1953	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
1954		flavor = avtab_flavors[i];
1955		rc = strs_init(&strs, 64);
1956		if (rc != 0) {
1957			goto exit;
1958		}
1959
1960		for (cond_av = cond_list; cond_av != NULL; cond_av = cond_av->next) {
1961			node = cond_av->node;
1962			key = &node->key;
1963			datum = &node->datum;
1964			if (key->specified & flavor) {
1965				rule = avtab_node_to_str(pdb, key, datum);
1966				if (!rule) {
1967					rc = -1;
1968					goto exit;
1969				}
1970				rc = strs_add(strs, rule);
1971				if (rc != 0) {
1972					free(rule);
1973					goto exit;
1974				}
1975			}
1976		}
1977
1978		strs_sort(strs);
1979		strs_write_each_indented(strs, out, indent);
1980		strs_free_all(strs);
1981		strs_destroy(&strs);
1982	}
1983
1984	return 0;
1985
1986exit:
1987	return rc;
1988}
1989
1990struct cond_data {
1991	char *expr;
1992	struct cond_node *cond;
1993};
1994
1995static int cond_node_cmp(const void *a, const void *b)
1996{
1997	const struct cond_data *aa = a;
1998	const struct cond_data *bb = b;
1999	return strcmp(aa->expr, bb->expr);
2000}
2001
2002static int write_cond_nodes_to_conf(FILE *out, struct policydb *pdb)
2003{
2004	struct cond_data *cond_data;
2005	char *expr;
2006	struct cond_node *cond;
2007	unsigned i, num;
2008	int rc = 0;
2009
2010	num = 0;
2011	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
2012		num++;
2013	}
2014
2015	if (num == 0) {
2016		return 0;
2017	}
2018
2019	cond_data = calloc(sizeof(struct cond_data), num);
2020	if (!cond_data) {
2021		rc = -1;
2022		goto exit;
2023	}
2024
2025	i = 0;
2026	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
2027		cond_data[i].cond = cond;
2028		expr = cond_expr_to_str(pdb, cond->expr);
2029		if (!expr) {
2030			num = i;
2031			goto exit;
2032		}
2033		cond_data[i].expr = expr;
2034		i++;
2035	}
2036
2037	qsort(cond_data, num, sizeof(*cond_data), cond_node_cmp);
2038
2039	for (i=0; i<num; i++) {
2040		expr = cond_data[i].expr;
2041		cond = cond_data[i].cond;
2042
2043		sepol_printf(out, "if (%s) {\n", expr);
2044
2045		if (cond->true_list != NULL) {
2046			rc = write_cond_av_list_to_conf(out, pdb, cond->true_list, 1);
2047			if (rc != 0) {
2048				goto exit;
2049			}
2050		}
2051
2052		if (cond->false_list != NULL) {
2053			sepol_printf(out, "} else {\n");
2054			rc = write_cond_av_list_to_conf(out, pdb, cond->false_list, 1);
2055			if (rc != 0) {
2056				goto exit;
2057			}
2058		}
2059		sepol_printf(out, "}\n");
2060	}
2061
2062exit:
2063	if (cond_data) {
2064		for (i=0; i<num; i++) {
2065			free(cond_data[i].expr);
2066		}
2067		free(cond_data);
2068	}
2069
2070	if (rc != 0) {
2071		sepol_log_err("Error writing conditional rules to policy.conf\n");
2072	}
2073
2074	return rc;
2075}
2076
2077static int write_role_decl_rules_to_conf(FILE *out, struct policydb *pdb)
2078{
2079	struct role_datum *role;
2080	struct strs *strs;
2081	char *name, *types, *p1, *p2;
2082	unsigned i, num;
2083	int rc = 0;
2084
2085	rc = strs_init(&strs, pdb->p_roles.nprim);
2086	if (rc != 0) {
2087		goto exit;
2088	}
2089
2090	/* Start at 1 to skip object_r */
2091	for (i=1; i < pdb->p_roles.nprim; i++) {
2092		role = pdb->role_val_to_struct[i];
2093		if (role && role->flavor == ROLE_ROLE) {
2094			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
2095			if (rc != 0) {
2096				goto exit;
2097			}
2098		}
2099	}
2100
2101	strs_sort(strs);
2102
2103	num = strs_num_items(strs);
2104
2105	for (i=0; i<num; i++) {
2106		name = strs_read_at_index(strs, i);
2107		if (!name) {
2108			continue;
2109		}
2110		sepol_printf(out, "role %s;\n", name);
2111	}
2112
2113	for (i=0; i<num; i++) {
2114		name = strs_read_at_index(strs, i);
2115		if (!name) continue;
2116		role = hashtab_search(pdb->p_roles.table, name);
2117		if (!role) {
2118			rc = -1;
2119			goto exit;
2120		}
2121		if (ebitmap_cardinality(&role->types.types) == 0) continue;
2122		types = ebitmap_to_str(&role->types.types, pdb->p_type_val_to_name, 1);
2123		if (!types) {
2124			rc = -1;
2125			goto exit;
2126		}
2127		if (strlen(types) > 900) {
2128			p1 = types;
2129			while (p1) {
2130				p2 = p1;
2131				while (p2 - p1 < 600) {
2132					p2 = strchr(p2, ' ');
2133					if (!p2)
2134						break;
2135					p2++;
2136				}
2137				if (p2) {
2138					*(p2-1) = '\0';
2139				}
2140				sepol_printf(out, "role %s types { %s };\n", name, p1);
2141				p1 = p2;
2142			}
2143		} else {
2144			sepol_printf(out, "role %s types { %s };\n", name, types);
2145		}
2146		free(types);
2147	}
2148
2149exit:
2150	strs_destroy(&strs);
2151
2152	if (rc != 0) {
2153		sepol_log_err("Error writing role declarations to policy.conf\n");
2154	}
2155
2156	return rc;
2157}
2158
2159static int write_role_transition_rules_to_conf(FILE *out, struct policydb *pdb)
2160{
2161	role_trans_t *curr = pdb->role_tr;
2162	struct strs *strs;
2163	char *role, *type, *class, *new;
2164	int rc = 0;
2165
2166	rc = strs_init(&strs, 32);
2167	if (rc != 0) {
2168		goto exit;
2169	}
2170
2171	while (curr) {
2172		role = pdb->p_role_val_to_name[curr->role - 1];
2173		type = pdb->p_type_val_to_name[curr->type - 1];
2174		class = pdb->p_class_val_to_name[curr->tclass - 1];
2175		new = pdb->p_role_val_to_name[curr->new_role - 1];
2176
2177		rc = strs_create_and_add(strs, "role_transition %s %s:%s %s;", 4,
2178					 role, type, class, new);
2179		if (rc != 0) {
2180			goto exit;
2181		}
2182
2183		curr = curr->next;
2184	}
2185
2186	strs_sort(strs);
2187	strs_write_each(strs, out);
2188
2189exit:
2190	strs_free_all(strs);
2191	strs_destroy(&strs);
2192
2193	if (rc != 0) {
2194		sepol_log_err("Error writing role transition rules to policy.conf\n");
2195	}
2196
2197	return rc;
2198}
2199
2200static int write_role_allow_rules_to_conf(FILE *out, struct policydb *pdb)
2201{
2202	role_allow_t *curr = pdb->role_allow;
2203	struct strs *strs;
2204	char *role, *new;
2205	int rc = 0;
2206
2207	rc = strs_init(&strs, 32);
2208	if (rc != 0) {
2209		goto exit;
2210	}
2211
2212	while (curr) {
2213		role = pdb->p_role_val_to_name[curr->role - 1];
2214		new =  pdb->p_role_val_to_name[curr->new_role - 1];
2215
2216		rc = strs_create_and_add(strs, "allow %s %s;", 2, role, new);
2217		if (rc != 0) {
2218			goto exit;
2219		}
2220
2221		curr = curr->next;
2222	}
2223
2224	strs_sort(strs);
2225	strs_write_each(strs, out);
2226
2227exit:
2228	strs_free_all(strs);
2229	strs_destroy(&strs);
2230
2231	if (rc != 0) {
2232		sepol_log_err("Error writing role allow rules to policy.conf\n");
2233	}
2234
2235	return rc;
2236}
2237
2238static int write_user_decl_rules_to_conf(FILE *out, struct policydb *pdb)
2239{
2240	struct user_datum *user;
2241	struct strs *strs;
2242	char *name, *roles, *level, *range;
2243	unsigned i, num;
2244	int rc = 0;
2245
2246	rc = strs_init(&strs, pdb->p_users.nprim);
2247	if (rc != 0) {
2248		goto exit;
2249	}
2250
2251	for (i=0; i < pdb->p_users.nprim; i++) {
2252		rc = strs_add(strs, pdb->p_user_val_to_name[i]);
2253		if (rc != 0) {
2254			goto exit;
2255		}
2256	}
2257
2258	strs_sort(strs);
2259
2260	num = strs_num_items(strs);
2261
2262	for (i=0; i<num; i++) {
2263		name = strs_read_at_index(strs, i);
2264		if (!name) {
2265			continue;
2266		}
2267		user = hashtab_search(pdb->p_users.table, name);
2268		if (!user) {
2269			rc = -1;
2270			goto exit;
2271		}
2272		sepol_printf(out, "user %s", name);
2273
2274		if (ebitmap_cardinality(&user->roles.roles) > 0) {
2275			roles = ebitmap_to_str(&user->roles.roles,
2276					       pdb->p_role_val_to_name, 1);
2277			if (!roles) {
2278				rc = -1;
2279				goto exit;
2280			}
2281			if (strchr(roles, ' ')) {
2282				sepol_printf(out, " roles { %s }", roles);
2283			} else {
2284				sepol_printf(out, " roles %s", roles);
2285			}
2286			free(roles);
2287		}
2288
2289		if (pdb->mls) {
2290			level = level_to_str(pdb, &user->exp_dfltlevel);
2291			if (!level) {
2292				rc = -1;
2293				goto exit;
2294			}
2295			sepol_printf(out, " level %s", level);
2296			free(level);
2297
2298			range = range_to_str(pdb, &user->exp_range);
2299			if (!range) {
2300				rc = -1;
2301				goto exit;
2302			}
2303			sepol_printf(out, " range %s", range);
2304			free(range);
2305		}
2306		sepol_printf(out, ";\n");
2307	}
2308
2309	strs_destroy(&strs);
2310
2311exit:
2312	if (rc != 0) {
2313		sepol_log_err("Error writing user declarations to policy.conf\n");
2314	}
2315
2316	return rc;
2317}
2318
2319static char *context_to_str(struct policydb *pdb, struct context_struct *con)
2320{
2321	char *user, *role, *type, *range;
2322	char *ctx = NULL;
2323
2324	user = pdb->p_user_val_to_name[con->user - 1];
2325	role = pdb->p_role_val_to_name[con->role - 1];
2326	type = pdb->p_type_val_to_name[con->type - 1];
2327
2328	if (pdb->mls) {
2329		range = range_to_str(pdb, &con->range);
2330		ctx = create_str("%s:%s:%s:%s", 4, user, role, type, range);
2331		free(range);
2332	} else {
2333		ctx = create_str("%s:%s:%s", 3, user, role, type);
2334	}
2335
2336	return ctx;
2337}
2338
2339static int write_sid_context_rules_to_conf(FILE *out, struct policydb *pdb, const char *const *sid_to_str)
2340{
2341	struct ocontext *isid;
2342	struct strs *strs;
2343	const char *sid;
2344	char *ctx, *rule;
2345	unsigned i;
2346	int rc;
2347
2348	rc = strs_init(&strs, 32);
2349	if (rc != 0) {
2350		goto exit;
2351	}
2352
2353	for (isid = pdb->ocontexts[0]; isid != NULL; isid = isid->next) {
2354		i = isid->sid[0];
2355		sid = sid_to_str[i];
2356		ctx = context_to_str(pdb, &isid->context[0]);
2357		if (!ctx) {
2358			rc = -1;
2359			goto exit;
2360		}
2361
2362		rule = create_str("sid %s %s", 2, sid, ctx);
2363		free(ctx);
2364		if (!rule) {
2365			rc = -1;
2366			goto exit;
2367		}
2368
2369		rc = strs_add_at_index(strs, rule, i);
2370		if (rc != 0) {
2371			free(rule);
2372			goto exit;
2373		}
2374	}
2375
2376	strs_write_each(strs, out);
2377
2378exit:
2379	strs_free_all(strs);
2380	strs_destroy(&strs);
2381
2382	if (rc != 0) {
2383		sepol_log_err("Error writing sidcontext rules to policy.conf\n");
2384	}
2385
2386	return rc;
2387}
2388
2389static int write_selinux_isid_rules_to_conf(FILE *out, struct policydb *pdb)
2390{
2391	return write_sid_context_rules_to_conf(out, pdb, selinux_sid_to_str);
2392}
2393
2394static int write_selinux_fsuse_rules_to_conf(FILE *out, struct policydb *pdb)
2395{
2396	struct ocontext *fsuse;
2397	const char *behavior;
2398	char *name, *ctx;
2399	int rc = 0;
2400
2401	for (fsuse = pdb->ocontexts[5]; fsuse != NULL; fsuse = fsuse->next) {
2402		switch (fsuse->v.behavior) {
2403		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
2404		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
2405		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
2406		default:
2407			sepol_log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
2408			rc = -1;
2409			goto exit;
2410		}
2411
2412		name = fsuse->u.name;
2413		ctx = context_to_str(pdb, &fsuse->context[0]);
2414		if (!ctx) {
2415			rc = -1;
2416			goto exit;
2417		}
2418
2419		sepol_printf(out, "fs_use_%s %s %s;\n", behavior, name, ctx);
2420
2421		free(ctx);
2422	}
2423
2424exit:
2425	if (rc != 0) {
2426		sepol_log_err("Error writing fsuse rules to policy.conf\n");
2427	}
2428
2429	return rc;
2430}
2431
2432static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb)
2433{
2434	struct genfs *genfs;
2435	struct ocontext *ocon;
2436	struct strs *strs;
2437	char *fstype, *name, *ctx;
2438	int rc;
2439
2440	rc = strs_init(&strs, 32);
2441	if (rc != 0) {
2442		goto exit;
2443	}
2444
2445	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
2446		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
2447			fstype = genfs->fstype;
2448			name = ocon->u.name;
2449
2450			ctx = context_to_str(pdb, &ocon->context[0]);
2451			if (!ctx) {
2452				rc = -1;
2453				goto exit;
2454			}
2455
2456			rc = strs_create_and_add(strs, "genfscon %s %s %s", 3,
2457						 fstype, name, ctx);
2458			free(ctx);
2459			if (rc != 0) {
2460				goto exit;
2461			}
2462		}
2463	}
2464
2465	strs_sort(strs);
2466	strs_write_each(strs, out);
2467
2468exit:
2469	strs_free_all(strs);
2470	strs_destroy(&strs);
2471
2472	if (rc != 0) {
2473		sepol_log_err("Error writing genfscon rules to policy.conf\n");
2474	}
2475
2476	return rc;
2477}
2478
2479static int write_selinux_port_rules_to_conf(FILE *out, struct policydb *pdb)
2480{
2481	struct ocontext *portcon;
2482	const char *protocol;
2483	uint16_t low;
2484	uint16_t high;
2485	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
2486	char *ctx;
2487	int rc = 0;
2488
2489	for (portcon = pdb->ocontexts[2]; portcon != NULL; portcon = portcon->next) {
2490		switch (portcon->u.port.protocol) {
2491		case IPPROTO_TCP: protocol = "tcp"; break;
2492		case IPPROTO_UDP: protocol = "udp"; break;
2493		case IPPROTO_DCCP: protocol = "dccp"; break;
2494		default:
2495			sepol_log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
2496			rc = -1;
2497			goto exit;
2498		}
2499
2500		low = portcon->u.port.low_port;
2501		high = portcon->u.port.high_port;
2502		if (low == high) {
2503			rc = snprintf(low_high_str, 44, "%u", low);
2504		} else {
2505			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
2506		}
2507		if (rc < 0 || rc >= 44) {
2508			rc = -1;
2509			goto exit;
2510		}
2511
2512		ctx = context_to_str(pdb, &portcon->context[0]);
2513		if (!ctx) {
2514			rc = -1;
2515			goto exit;
2516		}
2517
2518		sepol_printf(out, "portcon %s %s %s\n", protocol, low_high_str, ctx);
2519
2520		free(ctx);
2521	}
2522
2523	rc = 0;
2524
2525exit:
2526	if (rc != 0) {
2527		sepol_log_err("Error writing portcon rules to policy.conf\n");
2528	}
2529
2530	return rc;
2531}
2532
2533static int write_selinux_netif_rules_to_conf(FILE *out, struct policydb *pdb)
2534{
2535	struct ocontext *netif;
2536	char *name, *ctx1, *ctx2;
2537	int rc = 0;
2538
2539	for (netif = pdb->ocontexts[3]; netif != NULL; netif = netif->next) {
2540		name = netif->u.name;
2541		ctx1 = context_to_str(pdb, &netif->context[0]);
2542		if (!ctx1) {
2543			rc = -1;
2544			goto exit;
2545		}
2546		ctx2 = context_to_str(pdb, &netif->context[1]);
2547		if (!ctx2) {
2548			free(ctx1);
2549			rc = -1;
2550			goto exit;
2551		}
2552
2553		sepol_printf(out, "netifcon %s %s %s\n", name, ctx1, ctx2);
2554
2555		free(ctx1);
2556		free(ctx2);
2557	}
2558
2559exit:
2560	if (rc != 0) {
2561		sepol_log_err("Error writing netifcon rules to policy.conf\n");
2562	}
2563
2564	return rc;
2565}
2566
2567static int write_selinux_node_rules_to_conf(FILE *out, struct policydb *pdb)
2568{
2569	struct ocontext *node;
2570	char addr[INET_ADDRSTRLEN];
2571	char mask[INET_ADDRSTRLEN];
2572	char *ctx;
2573	int rc = 0;
2574
2575	for (node = pdb->ocontexts[4]; node != NULL; node = node->next) {
2576		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
2577			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
2578			rc = -1;
2579			goto exit;
2580		}
2581
2582		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
2583			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
2584			rc = -1;
2585			goto exit;
2586		}
2587
2588		ctx = context_to_str(pdb, &node->context[0]);
2589		if (!ctx) {
2590			rc = -1;
2591			goto exit;
2592		}
2593
2594		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
2595
2596		free(ctx);
2597	}
2598
2599exit:
2600	if (rc != 0) {
2601		sepol_log_err("Error writing nodecon rules to policy.conf\n");
2602	}
2603
2604	return rc;
2605}
2606
2607
2608static int write_selinux_node6_rules_to_conf(FILE *out, struct policydb *pdb)
2609{
2610	struct ocontext *node6;
2611	char addr[INET6_ADDRSTRLEN];
2612	char mask[INET6_ADDRSTRLEN];
2613	char *ctx;
2614	int rc = 0;
2615
2616	for (node6 = pdb->ocontexts[6]; node6 != NULL; node6 = node6->next) {
2617		if (inet_ntop(AF_INET6, &node6->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
2618			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
2619			rc = -1;
2620			goto exit;
2621		}
2622
2623		if (inet_ntop(AF_INET6, &node6->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
2624			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
2625			rc = -1;
2626			goto exit;
2627		}
2628
2629		ctx = context_to_str(pdb, &node6->context[0]);
2630		if (!ctx) {
2631			rc = -1;
2632			goto exit;
2633		}
2634
2635		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
2636
2637		free(ctx);
2638	}
2639
2640exit:
2641	if (rc != 0) {
2642		sepol_log_err("Error writing nodecon rules to policy.conf\n");
2643	}
2644
2645	return rc;
2646}
2647
2648static int write_xen_isid_rules_to_conf(FILE *out, struct policydb *pdb)
2649{
2650	return write_sid_context_rules_to_conf(out, pdb, xen_sid_to_str);
2651}
2652
2653
2654static int write_xen_pirq_rules_to_conf(FILE *out, struct policydb *pdb)
2655{
2656	struct ocontext *pirq;
2657	char pirq_str[21]; /* 2^64-1 <= 20 digits */
2658	char *ctx;
2659	int rc = 0;
2660
2661	for (pirq = pdb->ocontexts[1]; pirq != NULL; pirq = pirq->next) {
2662		rc = snprintf(pirq_str, 21, "%i", pirq->u.pirq);
2663		if (rc < 0 || rc >= 21) {
2664			fprintf(stderr,"error1\n");
2665			rc = -1;
2666			goto exit;
2667		}
2668
2669		ctx = context_to_str(pdb, &pirq->context[0]);
2670		if (!ctx) {
2671			rc = -1;
2672			fprintf(stderr,"error2\n");
2673			goto exit;
2674		}
2675
2676		sepol_printf(out, "pirqcon %s %s\n", pirq_str, ctx);
2677
2678		free(ctx);
2679	}
2680
2681	rc = 0;
2682
2683exit:
2684	if (rc != 0) {
2685		sepol_log_err("Error writing pirqcon rules to policy.conf\n");
2686	}
2687
2688	return rc;
2689}
2690
2691static int write_xen_ioport_rules_to_conf(FILE *out, struct policydb *pdb)
2692{
2693	struct ocontext *ioport;
2694	uint32_t low;
2695	uint32_t high;
2696	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
2697	char *ctx;
2698	int rc = 0;
2699
2700	for (ioport = pdb->ocontexts[2]; ioport != NULL; ioport = ioport->next) {
2701		low = ioport->u.ioport.low_ioport;
2702		high = ioport->u.ioport.high_ioport;
2703		if (low == high) {
2704			rc = snprintf(low_high_str, 40, "0x%x", low);
2705		} else {
2706			rc = snprintf(low_high_str, 40, "0x%x-0x%x", low, high);
2707		}
2708		if (rc < 0 || rc >= 40) {
2709			rc = -1;
2710			goto exit;
2711		}
2712
2713		ctx = context_to_str(pdb, &ioport->context[0]);
2714		if (!ctx) {
2715			rc = -1;
2716			goto exit;
2717		}
2718
2719		sepol_printf(out, "ioportcon %s %s\n", low_high_str, ctx);
2720
2721		free(ctx);
2722	}
2723
2724	rc = 0;
2725
2726exit:
2727	if (rc != 0) {
2728		sepol_log_err("Error writing ioportcon rules to policy.conf\n");
2729	}
2730
2731	return rc;
2732}
2733
2734static int write_xen_iomem_rules_to_conf(FILE *out, struct policydb *pdb)
2735{
2736	struct ocontext *iomem;
2737	uint64_t low;
2738	uint64_t high;
2739	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
2740	char *ctx;
2741	int rc = 0;
2742
2743	for (iomem = pdb->ocontexts[3]; iomem != NULL; iomem = iomem->next) {
2744		low = iomem->u.iomem.low_iomem;
2745		high = iomem->u.iomem.high_iomem;
2746		if (low == high) {
2747			rc = snprintf(low_high_str, 40, "0x%"PRIx64, low);
2748		} else {
2749			rc = snprintf(low_high_str, 40, "0x%"PRIx64"-0x%"PRIx64, low, high);
2750		}
2751		if (rc < 0 || rc >= 40) {
2752			rc = -1;
2753			goto exit;
2754		}
2755
2756		ctx = context_to_str(pdb, &iomem->context[0]);
2757		if (!ctx) {
2758			rc = -1;
2759			goto exit;
2760		}
2761
2762		sepol_printf(out, "iomemcon %s %s\n", low_high_str, ctx);
2763
2764		free(ctx);
2765	}
2766
2767	rc = 0;
2768
2769exit:
2770	if (rc != 0) {
2771		sepol_log_err("Error writing iomemcon rules to policy.conf\n");
2772	}
2773
2774	return rc;
2775}
2776
2777static int write_xen_pcidevice_rules_to_conf(FILE *out, struct policydb *pdb)
2778{
2779	struct ocontext *pcid;
2780	char device_str[20]; /* 2^64-1 <= 16 digits (hex) so < 19 chars */
2781	char *ctx;
2782	int rc = 0;
2783
2784	for (pcid = pdb->ocontexts[4]; pcid != NULL; pcid = pcid->next) {
2785		rc = snprintf(device_str, 20, "0x%lx", (unsigned long)pcid->u.device);
2786		if (rc < 0 || rc >= 20) {
2787			rc = -1;
2788			goto exit;
2789		}
2790
2791		ctx = context_to_str(pdb, &pcid->context[0]);
2792		if (!ctx) {
2793			rc = -1;
2794			goto exit;
2795		}
2796
2797		sepol_printf(out, "pcidevicecon %s %s\n", device_str, ctx);
2798
2799		free(ctx);
2800	}
2801
2802	rc = 0;
2803
2804exit:
2805	if (rc != 0) {
2806		sepol_log_err("Error writing pcidevicecon rules to policy.conf\n");
2807	}
2808
2809	return rc;
2810}
2811
2812static int write_xen_devicetree_rules_to_conf(FILE *out, struct policydb *pdb)
2813{
2814	struct ocontext *dtree;
2815	char *name, *ctx;
2816	int rc = 0;
2817
2818	for (dtree = pdb->ocontexts[5]; dtree != NULL; dtree = dtree->next) {
2819		name = dtree->u.name;
2820		ctx = context_to_str(pdb, &dtree->context[0]);
2821		if (!ctx) {
2822			rc = -1;
2823			goto exit;
2824		}
2825
2826		sepol_printf(out, "devicetreecon %s %s\n", name, ctx);
2827
2828		free(ctx);
2829	}
2830
2831exit:
2832	if (rc != 0) {
2833		sepol_log_err("Error writing devicetreecon rules to policy.conf\n");
2834	}
2835
2836	return rc;
2837}
2838
2839int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
2840{
2841	struct strs *mls_constraints = NULL;
2842	struct strs *non_mls_constraints = NULL;
2843	struct strs *mls_validatetrans = NULL;
2844	struct strs *non_mls_validatetrans = NULL;
2845	int rc = 0;
2846
2847	rc = strs_init(&mls_constraints, 32);
2848	if (rc != 0) {
2849		goto exit;
2850	}
2851
2852	rc = strs_init(&non_mls_constraints, 32);
2853	if (rc != 0) {
2854		goto exit;
2855	}
2856
2857	rc = strs_init(&mls_validatetrans, 32);
2858	if (rc != 0) {
2859		goto exit;
2860	}
2861
2862	rc = strs_init(&non_mls_validatetrans, 32);
2863	if (rc != 0) {
2864		goto exit;
2865	}
2866
2867	if (pdb == NULL) {
2868		sepol_log_err("No policy");
2869		rc = -1;
2870		goto exit;
2871	}
2872
2873	if (pdb->policy_type != SEPOL_POLICY_KERN) {
2874		sepol_log_err("Policy is not a kernel policy");
2875		rc = -1;
2876		goto exit;
2877	}
2878
2879	rc = constraint_rules_to_strs(pdb, mls_constraints, non_mls_constraints);
2880	if (rc != 0) {
2881		goto exit;
2882	}
2883
2884	rc = validatetrans_rules_to_strs(pdb, mls_validatetrans, non_mls_validatetrans);
2885	if (rc != 0) {
2886		goto exit;
2887	}
2888
2889	rc = write_handle_unknown_to_conf(out, pdb);
2890	if (rc != 0) {
2891		goto exit;
2892	}
2893
2894	rc = write_class_decl_rules_to_conf(out, pdb);
2895	if (rc != 0) {
2896		goto exit;
2897	}
2898
2899	rc = write_sid_decl_rules_to_conf(out, pdb);
2900	if (rc != 0) {
2901		goto exit;
2902	}
2903
2904	rc = write_class_and_common_rules_to_conf(out, pdb);
2905	if (rc != 0) {
2906		goto exit;
2907	}
2908
2909	rc = write_default_rules_to_conf(out, pdb);
2910	if (rc != 0) {
2911		goto exit;
2912	}
2913
2914	rc = write_mls_rules_to_conf(out, pdb);
2915	if (rc != 0) {
2916		goto exit;
2917	}
2918
2919	strs_write_each(mls_constraints, out);
2920	strs_write_each(mls_validatetrans, out);
2921
2922	rc = write_polcap_rules_to_conf(out, pdb);
2923	if (rc != 0) {
2924		goto exit;
2925	}
2926
2927	rc = write_type_attributes_to_conf(out, pdb);
2928	if (rc != 0) {
2929		goto exit;
2930	}
2931
2932	rc = write_role_attributes_to_conf(out, pdb);
2933	if (rc != 0) {
2934		goto exit;
2935	}
2936
2937	rc = write_boolean_decl_rules_to_conf(out, pdb);
2938	if (rc != 0) {
2939		goto exit;
2940	}
2941
2942	rc = write_type_decl_rules_to_conf(out, pdb);
2943	if (rc != 0) {
2944		goto exit;
2945	}
2946
2947	rc = write_type_alias_rules_to_conf(out, pdb);
2948	if (rc != 0) {
2949		goto exit;
2950	}
2951
2952	rc = write_type_bounds_rules_to_conf(out, pdb);
2953	if (rc != 0) {
2954		goto exit;
2955	}
2956
2957	rc = write_type_attribute_sets_to_conf(out, pdb);
2958	if (rc != 0) {
2959		goto exit;
2960	}
2961
2962	rc = write_type_permissive_rules_to_conf(out, pdb);
2963	if (rc != 0) {
2964		goto exit;
2965	}
2966
2967	rc = write_avtab_to_conf(out, pdb, 0);
2968	if (rc != 0) {
2969		goto exit;
2970	}
2971	write_filename_trans_rules_to_conf(out, pdb);
2972
2973	if (pdb->mls) {
2974		rc = write_range_trans_rules_to_conf(out, pdb);
2975		if (rc != 0) {
2976			goto exit;
2977		}
2978	}
2979
2980	rc = write_cond_nodes_to_conf(out, pdb);
2981	if (rc != 0) {
2982		goto exit;
2983	}
2984
2985	rc = write_role_decl_rules_to_conf(out, pdb);
2986	if (rc != 0) {
2987		goto exit;
2988	}
2989
2990	rc = write_role_transition_rules_to_conf(out, pdb);
2991	if (rc != 0) {
2992		goto exit;
2993	}
2994
2995	rc = write_role_allow_rules_to_conf(out, pdb);
2996	if (rc != 0) {
2997		goto exit;
2998	}
2999
3000	rc = write_user_decl_rules_to_conf(out, pdb);
3001	if (rc != 0) {
3002		goto exit;
3003	}
3004
3005	strs_write_each(non_mls_constraints, out);
3006	strs_write_each(non_mls_validatetrans, out);
3007
3008	rc = sort_ocontexts(pdb);
3009	if (rc != 0) {
3010		goto exit;
3011	}
3012
3013	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
3014		rc = write_selinux_isid_rules_to_conf(out, pdb);
3015		if (rc != 0) {
3016			goto exit;
3017		}
3018
3019		rc = write_selinux_fsuse_rules_to_conf(out, pdb);
3020		if (rc != 0) {
3021			goto exit;
3022		}
3023
3024		rc = write_genfscon_rules_to_conf(out, pdb);
3025		if (rc != 0) {
3026			goto exit;
3027		}
3028
3029		rc = write_selinux_port_rules_to_conf(out, pdb);
3030		if (rc != 0) {
3031			goto exit;
3032		}
3033
3034		rc = write_selinux_netif_rules_to_conf(out, pdb);
3035		if (rc != 0) {
3036			goto exit;
3037		}
3038
3039		rc = write_selinux_node_rules_to_conf(out, pdb);
3040		if (rc != 0) {
3041			goto exit;
3042		}
3043
3044		rc = write_selinux_node6_rules_to_conf(out, pdb);
3045		if (rc != 0) {
3046			goto exit;
3047		}
3048	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
3049		rc = write_xen_isid_rules_to_conf(out, pdb);
3050		if (rc != 0) {
3051			goto exit;
3052		}
3053
3054		rc = write_genfscon_rules_to_conf(out, pdb);
3055		if (rc != 0) {
3056			goto exit;
3057		}
3058
3059		rc = write_xen_pirq_rules_to_conf(out, pdb);
3060		if (rc != 0) {
3061			goto exit;
3062		}
3063
3064		rc = write_xen_iomem_rules_to_conf(out, pdb);
3065		if (rc != 0) {
3066			goto exit;
3067		}
3068
3069		rc = write_xen_ioport_rules_to_conf(out, pdb);
3070		if (rc != 0) {
3071			goto exit;
3072		}
3073
3074		rc = write_xen_pcidevice_rules_to_conf(out, pdb);
3075		if (rc != 0) {
3076			goto exit;
3077		}
3078
3079		rc = write_xen_devicetree_rules_to_conf(out, pdb);
3080		if (rc != 0) {
3081			goto exit;
3082		}
3083	}
3084
3085exit:
3086	strs_free_all(mls_constraints);
3087	strs_destroy(&mls_constraints);
3088	strs_free_all(non_mls_constraints);
3089	strs_destroy(&non_mls_constraints);
3090	strs_free_all(mls_validatetrans);
3091	strs_destroy(&mls_validatetrans);
3092	strs_free_all(non_mls_validatetrans);
3093	strs_destroy(&non_mls_validatetrans);
3094
3095	return rc;
3096}
3097