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