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