[PATCH 1/3 v4] libsepol, policycoreutils: Move functions to convert a module package to CIL

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Move code to convert a policy module to CIL from the policy package to
CIL conversion tool, pp, in policycoreutils to libsepol. The only changes
to the code are the additions of the prefix "sepol_" to the functions
sepol_module_package_to_cil() and sepol_ppfile_to_module_package(). This
code is being changed from GPL to LGPL with permission from Tresys.

Convert pp to use the renamed functions in libsepol.

Signed-off-by: James Carter <jwcart2@xxxxxxxxxxxxx>
---
 libsepol/Android.mk                    |    1 +
 libsepol/include/sepol/module_to_cil.h |    6 +
 libsepol/src/libsepol.map.in           |    2 +
 libsepol/src/module_to_cil.c           | 3873 ++++++++++++++++++++++++++++++++
 policycoreutils/hll/pp/Makefile        |    2 +-
 policycoreutils/hll/pp/pp.c            | 3830 +------------------------------
 6 files changed, 3886 insertions(+), 3828 deletions(-)
 create mode 100644 libsepol/include/sepol/module_to_cil.h
 create mode 100644 libsepol/src/module_to_cil.c

diff --git a/libsepol/Android.mk b/libsepol/Android.mk
index 3e4700b..6246061 100644
--- a/libsepol/Android.mk
+++ b/libsepol/Android.mk
@@ -23,6 +23,7 @@ common_src_files := \
 	src/link.c \
 	src/mls.c \
 	src/module.c \
+	src/module_to_cil.c \
 	src/node_record.c \
 	src/nodes.c \
 	src/polcaps.c \
diff --git a/libsepol/include/sepol/module_to_cil.h b/libsepol/include/sepol/module_to_cil.h
new file mode 100644
index 0000000..1d0225c
--- /dev/null
+++ b/libsepol/include/sepol/module_to_cil.h
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+#include <sepol/module.h>
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg);
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg);
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
index 0ae0f1a..4e0c4bc 100644
--- a/libsepol/src/libsepol.map.in
+++ b/libsepol/src/libsepol.map.in
@@ -45,5 +45,7 @@ LIBSEPOL_1.1 {
 	cil_set_target_platform;
 	cil_set_policy_version;
 	cil_set_mls;
+	sepol_ppfile_to_module_package;
+	sepol_module_package_to_cil;
   local: *;
 } LIBSEPOL_1.0;
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
new file mode 100644
index 0000000..8326826
--- /dev/null
+++ b/libsepol/src/module_to_cil.c
@@ -0,0 +1,3873 @@
+/* Authors: Steve Lawrence <slawrence@xxxxxxxxxx>
+ *
+ * Functions to convert policy module to CIL
+ *
+ * Copyright (C) 2015 Tresys Technology, LLC
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <sepol/module.h>
+#include <sepol/module_to_cil.h>
+#include <sepol/policydb/conditional.h>
+#include <sepol/policydb/hashtab.h>
+#include <sepol/policydb/polcaps.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/util.h>
+
+#ifdef __GNUC__
+#  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+#else
+#  define UNUSED(x) UNUSED_ ## x
+#endif
+
+FILE *out_file;
+
+#define STACK_SIZE 16
+#define DEFAULT_LEVEL "systemlow"
+#define DEFAULT_OBJECT "object_r"
+#define GEN_REQUIRE_ATTR "cil_gen_require"
+
+__attribute__ ((format(printf, 1, 2)))
+static void log_err(const char *fmt, ...)
+{
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(stderr, fmt, argptr) < 0) {
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+	if (fprintf(stderr, "\n") < 0) {
+		_exit(EXIT_FAILURE);
+	}
+}
+
+static void cil_indent(int indent)
+{
+	if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+}
+
+__attribute__ ((format(printf, 1, 2)))
+static void cil_printf(const char *fmt, ...) {
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(out_file, fmt, argptr) < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void cil_println(int indent, const char *fmt, ...)
+{
+	cil_indent(indent);
+	va_list argptr;
+	va_start(argptr, fmt);
+	if (vfprintf(out_file, fmt, argptr) < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+	va_end(argptr);
+	if (fprintf(out_file, "\n") < 0) {
+		log_err("Failed to write to output");
+		_exit(EXIT_FAILURE);
+	}
+}
+
+struct map_args {
+	struct policydb *pdb;
+	struct avrule_block *block;
+	struct stack *decl_stack;
+	int scope;
+	int indent;
+	int sym_index;
+};
+
+struct stack {
+	 void **stack;
+	 int pos;
+	 int size;
+};
+
+struct role_list_node {
+	char *role_name;
+	role_datum_t *role;
+};
+
+struct attr_list_node {
+	char *attribute;
+	int is_type;
+	union {
+		struct type_set *ts;
+		struct role_set *rs;
+	} set;
+};
+
+struct list_node {
+	void *data;
+	struct list_node *next;
+};
+
+struct list {
+	struct list_node *head;
+};
+
+/* A linked list of all roles stored in the pdb
+ * which is iterated to determine types associated
+ * with each role when printing role_type statements
+ */
+static struct list *role_list;
+
+static void list_destroy(struct list **list)
+{
+	struct list_node *curr = (*list)->head;
+	struct list_node *tmp;
+
+	while (curr != NULL) {
+		tmp = curr->next;
+		free(curr);
+		curr = tmp;
+	}
+
+	free(*list);
+	*list = NULL;
+}
+
+static void role_list_destroy(void)
+{
+	struct list_node *curr = role_list->head;
+
+	while (curr != NULL) {
+		free(curr->data);
+		curr->data = NULL;
+		curr = curr->next;
+	}
+
+	list_destroy(&role_list);
+}
+
+static void attr_list_destroy(struct list **attr_list)
+{
+	if (attr_list == NULL || *attr_list == NULL) {
+		return;
+	}
+
+	struct list_node *curr = (*attr_list)->head;
+	struct attr_list_node *attr;
+
+	while (curr != NULL) {
+		attr = curr->data;
+		if (attr != NULL) {
+			free(attr->attribute);
+		}
+
+		free(curr->data);
+		curr->data = NULL;
+		curr = curr->next;
+	}
+
+	list_destroy(attr_list);
+}
+
+static int list_init(struct list **list)
+{
+	int rc = -1;
+	struct list *l = calloc(1, sizeof(*l));
+	if (l == NULL) {
+		goto exit;
+	}
+
+	*list = l;
+
+	return 0;
+
+exit:
+	list_destroy(&l);
+	return rc;
+}
+
+static int list_prepend(struct list *list, void *data)
+{
+	int rc = -1;
+	struct list_node *node = calloc(1, sizeof(*node));
+	if (node == NULL) {
+		goto exit;
+	}
+
+	node->data = data;
+	node->next = list->head;
+	list->head = node;
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int roles_gather_map(char *key, void *data, void *args)
+{
+	struct role_list_node *role_node;
+	role_datum_t *role = data;
+	int rc = -1;
+
+	role_node = calloc(1, sizeof(*role_node));
+	if (role_node == NULL) {
+		return rc;
+	}
+
+	role_node->role_name = key;
+	role_node->role = role;
+
+	rc = list_prepend((struct list *)args, role_node);
+	return rc;
+}
+
+static int role_list_create(hashtab_t roles_tab)
+{
+	int rc = -1;
+
+	rc = list_init(&role_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = hashtab_map(roles_tab, roles_gather_map, role_list);
+
+exit:
+	return rc;
+}
+
+// array of lists, where each list contains all the aliases defined in the scope at index i
+static struct list **typealias_lists;
+static uint32_t typealias_lists_len;
+
+static int typealiases_gather_map(char *key, void *data, void *arg)
+{
+	int rc = -1;
+	struct type_datum *type = data;
+	struct policydb *pdb = arg;
+	struct scope_datum *scope;
+	uint32_t i;
+	uint32_t scope_id;
+
+	if (type->primary != 1) {
+		scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
+		if (scope == NULL) {
+			return -1;
+		}
+
+		for (i = 0; i < scope->decl_ids_len; i++) {
+			scope_id = scope->decl_ids[i];
+			if (typealias_lists[scope_id] == NULL) {
+				rc = list_init(&typealias_lists[scope_id]);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+			list_prepend(typealias_lists[scope_id], key);
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static void typealias_list_destroy(void)
+{
+	uint32_t i;
+	for (i = 0; i < typealias_lists_len; i++) {
+		if (typealias_lists[i] != NULL) {
+			list_destroy(&typealias_lists[i]);
+		}
+	}
+	typealias_lists_len = 0;
+	free(typealias_lists);
+	typealias_lists = NULL;
+}
+
+static int typealias_list_create(struct policydb *pdb)
+{
+	uint32_t max_decl_id = 0;
+	struct avrule_decl *decl;
+	struct avrule_block *block;
+	uint32_t rc = -1;
+
+	for (block = pdb->global; block != NULL; block = block->next) {
+		decl = block->branch_list;
+		if (decl->decl_id > max_decl_id) {
+			max_decl_id = decl->decl_id;
+		}
+	}
+
+	typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
+	typealias_lists_len = max_decl_id + 1;
+
+	rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	typealias_list_destroy();
+
+	return rc;
+}
+
+
+static int stack_destroy(struct stack **stack)
+{
+	if (stack == NULL || *stack == NULL) {
+		return 0;
+	}
+
+	free((*stack)->stack);
+	free(*stack);
+	*stack = NULL;
+
+	return 0;
+}
+
+static int stack_init(struct stack **stack)
+{
+	int rc = -1;
+	struct stack *s = calloc(1, sizeof(*s));
+	if (s == NULL) {
+		goto exit;
+	}
+
+	s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
+	if (s->stack == NULL) {
+		goto exit;
+	}
+
+	s->pos = -1;
+	s->size = STACK_SIZE;
+
+	*stack = s;
+
+	return 0;
+
+exit:
+	stack_destroy(&s);
+	return rc;
+}
+
+static int stack_push(struct stack *stack, void *ptr)
+{
+	int rc = -1;
+	void *new_stack;
+
+	if (stack->pos + 1 == stack->size) {
+		new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
+		if (new_stack == NULL) {
+			goto exit;
+		}
+		stack->stack = new_stack;
+		stack->size *= 2;
+	}
+
+	stack->pos++;
+	stack->stack[stack->pos] = ptr;
+
+	rc = 0;
+exit:
+	return rc;
+}
+
+static void *stack_pop(struct stack *stack)
+{
+	if (stack->pos == -1) {
+		return NULL;
+	}
+
+	stack->pos--;
+	return stack->stack[stack->pos + 1];
+}
+
+static void *stack_peek(struct stack *stack)
+{
+	if (stack->pos == -1) {
+		return NULL;
+	}
+
+	return stack->stack[stack->pos];
+}
+
+static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
+{
+	int i;
+	uint32_t j;
+	struct avrule_decl *decl;
+	struct scope_datum *scope;
+
+	scope = hashtab_search(pdb->scope[symbol_type].table, id);
+	if (scope == NULL) {
+		return 0;
+	}
+
+	for (i = start; i >= 0; i--) {
+		decl = decl_stack->stack[i];
+
+		for (j = 0; j < scope->decl_ids_len; j++) {
+			if (scope->decl_ids[j] == decl->decl_id) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+	int start = decl_stack->pos - 1;
+
+	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
+{
+	int start = decl_stack->pos;
+
+	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
+}
+
+static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
+{
+	struct mls_semantic_cat *cat;
+
+	cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
+
+	if (level->cat != NULL) {
+		cil_printf("(");
+	}
+
+	for (cat = level->cat; cat != NULL; cat = cat->next) {
+		if (cat->low == cat->high) {
+			cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
+		} else {
+			cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
+		}
+
+		if (cat->next != NULL) {
+			cil_printf(" ");
+		}
+	}
+
+	if (level->cat != NULL) {
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	return 0;
+}
+
+static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
+{
+	int rc = -1;
+	const char *rule;
+	const struct class_perm_node *classperm;
+	char *perms;
+
+	switch (type) {
+	case AVRULE_ALLOWED:
+		rule = "allow";
+		break;
+	case AVRULE_AUDITALLOW:
+		rule = "auditallow";
+		break;
+	case AVRULE_AUDITDENY:
+		rule = "auditdenty";
+		break;
+	case AVRULE_DONTAUDIT:
+		rule = "dontaudit";
+		break;
+	case AVRULE_NEVERALLOW:
+		rule = "neverallow";
+		break;
+	case AVRULE_TRANSITION:
+		rule = "typetransition";
+		break;
+	case AVRULE_MEMBER:
+		rule = "typemember";
+		break;
+	case AVRULE_CHANGE:
+		rule = "typechange";
+		break;
+	default:
+		log_err("Unknown avrule type: %i", type);
+		rc = -1;
+		goto exit;
+	}
+
+	for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
+		if (type & AVRULE_AV) {
+			perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
+			if (perms == NULL) {
+				log_err("Failed to generate permission string");
+				rc = -1;
+				goto exit;
+			}
+			cil_println(indent, "(%s %s %s (%s (%s)))",
+					rule, src, tgt,
+					pdb->p_class_val_to_name[classperm->tclass - 1],
+					perms + 1);
+		} else {
+			cil_println(indent, "(%s %s %s %s %s)",
+					rule, src, tgt,
+					pdb->p_class_val_to_name[classperm->tclass - 1],
+					pdb->p_type_val_to_name[classperm->data - 1]);
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int num_digits(int n)
+{
+	int num = 1;
+	while (n >= 10) {
+		n /= 10;
+		num++;
+	}
+	return num;
+}
+
+static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
+{
+	static unsigned int num_attrs = 0;
+	int rc = -1;
+	int len, rlen;
+	const char *attr_infix;
+	char *attr;
+
+	num_attrs++;
+
+	if (is_type) {
+		attr_infix = "_typeattr_";
+	} else {
+		attr_infix = "_roleattr_";
+	}
+
+	len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
+	attr = malloc(len);
+	if (attr == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+	rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
+	if (rlen < 0 || rlen >= len) {
+		log_err("Failed to generate attribute name");
+		rc = -1;
+		goto exit;
+	}
+
+	*names = malloc(sizeof(**names));
+	if (*names == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+
+	*names[0] = attr;
+	*num_names = 1;
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
+{
+	// CIL doesn't support anonymous positive/negative/complemented sets.  So
+	// instead we create a CIL type/roleattributeset that matches the set. If
+	// the set has a negative set, then convert it to is (P & !N), where P is
+	// the list of members in the positive set , and N is the list of members
+	// in the negative set. Additonally, if the set is complemented, then wrap
+	// the whole thing with a negation.
+
+	int rc = 0;
+	struct ebitmap_node *node;
+	unsigned int i;
+	char *statement;
+	int has_positive = pos && (ebitmap_cardinality(pos) > 0);
+	int has_negative = neg && (ebitmap_cardinality(neg) > 0);
+	char **val_to_name;
+
+	if (is_type) {
+		statement = "type";
+		val_to_name = pdb->p_type_val_to_name;
+	} else {
+		statement = "role";
+		val_to_name = pdb->p_role_val_to_name;
+	}
+
+	cil_println(indent, "(%sattribute %s)", statement, attr);
+	cil_indent(indent);
+	cil_printf("(%sattributeset %s ", statement, attr);
+
+	if (flags & TYPE_STAR) {
+		cil_printf("(all)");
+	}
+
+	if (flags & TYPE_COMP) {
+		cil_printf("(not ");
+	}
+
+	if (has_positive && has_negative) {
+		cil_printf("(and ");
+	}
+
+	if (has_positive) {
+		cil_printf("(");
+		ebitmap_for_each_bit(pos, node, i) {
+			if (!ebitmap_get_bit(pos, i)) {
+				continue;
+			}
+			cil_printf("%s ", val_to_name[i]);
+		}
+		cil_printf(") ");
+	}
+
+	if (has_negative) {
+		cil_printf("(not (");
+
+		ebitmap_for_each_bit(neg, node, i) {
+			if (!ebitmap_get_bit(neg, i)) {
+				continue;
+			}
+			cil_printf("%s ", val_to_name[i]);
+		}
+
+		cil_printf("))");
+	}
+
+	if (has_positive && has_negative) {
+		cil_printf(")");
+	}
+
+	if (flags & TYPE_COMP) {
+		cil_printf(")");
+	}
+
+	cil_printf(")\n");
+
+	return rc;
+}
+
+static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+	char **val_to_name = pdb->sym_val_to_name[type];
+
+	ebitmap_for_each_bit(map, node, i) {
+		if (!ebitmap_get_bit(map, i)) {
+			continue;
+		}
+		cil_printf("%s ", val_to_name[i]);
+	}
+
+	return 0;
+}
+
+static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+	uint32_t num = 0;
+	uint32_t max = 8;
+	char **name_arr = NULL;
+
+	name_arr = malloc(sizeof(*name_arr) * max);
+	if (name_arr == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	ebitmap_for_each_bit(&map, node, i) {
+		if (!ebitmap_get_bit(&map, i)) {
+			continue;
+		}
+
+		if (num + 1 == max) {
+			max *= 2;
+			name_arr = realloc(name_arr, sizeof(*name_arr) * max);
+			if (name_arr == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+		}
+
+		name_arr[num] = strdup(vals_to_names[i]);
+		if (name_arr[num] == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+		num++;
+	}
+
+	*names = name_arr;
+	*num_names = num;
+
+	return 0;
+
+exit:
+	for (i = 0; i < num; i++) {
+		free(name_arr[i]);
+	}
+	free(name_arr);
+	return rc;
+}
+
+static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
+{
+	struct attr_list_node *attr_list_node = NULL;
+	int rc = -1;
+
+	attr_list_node = calloc(1, sizeof(*attr_list_node));
+	if (attr_list_node == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = list_prepend(attr_list, attr_list_node);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	attr_list_node->attribute = strdup(attribute);
+	if (attr_list_node->attribute == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	attr_list_node->is_type = is_type;
+	if (is_type) {
+		attr_list_node->set.ts = set;
+	} else {
+		attr_list_node->set.rs = set;
+	}
+
+	return rc;
+
+exit:
+	if (attr_list_node != NULL) {
+		free(attr_list_node->attribute);
+	}
+	free(attr_list_node);
+	return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+	int rc = -1;
+	if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
+		rc = set_to_cil_attr(pdb, 1, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		*generated_attribute = *names[0];
+	} else {
+		rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
+static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
+{
+	int rc = -1;
+	if (rs->flags != 0) {
+		rc = set_to_cil_attr(pdb, 0, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		*generated_attribute = *names[0];
+	} else {
+		rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+	int rc = -1;
+	char *generated_attribute = NULL;
+	*num_type_names = 0;
+
+	rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (generated_attribute == NULL) {
+		goto exit;
+	}
+
+	if (attr_list == NULL) {
+		rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+		if (rc != 0) {
+			goto exit;
+		}
+	} else {
+		rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
+{
+	int rc = -1;
+	char *generated_attribute = NULL;
+	*num_type_names = 0;
+
+	rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (generated_attribute == NULL) {
+		rc = 0;
+		goto exit;
+	}
+
+	if (attr_list == NULL) {
+		rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+		if (rc != 0) {
+			goto exit;
+		}
+	} else {
+		rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static void names_destroy(char ***names, uint32_t *num_names)
+{
+	char **arr = *names;
+	uint32_t num = *num_names;
+	uint32_t i;
+
+	for (i = 0; i < num; i++) {
+		free(arr[i]);
+		arr[i] = NULL;
+	}
+	free(arr);
+
+	*names = NULL;
+	*num_names = 0;
+}
+
+static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
+{
+	struct list_node *curr;
+	char **tnames = NULL;
+	uint32_t num_tnames, i;
+	struct role_list_node *role_node = NULL;
+	int rc;
+	struct type_set *ts;
+
+	curr = role_list->head;
+	for (curr = role_list->head; curr != NULL; curr = curr->next) {
+		role_node = curr->data;
+		if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
+			continue;
+		}
+
+		ts = &role_node->role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
+		if (rc != 0) {
+			goto exit;
+		}
+		for (i = 0; i < num_tnames; i++) {
+			if (!strcmp(type_name, tnames[i])) {
+				cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
+			}
+		}
+		names_destroy(&tnames, &num_tnames);
+	}
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+
+static int name_list_to_string(char **names, int num_names, char **string)
+{
+	// create a space separated string of the names
+	int rc = -1;
+	int len = 0;
+	int i;
+	char *str;
+	char *strpos;
+	int name_len;
+	int rlen;
+
+	for (i = 0; i < num_names; i++) {
+		len += strlen(names[i]);
+	}
+
+	// add spaces + null terminator
+	len += (num_names - 1) + 1;
+
+	str = malloc(len);
+	if (str == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	strpos = str;
+
+	for (i = 0; i < num_names; i++) {
+		name_len = strlen(names[i]);
+		rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
+		if (rlen < 0 || rlen >= len) {
+			log_err("Failed to generate name list");
+			rc = -1;
+			goto exit;
+		}
+
+		if (i < num_names - 1) {
+			strpos[name_len] = ' ';
+		}
+		strpos += name_len + 1;
+	}
+
+	*string = str;
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
+{
+	int rc = -1;
+	struct avrule *avrule;
+	char **snames = NULL;
+	char **tnames = NULL;
+	uint32_t num_snames;
+	uint32_t num_tnames;
+	uint32_t s;
+	uint32_t t;
+	struct type_set *ts;
+
+	for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
+		ts = &avrule->stypes;
+		rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &avrule->ttypes;
+		rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (s = 0; s < num_snames; s++) {
+			for (t = 0; t < num_tnames; t++) {
+				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+
+			if (avrule->flags & RULE_SELF) {
+				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
+				if (rc != 0) {
+					goto exit;
+				}
+			}
+		}
+
+		names_destroy(&snames, &num_snames);
+		names_destroy(&tnames, &num_tnames);
+	}
+
+	return 0;
+
+exit:
+	names_destroy(&snames, &num_snames);
+	names_destroy(&tnames, &num_tnames);
+
+	return rc;
+}
+
+static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
+{
+	int rc = -1;
+	struct cond_expr *curr;
+	struct stack *stack = NULL;
+	int len = 0;
+	int rlen;
+	char *new_val = NULL;
+	char *val1 = NULL;
+	char *val2 = NULL;
+	int num_params;
+	const char *op;
+	const char *fmt_str;
+	const char *type;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		log_err("Out of memory");
+		goto exit;
+	}
+
+	for (curr = cond_expr; curr != NULL; curr = curr->next) {
+		if (curr->expr_type == COND_BOOL) {
+			val1 = pdb->p_bool_val_to_name[curr->bool - 1];
+			// length of boolean + 2 parens + null terminator
+			len = strlen(val1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+			rlen = snprintf(new_val, len, "(%s)", val1);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate conditional expression");
+				rc = -1;
+				goto exit;
+			}
+			num_params = 0;
+		} else {
+			switch(curr->expr_type) {
+			case COND_NOT:	op = "not";	break;
+			case COND_OR:	op = "or";	break;
+			case COND_AND:	op = "and";	break;
+			case COND_XOR:	op = "xor";	break;
+			case COND_EQ:	op = "eq";	break;
+			case COND_NEQ:	op = "neq";	break;
+			default:
+				rc = -1;
+				goto exit;
+			}
+
+			num_params = curr->expr_type == COND_NOT ? 1 : 2;
+
+			if (num_params == 1) {
+				val1 = stack_pop(stack);
+				val2 = strdup("");
+				if (val2 == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				fmt_str = "(%s %s)";
+			} else {
+				val2 = stack_pop(stack);
+				val1 = stack_pop(stack);
+				fmt_str = "(%s %s %s)";
+			}
+
+			if (val1 == NULL || val2 == NULL) {
+				log_err("Invalid conditional expression");
+				rc = -1;
+				goto exit;
+			}
+
+			// length = length of parameters +
+			//          length of operator +
+			//          1 space preceeding each parameter +
+			//          2 parens around the whole expression
+			//          + null terminator
+			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+
+			// although we always supply val2 and there isn't always a 2nd
+			// value, it should only be used when there are actually two values
+			// in the format strings
+			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate conditional expression");
+				rc = -1;
+				goto exit;
+			}
+
+			free(val1);
+			free(val2);
+			val1 = NULL;
+			val2 = NULL;
+		}
+
+		rc = stack_push(stack, new_val);
+		if (rc != 0) {
+			log_err("Out of memory");
+			goto exit;
+		}
+		new_val = NULL;
+	}
+
+	if (flags & COND_NODE_FLAGS_TUNABLE) {
+		type = "tunableif";
+	} else {
+		type = "booleanif";
+	}
+
+	val1 = stack_pop(stack);
+	if (val1 == NULL || stack_peek(stack) != NULL) {
+		log_err("Invalid conditional expression");
+		rc = -1;
+		goto exit;
+	}
+
+	cil_println(indent, "(%s %s", type, val1);
+	free(val1);
+	val1 = NULL;
+
+	rc = 0;
+
+exit:
+	free(new_val);
+	free(val1);
+	free(val2);
+	while ((val1 = stack_pop(stack)) != NULL) {
+		free(val1);
+	}
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
+{
+	struct list_node *curr;
+	struct attr_list_node *attr_list_node;
+	int rc = 0;
+	struct type_set *ts;
+	struct role_set *rs;
+	char *generated_attribute;
+
+	for (curr = attr_list->head; curr != NULL; curr = curr->next) {
+		attr_list_node = curr->data;
+		generated_attribute = attr_list_node->attribute;
+		if (generated_attribute == NULL) {
+			return -1;
+		}
+
+		if (attr_list_node->is_type) {
+			ts = attr_list_node->set.ts;
+			rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
+			if (rc != 0) {
+				return rc;
+			}
+		} else {
+			rs = attr_list_node->set.rs;
+			rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
+			if (rc != 0) {
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
+{
+	int rc = -1;
+	struct cond_node *cond;
+	struct list *attr_list;
+
+	rc = list_init(&attr_list);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (cond = cond_list; cond != NULL; cond = cond->next) {
+
+		rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		if (cond->avtrue_list != NULL) {
+			cil_println(indent + 1, "(true");
+			rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
+			if (rc != 0) {
+				goto exit;
+			}
+			cil_println(indent + 1, ")");
+		}
+
+		if (cond->avfalse_list != NULL) {
+			cil_println(indent + 1, "(false");
+			rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
+			if (rc != 0) {
+				goto exit;
+			}
+			cil_println(indent + 1, ")");
+		}
+
+		cil_println(indent, ")");
+	}
+
+	rc = cil_print_attr_list(indent, pdb, attr_list);
+
+exit:
+	attr_list_destroy(&attr_list);
+	return rc;
+}
+
+static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
+{
+	int rc = -1;
+	struct role_trans_rule *rule;
+	char **role_names = NULL;
+	uint32_t num_role_names = 0;
+	char **type_names = NULL;
+	uint32_t num_type_names = 0;
+	uint32_t type;
+	uint32_t role;
+	uint32_t i;
+	struct ebitmap_node *node;
+	struct type_set *ts;
+	struct role_set *rs;
+
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		rs = &rule->roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (role = 0; role < num_role_names; role++) {
+			for (type = 0; type < num_type_names; type++) {
+				ebitmap_for_each_bit(&rule->classes, node, i) {
+					if (!ebitmap_get_bit(&rule->classes, i)) {
+						continue;
+					}
+					cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
+					                                                    type_names[type],
+					                                                    pdb->p_class_val_to_name[i],
+					                                                    pdb->p_role_val_to_name[rule->new_role - 1]);
+				}
+			}
+		}
+
+		names_destroy(&role_names, &num_role_names);
+		names_destroy(&type_names, &num_type_names);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&role_names, &num_role_names);
+	names_destroy(&type_names, &num_type_names);
+
+	return rc;
+}
+
+static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
+{
+	int rc = -1;
+	struct role_allow_rule *rule;
+	char **roles = NULL;
+	uint32_t num_roles = 0;
+	char **new_roles = NULL;
+	uint32_t num_new_roles = 0;
+	uint32_t i;
+	uint32_t j;
+	struct role_set *rs;
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		rs = &rule->roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rs = &rule->new_roles;
+		rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (i = 0; i < num_roles; i++) {
+			for (j = 0; j < num_new_roles; j++) {
+				cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
+			}
+		}
+
+		names_destroy(&roles, &num_roles);
+		names_destroy(&new_roles, &num_new_roles);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&roles, &num_roles);
+	names_destroy(&new_roles, &num_new_roles);
+
+	return rc;
+}
+
+static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
+{
+	int rc = -1;
+	struct range_trans_rule *rule;
+	char **stypes = NULL;
+	uint32_t num_stypes = 0;
+	char **ttypes = NULL;
+	uint32_t num_ttypes = 0;
+	struct ebitmap_node *node;
+	uint32_t i;
+	uint32_t stype;
+	uint32_t ttype;
+	struct type_set *ts;
+
+	if (!pdb->mls) {
+		return 0;
+	}
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		ts = &rule->stypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->ttypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (stype = 0; stype < num_stypes; stype++) {
+			for (ttype = 0; ttype < num_ttypes; ttype++) {
+				ebitmap_for_each_bit(&rule->tclasses, node, i) {
+					if (!ebitmap_get_bit(&rule->tclasses, i)) {
+						continue;
+					}
+
+					cil_indent(indent);
+					cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
+
+					cil_printf("(");
+
+					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
+					if (rc != 0) {
+						goto exit;
+					}
+
+					cil_printf(" ");
+
+					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
+					if (rc != 0) {
+						goto exit;
+					}
+
+					cil_printf("))\n");
+				}
+
+			}
+		}
+
+		names_destroy(&stypes, &num_stypes);
+		names_destroy(&ttypes, &num_ttypes);
+	}
+
+	rc = 0;
+
+exit:
+	names_destroy(&stypes, &num_stypes);
+	names_destroy(&ttypes, &num_ttypes);
+
+	return rc;
+}
+
+static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
+{
+	int rc = -1;
+	char **stypes = NULL;
+	uint32_t num_stypes = 0;
+	char **ttypes = NULL;
+	uint32_t num_ttypes = 0;
+	uint32_t stype;
+	uint32_t ttype;
+	struct type_set *ts;
+
+	struct filename_trans_rule *rule;
+
+	for (rule = rules; rule != NULL; rule = rule->next) {
+		ts = &rule->stypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		ts = &rule->ttypes;
+		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (stype = 0; stype < num_stypes; stype++) {
+			for (ttype = 0; ttype < num_ttypes; ttype++) {
+				cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
+				                                                       ttypes[ttype],
+				                                                       pdb->p_class_val_to_name[rule->tclass - 1],
+				                                                       rule->name,
+				                                                       pdb->p_type_val_to_name[rule->otype - 1]);
+			}
+		}
+
+		names_destroy(&stypes, &num_stypes);
+		names_destroy(&ttypes, &num_ttypes);
+	}
+
+	rc = 0;
+exit:
+	names_destroy(&stypes, &num_stypes);
+	names_destroy(&ttypes, &num_ttypes);
+
+	return rc;
+}
+
+struct class_perm_datum {
+	char *name;
+	uint32_t val;
+};
+
+struct class_perm_array {
+	struct class_perm_datum *perms;
+	uint32_t count;
+};
+
+static int class_perm_to_array(char *key, void *data, void *args)
+{
+	struct class_perm_array *arr = args;
+	struct perm_datum *datum = data;
+	arr->perms[arr->count].name = key;
+	arr->perms[arr->count].val = datum->s.value;
+	arr->count++;
+
+	return 0;
+}
+
+static int class_perm_cmp(const void *a, const void *b)
+{
+	const struct class_perm_datum *aa = a;
+	const struct class_perm_datum *bb = b;
+
+	return aa->val - bb->val;
+}
+
+static int common_to_cil(char *key, void *data, void *UNUSED(arg))
+{
+	int rc = -1;
+	struct common_datum *common = data;
+	struct class_perm_array arr;
+	uint32_t i;
+
+	arr.count = 0;
+	arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
+	rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+	cil_printf("(common %s (", key);
+	for (i = 0; i < arr.count; i++) {
+		cil_printf("%s ", arr.perms[i].name);
+	}
+	cil_printf("))\n");
+
+	rc = 0;
+
+exit:
+	free(arr.perms);
+	return rc;
+}
+
+
+static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
+{
+	int rc = -1;
+	struct constraint_expr *expr;
+	struct stack *stack = NULL;
+	int len = 0;
+	int rlen;
+	char *new_val = NULL;
+	char *val1 = NULL;
+	char *val2 = NULL;
+	uint32_t num_params;
+	const char *op;
+	const char *fmt_str;
+	const char *attr1;
+	const char *attr2;
+	char *names;
+	char **name_list = NULL;
+	uint32_t num_names = 0;
+	struct type_set *ts;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (expr = exprs; expr != NULL; expr = expr->next) {
+		if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
+			switch (expr->op) {
+			case CEXPR_EQ:      op = "eq";     break;
+			case CEXPR_NEQ:     op = "neq";    break;
+			case CEXPR_DOM:     op = "dom";    break;
+			case CEXPR_DOMBY:   op = "domby";  break;
+			case CEXPR_INCOMP:  op = "incomp"; break;
+			default:
+				log_err("Unknown constraint operator type: %i", expr->op);
+				rc = -1;
+				goto exit;
+			}
+
+			switch (expr->attr) {
+			case CEXPR_USER:                 attr1 = "u1"; attr2 = "u2"; break;
+			case CEXPR_USER | CEXPR_TARGET:  attr1 = "u2"; attr2 = "";   break;
+			case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = "";   break;
+			case CEXPR_ROLE:                 attr1 = "r1"; attr2 = "r2"; break;
+			case CEXPR_ROLE | CEXPR_TARGET:  attr1 = "r2"; attr2 = "";   break;
+			case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = "";   break;
+			case CEXPR_TYPE:                 attr1 = "t1"; attr2 = "";   break;
+			case CEXPR_TYPE | CEXPR_TARGET:  attr1 = "t2"; attr2 = "";   break;
+			case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = "";   break;
+			case CEXPR_L1L2:                 attr1 = "l1"; attr2 = "l2"; break;
+			case CEXPR_L1H2:                 attr1 = "l1"; attr2 = "h2"; break;
+			case CEXPR_H1L2:                 attr1 = "h1"; attr2 = "l2"; break;
+			case CEXPR_H1H2:                 attr1 = "h1"; attr2 = "h2"; break;
+			case CEXPR_L1H1:                 attr1 = "l1"; attr2 = "h1"; break;
+			case CEXPR_L2H2:                 attr1 = "l2"; attr2 = "h2"; break;
+			default:
+				log_err("Unknown expression attribute type: %i", expr->attr);
+				rc = -1;
+				goto exit;
+			}
+
+			if (expr->expr_type == CEXPR_ATTR) {
+				// length of values/attrs + 2 separating spaces + 2 parens + null terminator
+				len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
+				new_val = malloc(len);
+				if (new_val == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
+				if (rlen < 0 || rlen >= len) {
+					log_err("Failed to generate constraint expression");
+					rc = -1;
+					goto exit;
+				}
+			} else {
+				if (expr->attr & CEXPR_TYPE) {
+					ts = expr->type_names;
+					rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				} else if (expr->attr & CEXPR_USER) {
+					rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				} else if (expr->attr & CEXPR_ROLE) {
+					rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
+					if (rc != 0) {
+						goto exit;
+					}
+				}
+				rc = name_list_to_string(name_list, num_names, &names);
+				if (rc != 0) {
+					goto exit;
+				}
+
+				// length of values/oper + 2 spaces + 2 parens + null terminator
+				len = strlen(op) + strlen(attr1) +  strlen(names) + 2 + 2 + 1;
+				new_val = malloc(len);
+				if (new_val == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
+				if (rlen < 0 || rlen >= len) {
+					log_err("Failed to generate constraint expression");
+					rc = -1;
+					goto exit;
+				}
+
+				names_destroy(&name_list, &num_names);
+				free(names);
+			}
+
+			num_params = 0;
+		} else {
+			switch (expr->expr_type) {
+			case CEXPR_NOT: op = "not"; break;
+			case CEXPR_AND: op = "and"; break;
+			case CEXPR_OR:  op = "or"; break;
+			default:
+				log_err("Unknown constraint expression type: %i", expr->expr_type);
+				rc = -1;
+				goto exit;
+			}
+
+			num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
+
+			if (num_params == 1) {
+				val1 = stack_pop(stack);
+				val2 = strdup("");
+				if (val2 == NULL) {
+					log_err("Out of memory");
+					rc = -1;
+					goto exit;
+				}
+				fmt_str = "(%s %s)";
+			} else {
+				val2 = stack_pop(stack);
+				val1 = stack_pop(stack);
+				fmt_str = "(%s %s %s)";
+			}
+
+			if (val1 == NULL || val2 == NULL) {
+				log_err("Invalid constraint expression");
+				rc = -1;
+				goto exit;
+			}
+
+			// length = length of parameters +
+			//          length of operator +
+			//          1 space preceeding each parameter +
+			//          2 parens around the whole expression
+			//          + null terminator
+			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
+			new_val = malloc(len);
+			if (new_val == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+
+			// although we always supply val2 and there isn't always a 2nd
+			// value, it should only be used when there are actually two values
+			// in the format strings
+			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+			if (rlen < 0 || rlen >= len) {
+				log_err("Failed to generate constraint expression");
+				rc = -1;
+				goto exit;
+			}
+
+			free(val1);
+			free(val2);
+			val1 = NULL;
+			val2 = NULL;
+		}
+
+		rc = stack_push(stack, new_val);
+		if (rc != 0) {
+			log_err("Out of memory");
+			goto exit;
+		}
+
+		new_val = NULL;
+	}
+
+	new_val = stack_pop(stack);
+	if (new_val == NULL || stack_peek(stack) != NULL) {
+		log_err("Invalid constraint expression");
+		rc = -1;
+		goto exit;
+	}
+
+	*expr_string = new_val;
+	new_val = NULL;
+
+	rc = 0;
+
+exit:
+	names_destroy(&name_list, &num_names);
+
+	free(new_val);
+	free(val1);
+	free(val2);
+	while ((val1 = stack_pop(stack)) != NULL) {
+		free(val1);
+	}
+	stack_destroy(&stack);
+
+	return rc;
+}
+
+
+static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
+{
+	int rc = -1;
+	struct constraint_node *node;
+	char *expr = NULL;
+	const char *mls;
+	char *perms;
+
+	mls = pdb->mls ? "mls" : "";
+
+	for (node = constraints; node != NULL; node = node->next) {
+
+		rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		if (is_constraint) {
+			perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
+			cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
+		} else {
+			cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
+		}
+
+		free(expr);
+		expr = NULL;
+	}
+
+	rc = 0;
+
+exit:
+	free(expr);
+	return rc;
+}
+
+static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct class_datum *class = datum;
+	const char *dflt;
+	struct class_perm_array arr;
+	uint32_t i;
+
+	if (scope == SCOPE_REQ) {
+		return 0;
+	}
+
+	arr.count = 0;
+	arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
+	rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
+
+	cil_indent(indent);
+	cil_printf("(class %s (", key);
+	for (i = 0; i < arr.count; i++) {
+		cil_printf("%s ", arr.perms[i].name);
+	}
+	cil_printf("))\n");
+
+	if (class->comkey != NULL) {
+		cil_println(indent, "(classcommon %s %s)", key, class->comkey);
+	}
+
+	if (class->default_user != 0) {
+		switch (class->default_user) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default user value: %i", class->default_user);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultuser %s %s)", key, dflt);
+	}
+
+	if (class->default_role != 0) {
+		switch (class->default_role) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default role value: %i", class->default_role);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultrole %s %s)", key, dflt);
+	}
+
+	if (class->default_type != 0) {
+		switch (class->default_type) {
+		case DEFAULT_SOURCE:	dflt = "source";	break;
+		case DEFAULT_TARGET:	dflt = "target";	break;
+		default:
+			log_err("Unknown default type value: %i", class->default_type);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaulttype %s %s)", key, dflt);
+	}
+
+	if (class->default_range != 0) {
+		switch (class->default_range) {
+		case DEFAULT_SOURCE_LOW:		dflt = "source low";	break;
+		case DEFAULT_SOURCE_HIGH:		dflt = "source high";	break;
+		case DEFAULT_SOURCE_LOW_HIGH:	dflt = "source low-high";	break;
+		case DEFAULT_TARGET_LOW:		dflt = "target low";	break;
+		case DEFAULT_TARGET_HIGH:		dflt = "target high";	break;
+		case DEFAULT_TARGET_LOW_HIGH:	dflt = "target low-high";	break;
+		default:
+			log_err("Unknown default range value: %i", class->default_range);
+			rc = -1;
+			goto exit;
+		}
+		cil_println(indent, "(defaultrange %s %s)", key, dflt);
+
+	}
+
+	if (class->constraints != NULL) {
+		rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	if (class->validatetrans != NULL) {
+		rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	rc = 0;
+
+exit:
+	free(arr.perms);
+	return rc;
+}
+
+static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		return 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(classorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+}
+
+static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+	char **types = NULL;
+	uint32_t num_types = 0;
+	struct role_datum *role = datum;
+	struct type_set *ts;
+
+	if (scope == SCOPE_REQ) {
+		// if a role/roleattr is in the REQ scope, then it could cause an
+		// optional block to fail, even if it is never used. However in CIL,
+		// symbols must be used in order to cause an optional block to fail. So
+		// for symbols in the REQ scope, add them to a roleattribute as a way
+		// to 'use' them in the optional without affecting the resulting policy.
+		cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
+	}
+
+	switch (role->flavor) {
+	case ROLE_ROLE:
+		if (scope == SCOPE_DECL) {
+			// Only declare certain roles if we are reading a base module.
+			// These roles are defined in the base module and sometimes in
+			// other non-base modules. If we generated the roles regardless of
+			// the policy type, it would result in duplicate declarations,
+			// which isn't allowed in CIL. Patches have been made to refpolicy
+			// to remove these duplicate role declarations, but we need to be
+			// backwards compatable and support older policies. Since we know
+			// these roles are always declared in base, only print them when we
+			// see them in the base module. If the declarations appear in a
+			// non-base module, ignore their declarations.
+			//
+			// Note that this is a hack, and if a policy author does not define
+			// one of these roles in base, the declaration will not appeaer in
+			// the resulting policy, likely resulting in a compilation error in
+			// CIL.
+			int is_base_role = (!strcmp(key, "user_r") ||
+			                    !strcmp(key, "staff_r") ||
+			                    !strcmp(key, "sysadm_r") ||
+			                    !strcmp(key, "system_r") ||
+			                    !strcmp(key, "unconfined_r"));
+			if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) || !is_base_role) {
+				cil_println(indent, "(role %s)", key);
+			}
+		}
+
+		if (ebitmap_cardinality(&role->dominates) > 1) {
+			log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
+		}
+
+		ts = &role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		for (i = 0; i < num_types; i++) {
+			if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
+				cil_println(indent, "(roletype %s %s)", key, types[i]);
+			}
+		}
+
+		if (role->bounds > 0) {
+			cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
+		}
+		break;
+
+	case ROLE_ATTRIB:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(roleattribute %s)", key);
+		}
+
+		if (ebitmap_cardinality(&role->roles) > 0) {
+			cil_indent(indent);
+			cil_printf("(roleattributeset %s (", key);
+			ebitmap_for_each_bit(&role->roles, node, i) {
+				if (!ebitmap_get_bit(&role->roles, i)) {
+					continue;
+				}
+				cil_printf("%s ", pdb->p_role_val_to_name[i]);
+			}
+			cil_printf("))\n");
+		}
+
+		ts = &role->types;
+		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
+		if (rc != 0) {
+			goto exit;
+		}
+
+
+		for (i = 0; i < num_types; i++) {
+			cil_println(indent, "(roletype %s %s)", key, types[i]);
+		}
+
+		break;
+
+	default:
+		log_err("Unknown role type: %i", role->flavor);
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	names_destroy(&types, &num_types);
+
+	return rc;
+}
+
+static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
+{
+	int rc = -1;
+	struct type_datum *type = datum;
+
+	if (scope == SCOPE_REQ) {
+		// if a type/typeattr is in the REQ scope, then it could cause an
+		// optional block to fail, even if it is never used. However in CIL,
+		// symbols must be used in order to cause an optional block to fail. So
+		// for symbols in the REQ scope, add them to a typeattribute as a way
+		// to 'use' them in the optional without affecting the resulting policy.
+		cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
+	}
+
+	rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	switch(type->flavor) {
+	case TYPE_TYPE:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(type %s)", key);
+			// object_r is implicit in checkmodule, but not with CIL,
+			// create it as part of base
+			cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
+		}
+
+		if (type->flags & TYPE_FLAGS_PERMISSIVE) {
+			cil_println(indent, "(typepermissive %s)", key);
+		}
+
+		if (type->bounds > 0) {
+			cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
+		}
+		break;
+	case TYPE_ATTRIB:
+		if (scope == SCOPE_DECL) {
+			cil_println(indent, "(typeattribute %s)", key);
+		}
+
+		if (ebitmap_cardinality(&type->types) > 0) {
+			cil_indent(indent);
+			cil_printf("(typeattributeset %s (", key);
+			ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
+			cil_printf("))\n");
+		}
+		break;
+	default:
+		log_err("Unknown flavor (%i) of type %s", type->flavor, key);
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	return rc;
+}
+
+static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct user_datum *user = datum;
+	struct ebitmap roles = user->roles.roles;
+	struct mls_semantic_level level = user->dfltlevel;
+	struct mls_semantic_range range = user->range;
+	struct ebitmap_node *node;
+	uint32_t i;
+	int sens_offset = 1;
+
+	if (scope == SCOPE_DECL) {
+		cil_println(indent, "(user %s)", key);
+		// object_r is implicit in checkmodule, but not with CIL, create it
+		// as part of base
+		cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
+	}
+
+	ebitmap_for_each_bit(&roles, node, i) {
+		if (!ebitmap_get_bit(&roles, i)) {
+			continue;
+		}
+		cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
+	}
+
+	if (block->flags & AVRULE_OPTIONAL) {
+		// sensitivites in user statements in optionals do not have the
+		// standard -1 offest
+		sens_offset = 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(userlevel %s ", key);
+	if (pdb->mls) {
+		semantic_level_to_cil(pdb, sens_offset, &level);
+	} else {
+		cil_printf(DEFAULT_LEVEL);
+	}
+	cil_printf(")\n");
+
+	cil_indent(indent);
+	cil_printf("(userrange %s (", key);
+	if (pdb->mls) {
+		semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
+		cil_printf(" ");
+		semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
+	} else {
+		cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
+	}
+	cil_printf("))\n");
+
+
+	return 0;
+}
+
+static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct cond_bool_datum *boolean = datum;
+	const char *type;
+
+	if (scope == SCOPE_DECL) {
+		if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
+			type = "tunable";
+		} else {
+			type = "boolean";
+		}
+
+		cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
+	}
+
+	return 0;
+}
+
+static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
+{
+	struct level_datum *level = datum;
+
+	if (scope == SCOPE_DECL) {
+		if (!level->isalias) {
+			cil_println(indent, "(sensitivity %s)", key);
+		} else {
+			cil_println(indent, "(sensitivityalias %s)", key);
+			cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
+		}
+	}
+
+	if (ebitmap_cardinality(&level->level->cat) > 0) {
+		cil_indent(indent);
+		cil_printf("(sensitivitycategory %s (", key);
+		ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
+		cil_printf("))\n");
+	}
+
+	return 0;
+}
+
+static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		return 0;
+	}
+
+	cil_indent(indent);
+	cil_printf("(sensitivityorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->p_sens_val_to_name[i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+}
+
+static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
+{
+	struct cat_datum *cat = datum;
+
+	if (scope == SCOPE_REQ) {
+		return 0;
+	}
+
+	if (!cat->isalias) {
+		cil_println(indent, "(category %s)", key);
+	} else {
+		cil_println(indent, "(categoryalias %s)", key);
+		cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
+	}
+
+	return 0;
+}
+
+static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
+{
+	int rc = -1;
+	struct ebitmap_node *node;
+	uint32_t i;
+
+	if (ebitmap_cardinality(&order) == 0) {
+		rc = 0;
+		goto exit;
+	}
+
+	cil_indent(indent);
+	cil_printf("(categoryorder (");
+
+	ebitmap_for_each_bit(&order, node, i) {
+		if (!ebitmap_get_bit(&order, i)) {
+			continue;
+		}
+		cil_printf("%s ", pdb->p_cat_val_to_name[i]);
+	}
+
+	cil_printf("))\n");
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int polcaps_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	struct ebitmap *map;
+	struct ebitmap_node *node;
+	uint32_t i;
+	const char *name;
+
+	map = &pdb->policycaps;
+
+	ebitmap_for_each_bit(map, node, i) {
+		if (!ebitmap_get_bit(map, i)) {
+			continue;
+		}
+		name = sepol_polcap_getname(i);
+		if (name == NULL) {
+			log_err("Unknown policy capability id: %i", i);
+			rc = -1;
+			goto exit;
+		}
+
+		cil_println(0, "(policycap %s)", name);
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int level_to_cil(struct policydb *pdb, struct mls_level *level)
+{
+	struct ebitmap *map = &level->cat;
+
+	cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
+
+	if (ebitmap_cardinality(map) > 0) {
+		cil_printf("(");
+		ebitmap_to_cil(pdb, map, SYM_CATS);
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	return 0;
+}
+
+static int context_to_cil(struct policydb *pdb, struct context_struct *con)
+{
+	cil_printf("(%s %s %s (",
+		pdb->p_user_val_to_name[con->user - 1],
+		pdb->p_role_val_to_name[con->role - 1],
+		pdb->p_type_val_to_name[con->type - 1]);
+
+	if (pdb->mls) {
+		level_to_cil(pdb, &con->range.level[0]);
+		cil_printf(" ");
+		level_to_cil(pdb, &con->range.level[1]);
+	} else {
+		cil_printf(DEFAULT_LEVEL);
+		cil_printf(" ");
+		cil_printf(DEFAULT_LEVEL);
+	}
+
+	cil_printf("))");
+
+	return 0;
+}
+
+static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
+{
+	int rc = -1;
+
+	struct ocontext *isid;
+
+	struct sid_item {
+		const char *sid_key;
+		struct sid_item *next;
+	};
+
+	struct sid_item *head = NULL;
+	struct sid_item *item = NULL;
+
+	for (isid = isids; isid != NULL; isid = isid->next) {
+		cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
+		cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
+		context_to_cil(pdb, &isid->context[0]);
+		cil_printf(")\n");
+
+		// get the sid names in the correct order (reverse from the isids
+		// ocontext) for sidorder statement
+		item = malloc(sizeof(*item));
+		if (item == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+		item->sid_key = sid_to_string[isid->sid[0]];
+		item->next = head;
+		head = item;
+	}
+
+	if (head != NULL) {
+		cil_printf("(sidorder (");
+		for (item = head; item != NULL; item = item->next) {
+			cil_printf("%s ", item->sid_key);
+		}
+		cil_printf("))\n");
+	}
+
+	rc = 0;
+
+exit:
+	while(head) {
+		item = head;
+		head = item->next;
+		free(item);
+	}
+	return rc;
+}
+
+static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+	int rc = -1;
+
+	// initial sid names aren't actually stored in the pp files, need to a have
+	// a mapping, taken from the linux kernel
+	static const char *selinux_sid_to_string[] = {
+		"null",
+		"kernel",
+		"security",
+		"unlabeled",
+		"fs",
+		"file",
+		"file_labels",
+		"init",
+		"any_socket",
+		"port",
+		"netif",
+		"netmsg",
+		"node",
+		"igmp_packet",
+		"icmp_socket",
+		"tcp_socket",
+		"sysctl_modprobe",
+		"sysctl",
+		"sysctl_fs",
+		"sysctl_kernel",
+		"sysctl_net",
+		"sysctl_net_unix",
+		"sysctl_vm",
+		"sysctl_dev",
+		"kmod",
+		"policy",
+		"scmp_packet",
+		"devnull",
+		NULL
+	};
+
+	rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
+{
+	if (fss != NULL) {
+		log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
+	}
+
+	return 0;
+}
+
+static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
+{
+	int rc = -1;
+	struct ocontext *portcon;
+	const char *protocol;
+	uint16_t high;
+	uint16_t low;
+
+	for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
+
+		switch (portcon->u.port.protocol) {
+		case IPPROTO_TCP: protocol = "tcp"; break;
+		case IPPROTO_UDP: protocol = "udp"; break;
+		default:
+			log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
+			rc = -1;
+			goto exit;
+		}
+
+		low = portcon->u.port.low_port;
+		high = portcon->u.port.high_port;
+
+		if (low == high) {
+			cil_printf("(portcon %s %i ", protocol, low);
+		} else {
+			cil_printf("(portcon %s (%i %i) ", protocol, low, high);
+		}
+
+		context_to_cil(pdb, &portcon->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
+{
+	struct ocontext *netif;
+
+	for (netif = netifs; netif != NULL; netif = netif->next) {
+		cil_printf("(netifcon %s ", netif->u.name);
+		context_to_cil(pdb, &netif->context[0]);
+
+		cil_printf(" ");
+		context_to_cil(pdb, &netif->context[1]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+	int rc = -1;
+	struct ocontext *node;
+	char addr[INET_ADDRSTRLEN];
+	char mask[INET_ADDRSTRLEN];
+
+	for (node = nodes; node != NULL; node = node->next) {
+		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon address is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon mask is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(nodecon %s %s ", addr, mask);
+
+		context_to_cil(pdb, &node->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
+{
+	int rc = -1;
+	struct ocontext *node;
+	char addr[INET6_ADDRSTRLEN];
+	char mask[INET6_ADDRSTRLEN];
+
+	for (node = nodes; node != NULL; node = node->next) {
+		if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon address is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
+			log_err("Nodecon mask is invalid: %s", strerror(errno));
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(nodecon %s %s ", addr, mask);
+
+		context_to_cil(pdb, &node->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
+{
+	int rc = -1;
+	struct ocontext *fsuse;
+	const char *behavior;
+
+
+	for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
+		switch (fsuse->v.behavior) {
+		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
+		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
+		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
+		default:
+			log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
+			rc = -1;
+			goto exit;
+		}
+
+		cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
+
+		context_to_cil(pdb, &fsuse->context[0]);
+
+		cil_printf(")\n");
+
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
+{
+	int rc = -1;
+
+	// initial sid names aren't actually stored in the pp files, need to a have
+	// a mapping, taken from the xen kernel
+	static const char *xen_sid_to_string[] = {
+		"null",
+		"xen",
+		"dom0",
+		"domio",
+		"domxen",
+		"unlabeled",
+		"security",
+		"ioport",
+		"iomem",
+		"irq",
+		"device",
+		NULL,
+	};
+
+	rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
+{
+	struct ocontext *pirq;
+
+	for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
+		cil_printf("(pirqcon %i ", pirq->u.pirq);
+		context_to_cil(pdb, &pirq->context[0]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
+{
+	struct ocontext *ioport;
+	uint32_t low;
+	uint32_t high;
+
+	for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
+		low = ioport->u.ioport.low_ioport;
+		high = ioport->u.ioport.high_ioport;
+
+		if (low == high) {
+			cil_printf("(ioportcon %i ", low);
+		} else {
+			cil_printf("(ioportcon (%i %i) ", low, high);
+		}
+
+		context_to_cil(pdb, &ioport->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
+{
+	struct ocontext *iomem;
+	uint64_t low;
+	uint64_t high;
+
+	for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
+		low = iomem->u.iomem.low_iomem;
+		high = iomem->u.iomem.high_iomem;
+
+		if (low == high) {
+			cil_printf("(iomemcon %#lX ", (unsigned long)low);
+		} else {
+			cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
+		}
+
+		context_to_cil(pdb, &iomem->context[0]);
+
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
+{
+	struct ocontext *pcid;
+
+	for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
+		cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
+		context_to_cil(pdb, &pcid->context[0]);
+		cil_printf(")\n");
+	}
+
+	return 0;
+}
+
+static int ocontexts_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	int ocon;
+
+	static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
+	static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+		ocontext_selinux_isid_to_cil,
+		ocontext_selinux_fs_to_cil,
+		ocontext_selinux_port_to_cil,
+		ocontext_selinux_netif_to_cil,
+		ocontext_selinux_node_to_cil,
+		ocontext_selinux_fsuse_to_cil,
+		ocontext_selinux_node6_to_cil,
+	};
+	static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
+		ocontext_xen_isid_to_cil,
+		ocontext_xen_pirq_to_cil,
+		ocontext_xen_ioport_to_cil,
+		ocontext_xen_iomem_to_cil,
+		ocontext_xen_pcidevice_to_cil,
+		NULL,
+		NULL,
+	};
+
+	switch (pdb->target_platform) {
+	case SEPOL_TARGET_SELINUX:
+		ocon_funcs = ocon_selinux_funcs;
+		break;
+	case SEPOL_TARGET_XEN:
+		ocon_funcs = ocon_xen_funcs;
+		break;
+	default:
+		log_err("Unknown target platform: %i", pdb->target_platform);
+		rc = -1;
+		goto exit;
+	}
+
+	for (ocon = 0; ocon < OCON_NUM; ocon++) {
+		if (ocon_funcs[ocon] != NULL) {
+			rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int genfscon_to_cil(struct policydb *pdb)
+{
+	struct genfs *genfs;
+	struct ocontext *ocon;
+
+	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
+		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
+			cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
+			context_to_cil(pdb, &ocon->context[0]);
+			cil_printf(")\n");
+		}
+	}
+
+	return 0;
+}
+
+static int level_string_to_cil(char *levelstr)
+{
+	int rc = -1;
+	char *sens = NULL;
+	char *cats = NULL;
+	int matched;
+	char *saveptr = NULL;
+	char *token = NULL;
+	char *ranged = NULL;
+
+	matched = sscanf(levelstr, "%m[^:]:%ms", &sens, &cats);
+	if (matched < 1 || matched > 2) {
+		log_err("Invalid level: %s", levelstr);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_printf("(%s", sens);
+
+	if (matched == 2) {
+		cil_printf("(");
+		token = strtok_r(cats, ",", &saveptr);
+		while (token != NULL) {
+			ranged = strchr(token, '.');
+			if (ranged == NULL) {
+				cil_printf("%s ", token);
+			} else {
+				*ranged = '\0';
+				cil_printf("(range %s %s) ", token, ranged + 1);
+			}
+			token = strtok_r(NULL, ",", &saveptr);
+		}
+		cil_printf(")");
+	}
+
+	cil_printf(")");
+
+	rc = 0;
+exit:
+	free(sens);
+	free(cats);
+	return rc;
+}
+
+static int level_range_string_to_cil(char *levelrangestr)
+{
+	char *ranged = NULL;
+	char *low;
+	char *high;
+
+	ranged = strchr(levelrangestr, '-');
+	if (ranged == NULL) {
+		low = high = levelrangestr;
+	} else {
+		*ranged = '\0';
+		low = levelrangestr;
+		high = ranged + 1;
+	}
+
+	level_string_to_cil(low);
+	cil_printf(" ");
+	level_string_to_cil(high);
+
+	return 0;
+}
+
+static int context_string_to_cil(char *contextstr)
+{
+	int rc = -1;
+	int matched;
+	char *user = NULL;
+	char *role = NULL;
+	char *type = NULL;
+	char *level = NULL;
+
+	matched = sscanf(contextstr, "%m[^:]:%m[^:]:%m[^:]:%ms", &user, &role, &type, &level);
+	if (matched < 3 || matched > 4) {
+		log_err("Invalid context: %s", contextstr);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_printf("(%s %s %s (", user, role, type);
+
+	if (matched == 3) {
+		cil_printf(DEFAULT_LEVEL);
+		cil_printf(" ");
+		cil_printf(DEFAULT_LEVEL);
+	} else {
+		level_range_string_to_cil(level);
+	}
+
+	cil_printf("))");
+
+	rc = 0;
+
+exit:
+	free(user);
+	free(role);
+	free(type);
+	free(level);
+
+	return rc;
+}
+
+static int seusers_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	FILE *fp = NULL;
+	char *seusers = sepol_module_package_get_seusers(mod_pkg);
+	size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
+	size_t len = 0;
+	char *line = NULL;
+	ssize_t line_len = 0;
+	char *buf = NULL;
+
+	char *user = NULL;
+	char *seuser = NULL;
+	char *level = NULL;
+	int matched;
+
+	if (seusers_len == 0) {
+		return 0;
+	}
+
+	fp = fmemopen(seusers, seusers_len, "r");
+
+	while ((line_len = getline(&line, &len, fp)) != -1) {
+		buf = line;
+		buf[line_len - 1] = '\0';
+		while (*buf && isspace(buf[0])) {
+			buf++;
+		}
+		if (buf[0] == '#' || buf[0] == '\0') {
+			continue;
+		}
+
+		matched = sscanf(buf, "%m[^:]:%m[^:]:%ms", &user, &seuser, &level);
+
+		if (matched < 2 || matched > 3) {
+			log_err("Invalid seuser line: %s", line);
+			rc = -1;
+			goto exit;
+		}
+
+		if (!strcmp(user, "__default__")) {
+			cil_printf("(selinuxuserdefault %s (", seuser);
+		} else {
+			cil_printf("(selinuxuser %s %s (", user, seuser);
+		}
+
+		switch (matched) {
+		case 2:
+			cil_printf("systemlow systemlow");
+			break;
+		case 3:
+			level_range_string_to_cil(level);
+			break;
+		}
+
+		cil_printf("))\n");
+
+		free(user);
+		free(seuser);
+		free(level);
+		user = seuser = level = NULL;
+	}
+	if (ferror(fp)) {
+		cil_printf("Failed to read seusers\n");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	if (fp != NULL) {
+		fclose(fp);
+	}
+	free(line);
+	free(user);
+	free(seuser);
+	free(level);
+
+	return rc;
+}
+
+static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+	size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
+
+	if (netcons_len > 0) {
+		log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
+	}
+
+	return 0;
+}
+
+static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	char *userx = sepol_module_package_get_user_extra(mod_pkg);
+	size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
+	FILE *fp = NULL;
+	size_t len = 0;
+	char *line = NULL;
+	ssize_t line_len = 0;
+	int matched;
+	char *user = NULL;
+	char *prefix = NULL;
+
+	if (userx_len == 0) {
+		return 0;
+	}
+
+	fp = fmemopen(userx, userx_len, "r");
+
+	while ((line_len = getline(&line, &len, fp)) != -1) {
+		line[line_len - 1] = '\0';
+
+		matched = sscanf(line, "user %ms prefix %m[^;];", &user, &prefix);
+		if (matched != 2) {
+			rc = -1;
+			log_err("Invalid file context line: %s", line);
+			goto exit;
+		}
+
+		cil_println(0, "(userprefix %s %s)", user, prefix);
+		free(user);
+		free(prefix);
+		user = prefix = NULL;
+	}
+
+	if (ferror(fp)) {
+		cil_printf("Failed to read user_extra\n");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	if (fp != NULL) {
+		fclose(fp);
+	}
+	free(line);
+	free(user);
+	free(prefix);
+
+	return rc;
+}
+
+static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	char *fc = sepol_module_package_get_file_contexts(mod_pkg);
+	size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
+	FILE *fp = NULL;
+	size_t len = 0;
+	char *line = NULL;
+	char *buf = NULL;
+	ssize_t line_len = 0;
+	int matched;
+	char *regex = NULL;
+	char *mode = NULL;
+	char *context = NULL;
+	const char *cilmode;
+
+	if (fc_len == 0) {
+		return 0;
+	}
+
+	fp = fmemopen(fc, fc_len, "r");
+	while ((line_len = getline(&line, &len, fp)) != -1) {
+		buf = line;
+		if (buf[line_len - 1] == '\n') {
+			buf[line_len - 1] = '\0';
+		}
+		while (*buf && isspace(buf[0])) {
+			buf++;
+		}
+		if (buf[0] == '#' || buf[0] == '\0') {
+			continue;
+		}
+
+		matched = sscanf(buf, "%ms %ms %ms", &regex, &mode, &context);
+		if (matched < 2 || matched > 3) {
+			rc = -1;
+			log_err("Invalid file context line: %s", line);
+			goto exit;
+		}
+
+		if (matched == 2) {
+			context = mode;
+			mode = NULL;
+		}
+
+		if (mode == NULL) {
+			cilmode = "any";
+		} else if (!strcmp(mode, "--")) {
+			cilmode = "file";
+		} else if (!strcmp(mode, "-d")) {
+			cilmode = "dir";
+		} else if (!strcmp(mode, "-c")) {
+			cilmode = "char";
+		} else if (!strcmp(mode, "-b")) {
+			cilmode = "block";
+		} else if (!strcmp(mode, "-s")) {
+			cilmode = "socket";
+		} else if (!strcmp(mode, "-p")) {
+			cilmode = "pipe";
+		} else if (!strcmp(mode, "-l")) {
+			cilmode = "symlink";
+		} else {
+			rc = -1;
+			log_err("Invalid mode in file context line: %s", line);
+			goto exit;
+		}
+
+		cil_printf("(filecon \"%s\" %s ", regex, cilmode);
+
+		if (!strcmp(context, "<<none>>")) {
+			cil_printf("()");
+		} else {
+			context_string_to_cil(context);
+		}
+
+		cil_printf(")\n");
+
+		free(regex);
+		free(mode);
+		free(context);
+		regex = mode = context = NULL;
+	}
+
+	if (ferror(fp)) {
+		cil_printf("Failed to read user_extra\n");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	free(line);
+	free(regex);
+	free(mode);
+	free(context);
+	if (fp != NULL) {
+		fclose(fp);
+	}
+
+	return rc;
+}
+
+
+static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
+	NULL,	// commons, only stored in the global symtab, handled elsewhere
+	class_to_cil,
+	role_to_cil,
+	type_to_cil,
+	user_to_cil,
+	boolean_to_cil,
+	sens_to_cil,
+	cat_to_cil
+};
+
+static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
+{
+	struct type_datum *alias_datum;
+	char *alias_name;
+	struct list_node *curr;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+	struct list *alias_list = typealias_lists[decl->decl_id];
+	int rc = -1;
+
+	if (alias_list == NULL) {
+		return 0;
+	}
+
+	for (curr = alias_list->head; curr != NULL; curr = curr->next) {
+		alias_name = curr->data;
+		alias_datum = hashtab_search(pdb->p_types.table, alias_name);
+		if (alias_datum == NULL) {
+			rc = -1;
+			goto exit;
+		}
+
+		cil_println(indent, "(typealias %s)", alias_name);
+		cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct ebitmap map;
+	struct ebitmap_node *node;
+	unsigned int i;
+	char * key;
+	struct scope_datum *scope;
+	int sym;
+	void *datum;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+
+	for (sym = 0; sym < SYM_NUM; sym++) {
+		if (func_to_cil[sym] == NULL) {
+			continue;
+		}
+
+		map = decl->declared.scope[sym];
+		ebitmap_for_each_bit(&map, node, i) {
+			if (!ebitmap_get_bit(&map, i)) {
+				continue;
+			}
+			key = pdb->sym_val_to_name[sym][i];
+			datum = hashtab_search(pdb->symtab[sym].table, key);
+			if (datum == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			scope = hashtab_search(pdb->scope[sym].table, key);
+			if (scope == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_CATS) {
+			rc = cat_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_LEVELS) {
+			rc = sens_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		if (sym == SYM_CLASSES) {
+			rc = class_order_to_cil(indent, pdb, map);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct ebitmap map;
+	struct ebitmap_node *node;
+	unsigned int i;
+	unsigned int j;
+	char * key;
+	int sym;
+	void *datum;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+	struct scope_datum *scope_datum;
+
+	for (sym = 0; sym < SYM_NUM; sym++) {
+		if (func_to_cil[sym] == NULL) {
+			continue;
+		}
+
+		map = decl->required.scope[sym];
+		ebitmap_for_each_bit(&map, node, i) {
+			if (!ebitmap_get_bit(&map, i)) {
+				continue;
+			}
+			key = pdb->sym_val_to_name[sym][i];
+
+			scope_datum = hashtab_search(pdb->scope[sym].table, key);
+			for (j = 0; j < scope_datum->decl_ids_len; j++) {
+				if (scope_datum->decl_ids[j] == decl->decl_id) {
+					break;
+				}
+			}
+			if (j >= scope_datum->decl_ids_len) {
+				// Symbols required in the global scope are also in the
+				// required scope ebitmap of all avrule decls (i.e. required
+				// in all optionals). So we need to look at the scopes of each
+				// symbol in this avrule_decl to determine if it actually is
+				// required in this decl, or if it's just required in the
+				// global scope. If we got here, then this symbol is not
+				// actually required in this scope, so skip it.
+				continue;
+			}
+
+			datum = hashtab_search(pdb->symtab[sym].table, key);
+			if (datum == NULL) {
+				rc = -1;
+				goto exit;
+			}
+			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+
+static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
+{
+	int rc = -1;
+	struct map_args *args = arg;
+
+	rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
+{
+	int rc = -1;
+	struct map_args args;
+	args.pdb = pdb;
+	args.block = block;
+	args.decl_stack = decl_stack;
+	args.indent = indent;
+	struct avrule_decl *decl = stack_peek(decl_stack);
+
+	for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
+		rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
+{
+	// returns 1 if sup is a superset of sub, returns 0 otherwise
+
+	int rc = 0;
+
+	uint32_t i;
+	struct ebitmap sup_map;
+	struct ebitmap sub_map;
+	struct ebitmap res;
+
+	ebitmap_init(&res);
+
+	for (i = 0; i < SYM_NUM; i++) {
+		sup_map = sup->scope[i];
+		sub_map = sub->scope[i];
+
+		ebitmap_and(&res, &sup_map, &sub_map);
+		if (!ebitmap_cmp(&res, &sub_map)) {
+			goto exit;
+		}
+		ebitmap_destroy(&res);
+	}
+
+	if (sup->class_perms_len < sub->class_perms_len) {
+		goto exit;
+	}
+
+	for (i = 0; i < sub->class_perms_len; i++) {
+		sup_map = sup->class_perms_map[i];
+		sub_map = sub->class_perms_map[i];
+
+		ebitmap_and(&res, &sup_map, &sub_map);
+		if (!ebitmap_cmp(&res, &sub_map)) {
+			goto exit;
+		}
+		ebitmap_destroy(&res);
+	}
+
+	rc = 1;
+
+exit:
+
+	ebitmap_destroy(&res);
+	return rc;
+}
+
+static int blocks_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	struct avrule_block *block;
+	struct avrule_decl *decl;
+	struct avrule_decl *decl_tmp;
+	int indent = 0;
+	struct stack *stack;
+	struct list *attr_list;
+
+	rc = stack_init(&stack);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	for (block = pdb->global; block != NULL; block = block->next) {
+		rc = list_init(&attr_list);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		decl = block->branch_list;
+		if (decl == NULL) {
+			continue;
+		}
+
+		if (decl->next != NULL) {
+			log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
+		}
+
+		if (block->flags & AVRULE_OPTIONAL) {
+			while (stack->pos > 0) {
+				decl_tmp = stack_peek(stack);
+				if (is_scope_superset(&decl->required, &decl_tmp->required)) {
+					break;
+				}
+
+				stack_pop(stack);
+				indent--;
+				cil_println(indent, ")");
+			}
+
+			cil_println(indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
+			indent++;
+		}
+
+		stack_push(stack, decl);
+
+		if (stack->pos == 0) {
+			// type aliases and commons are only stored in the global symtab.
+			// However, to get scoping correct, we assume they are in the
+			// global block
+			struct map_args args;
+			args.pdb = pdb;
+			args.block = block;
+			args.decl_stack = stack;
+			args.indent = 0;
+			args.scope = SCOPE_DECL;
+
+			rc = hashtab_map(pdb->p_commons.table, common_to_cil, &args);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
+
+		rc = typealiases_to_cil(indent, pdb, block, stack);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = declared_scopes_to_cil(indent, pdb, block, stack);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = required_scopes_to_cil(indent, pdb, block, stack);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = additive_scopes_to_cil(indent, pdb, block, stack);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = cond_list_to_cil(indent, pdb, decl->cond_list);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		rc = cil_print_attr_list(indent, pdb, attr_list);
+		if (rc != 0) {
+			goto exit;
+		}
+		attr_list_destroy(&attr_list);
+	}
+
+	while (indent > 0) {
+		indent--;
+		cil_println(indent, ")");
+	}
+
+	rc = 0;
+
+exit:
+	stack_destroy(&stack);
+	attr_list_destroy(&attr_list);
+
+	return rc;
+}
+
+static int handle_unknown_to_cil(struct policydb *pdb)
+{
+	int rc = -1;
+	const char *hu;
+
+	switch (pdb->handle_unknown) {
+	case SEPOL_DENY_UNKNOWN:
+		hu = "deny";
+		break;
+	case SEPOL_REJECT_UNKNOWN:
+		hu = "reject";
+		break;
+	case SEPOL_ALLOW_UNKNOWN:
+		hu = "allow";
+		break;
+	default:
+		log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
+		rc = -1;
+		goto exit;
+	}
+
+	cil_println(0, "(handleunknown %s)", hu);
+
+	return 0;
+
+exit:
+	return rc;
+}
+
+static int generate_mls(struct policydb *pdb)
+{
+	const char *mls_str = pdb->mls ? "true" : "false";
+	cil_println(0, "(mls %s)", mls_str);
+
+	return 0;
+}
+
+static int generate_default_level(void)
+{
+	cil_println(0, "(sensitivity s0)");
+	cil_println(0, "(sensitivityorder (s0))");
+	cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
+
+	return 0;
+}
+
+static int generate_default_object(void)
+{
+	cil_println(0, "(role " DEFAULT_OBJECT ")");
+
+	return 0;
+}
+
+static int generate_gen_require_attribute(void)
+{
+	cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
+	cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
+
+	return 0;
+}
+
+static int fix_module_name(struct policydb *pdb)
+{
+	char *letter;
+	int rc = -1;
+
+	// The base module doesn't have its name set, but we use that for some
+	// autogenerated names, like optionals and attributes, to prevent naming
+	// collisions. However, they sometimes need to be fixed up.
+
+	// the base module isn't given a name, so just call it "base"
+	if (pdb->policy_type == POLICY_BASE) {
+		pdb->name = strdup("base");
+		if (pdb->name == NULL) {
+			log_err("Out of memory");
+			rc = -1;
+			goto exit;
+		}
+	}
+
+	// CIL is more restrictive in module names than checkmodule. Convert bad
+	// characters to underscores
+	for (letter = pdb->name; *letter != '\0'; letter++) {
+		if (isalnum(*letter)) {
+			continue;
+		}
+
+		*letter = '_';
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+int sepol_module_package_to_cil(FILE *fp, struct sepol_module_package *mod_pkg)
+{
+	int rc = -1;
+	struct sepol_policydb *pdb;
+
+	out_file = fp;
+
+	pdb = sepol_module_package_get_policy(mod_pkg);
+	if (pdb == NULL) {
+		log_err("Failed to get policydb");
+		rc = -1;
+		goto exit;
+	}
+
+	if (pdb->p.policy_type != SEPOL_POLICY_BASE &&
+		pdb->p.policy_type != SEPOL_POLICY_MOD) {
+		log_err("Policy pakcage is not a base or module");
+		rc = -1;
+		goto exit;
+	}
+
+	rc = fix_module_name(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	if (pdb->p.policy_type == SEPOL_POLICY_BASE && !pdb->p.mls) {
+		// If this is a base non-mls policy, we need to define a default level
+		// range that can be used for contexts by other non-mls modules, since
+		// CIL requires that all contexts have a range, even if they are
+		// ignored as in non-mls policies
+		rc = generate_default_level();
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	if (pdb->p.policy_type == SEPOL_POLICY_BASE) {
+		// object_r is implicit in checkmodule, but not with CIL, create it
+		// as part of base
+		rc = generate_default_object();
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// default attribute to be used to mimic gen_require in CIL
+		rc = generate_gen_require_attribute();
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// handle_unknown is used from only the base module
+		rc = handle_unknown_to_cil(&pdb->p);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		// mls is used from only the base module
+		rc = generate_mls(&pdb->p);
+		if (rc != 0) {
+			goto exit;
+		}
+	}
+
+	rc = role_list_create(pdb->p.p_roles.table);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = typealias_list_create(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = polcaps_to_cil(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = ocontexts_to_cil(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = genfscon_to_cil(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = seusers_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = netfilter_contexts_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = user_extra_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = file_contexts_to_cil(mod_pkg);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	// now print everything that is scoped
+	rc = blocks_to_cil(&pdb->p);
+	if (rc != 0) {
+		goto exit;
+	}
+
+	rc = 0;
+
+exit:
+	role_list_destroy();
+	typealias_list_destroy();
+
+	return rc;
+}
+
+static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
+{
+	int rc = -1;
+	char *d = NULL;
+	size_t d_len = 0;
+	size_t read_len = 0;
+	size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
+
+	d = malloc(max_len);
+	if (d == NULL) {
+		log_err("Out of memory");
+		rc = -1;
+		goto exit;
+	}
+
+	while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
+		d_len += read_len;
+		if (d_len == max_len) {
+			max_len *= 2;
+			d = realloc(d, max_len);
+			if (d == NULL) {
+				log_err("Out of memory");
+				rc = -1;
+				goto exit;
+			}
+		}
+	}
+
+	if (ferror(fp) != 0) {
+		log_err("Failed to read pp file");
+		rc = -1;
+		goto exit;
+	}
+
+	*data = d;
+	*data_len = d_len;
+
+	return 0;
+
+exit:
+	free(d);
+	return rc;
+}
+
+int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
+{
+	int rc = -1;
+	FILE *f = NULL;
+	struct sepol_policy_file *pf = NULL;
+	struct sepol_module_package *pkg = NULL;
+	char *data = NULL;
+	size_t data_len;
+	int fd;
+	struct stat sb;
+
+	rc = sepol_policy_file_create(&pf);
+	if (rc != 0) {
+		log_err("Failed to create policy file");
+		goto exit;
+	}
+
+	fd = fileno(fp);
+	if (fstat(fd, &sb) == -1) {
+		rc = -1;
+		goto exit;
+	}
+
+	if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
+		// libsepol fails when trying to read a policy package from a pipe or a
+		// socket due its use of lseek. In this case, read the data into a
+		// buffer and provide that to libsepol
+		rc = fp_to_buffer(fp, &data, &data_len);
+		if (rc != 0) {
+			goto exit;
+		}
+
+		sepol_policy_file_set_mem(pf, data, data_len);
+	} else {
+		sepol_policy_file_set_fp(pf, fp);
+	}
+
+	rc = sepol_module_package_create(&pkg);
+	if (rc != 0) {
+		log_err("Failed to create module package");
+		goto exit;
+	}
+
+	rc = sepol_module_package_read(pkg, pf, 0);
+	if (rc != 0) {
+		log_err("Failed to read policy package");
+		goto exit;
+	}
+
+	*mod_pkg = pkg;
+
+exit:
+	free(data);
+
+	sepol_policy_file_free(pf);
+	if (f != NULL) {
+		fclose(f);
+	}
+
+	if (rc != 0) {
+		sepol_module_package_free(pkg);
+	}
+
+	return rc;
+}
diff --git a/policycoreutils/hll/pp/Makefile b/policycoreutils/hll/pp/Makefile
index 81cf7a4..09168bc 100644
--- a/policycoreutils/hll/pp/Makefile
+++ b/policycoreutils/hll/pp/Makefile
@@ -9,7 +9,7 @@ HLLDIR ?= $(LIBEXECDIR)/selinux/hll
 
 CFLAGS ?= -Werror -Wall -W
 override CFLAGS += -I$(INCLUDEDIR)
-LDLIBS = $(LIBDIR)/libsepol.a -L$(LIBDIR)
+LDLIBS = -lsepol -L$(LIBDIR)
 
 PP_SRCS = $(wildcard *.c)
 PP_OBJS = $(patsubst %.c,%.o,$(PP_SRCS))
diff --git a/policycoreutils/hll/pp/pp.c b/policycoreutils/hll/pp/pp.c
index 60c493d..866734f 100644
--- a/policycoreutils/hll/pp/pp.c
+++ b/policycoreutils/hll/pp/pp.c
@@ -17,43 +17,19 @@
  * 02110-1301, USA.
  */
 
-#include <arpa/inet.h>
-#include <ctype.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <getopt.h>
 #include <libgen.h>
-#include <netinet/in.h>
 #include <signal.h>
 #include <stdarg.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
 #include <sepol/module.h>
-#include <sepol/policydb/conditional.h>
-#include <sepol/policydb/hashtab.h>
-#include <sepol/policydb/polcaps.h>
-#include <sepol/policydb/policydb.h>
-#include <sepol/policydb/services.h>
-#include <sepol/policydb/util.h>
-
-#ifdef __GNUC__
-#  define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
-#else
-#  define UNUSED(x) UNUSED_ ## x
-#endif
+#include <sepol/module_to_cil.h>
 
 char *progname;
-FILE *out_file;
-
-#define STACK_SIZE 16
-#define DEFAULT_LEVEL "systemlow"
-#define DEFAULT_OBJECT "object_r"
-#define GEN_REQUIRE_ATTR "cil_gen_require"
 
 __attribute__ ((format(printf, 1, 2)))
 static void log_err(const char *fmt, ...)
@@ -69,3805 +45,6 @@ static void log_err(const char *fmt, ...)
 	}
 }
 
-static void cil_indent(int indent)
-{
-	if (fprintf(out_file, "%*s", indent * 4, "") < 0) {
-		log_err("Failed to write to output");
-		_exit(EXIT_FAILURE);
-	}
-}
-
-__attribute__ ((format(printf, 1, 2)))
-static void cil_printf(const char *fmt, ...) {
-	va_list argptr;
-	va_start(argptr, fmt);
-	if (vfprintf(out_file, fmt, argptr) < 0) {
-		log_err("Failed to write to output");
-		_exit(EXIT_FAILURE);
-	}
-	va_end(argptr);
-}
-
-__attribute__ ((format(printf, 2, 3)))
-static void cil_println(int indent, const char *fmt, ...)
-{
-	cil_indent(indent);
-	va_list argptr;
-	va_start(argptr, fmt);
-	if (vfprintf(out_file, fmt, argptr) < 0) {
-		log_err("Failed to write to output");
-		_exit(EXIT_FAILURE);
-	}
-	va_end(argptr);
-	if (fprintf(out_file, "\n") < 0) {
-		log_err("Failed to write to output");
-		_exit(EXIT_FAILURE);
-	}
-}
-
-struct map_args {
-	struct policydb *pdb;
-	struct avrule_block *block;
-	struct stack *decl_stack;
-	int scope;
-	int indent;
-	int sym_index;
-};
-
-struct stack {
-	 void **stack;
-	 int pos;
-	 int size;
-};
-
-struct role_list_node {
-	char *role_name;
-	role_datum_t *role;
-};
-
-struct attr_list_node {
-	char *attribute;
-	int is_type;
-	union {
-		struct type_set *ts;
-		struct role_set *rs;
-	} set;
-};
-
-struct list_node {
-	void *data;
-	struct list_node *next;
-};
-
-struct list {
-	struct list_node *head;
-};
-
-/* A linked list of all roles stored in the pdb
- * which is iterated to determine types associated
- * with each role when printing role_type statements
- */
-static struct list *role_list;
-
-static void list_destroy(struct list **list)
-{
-	struct list_node *curr = (*list)->head;
-	struct list_node *tmp;
-
-	while (curr != NULL) {
-		tmp = curr->next;
-		free(curr);
-		curr = tmp;
-	}
-
-	free(*list);
-	*list = NULL;
-}
-
-static void role_list_destroy(void)
-{
-	struct list_node *curr = role_list->head;
-
-	while (curr != NULL) {
-		free(curr->data);
-		curr->data = NULL;
-		curr = curr->next;
-	}
-
-	list_destroy(&role_list);
-}
-
-static void attr_list_destroy(struct list **attr_list)
-{
-	if (attr_list == NULL || *attr_list == NULL) {
-		return;
-	}
-
-	struct list_node *curr = (*attr_list)->head;
-	struct attr_list_node *attr;
-
-	while (curr != NULL) {
-		attr = curr->data;
-		if (attr != NULL) {
-			free(attr->attribute);
-		}
-
-		free(curr->data);
-		curr->data = NULL;
-		curr = curr->next;
-	}
-
-	list_destroy(attr_list);
-}
-
-static int list_init(struct list **list)
-{
-	int rc = -1;
-	struct list *l = calloc(1, sizeof(*l));
-	if (l == NULL) {
-		goto exit;
-	}
-
-	*list = l;
-
-	return 0;
-
-exit:
-	list_destroy(&l);
-	return rc;
-}
-
-static int list_prepend(struct list *list, void *data)
-{
-	int rc = -1;
-	struct list_node *node = calloc(1, sizeof(*node));
-	if (node == NULL) {
-		goto exit;
-	}
-
-	node->data = data;
-	node->next = list->head;
-	list->head = node;
-
-	rc = 0;
-
-exit:
-	return rc;
-}
-
-static int roles_gather_map(char *key, void *data, void *args)
-{
-	struct role_list_node *role_node;
-	role_datum_t *role = data;
-	int rc = -1;
-
-	role_node = calloc(1, sizeof(*role_node));
-	if (role_node == NULL) {
-		return rc;
-	}
-
-	role_node->role_name = key;
-	role_node->role = role;
-
-	rc = list_prepend((struct list *)args, role_node);
-	return rc;
-}
-
-static int role_list_create(hashtab_t roles_tab)
-{
-	int rc = -1;
-
-	rc = list_init(&role_list);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = hashtab_map(roles_tab, roles_gather_map, role_list);
-
-exit:
-	return rc;
-}
-
-// array of lists, where each list contains all the aliases defined in the scope at index i
-static struct list **typealias_lists;
-static uint32_t typealias_lists_len;
-
-static int typealiases_gather_map(char *key, void *data, void *arg)
-{
-	int rc = -1;
-	struct type_datum *type = data;
-	struct policydb *pdb = arg;
-	struct scope_datum *scope;
-	uint32_t i;
-	uint32_t scope_id;
-
-	if (type->primary != 1) {
-		scope = hashtab_search(pdb->scope[SYM_TYPES].table, key);
-		if (scope == NULL) {
-			return -1;
-		}
-
-		for (i = 0; i < scope->decl_ids_len; i++) {
-			scope_id = scope->decl_ids[i];
-			if (typealias_lists[scope_id] == NULL) {
-				rc = list_init(&typealias_lists[scope_id]);
-				if (rc != 0) {
-					goto exit;
-				}
-			}
-			list_prepend(typealias_lists[scope_id], key);
-		}
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static void typealias_list_destroy(void)
-{
-	uint32_t i;
-	for (i = 0; i < typealias_lists_len; i++) {
-		if (typealias_lists[i] != NULL) {
-			list_destroy(&typealias_lists[i]);
-		}
-	}
-	typealias_lists_len = 0;
-	free(typealias_lists);
-	typealias_lists = NULL;
-}
-
-static int typealias_list_create(struct policydb *pdb)
-{
-	uint32_t max_decl_id = 0;
-	struct avrule_decl *decl;
-	struct avrule_block *block;
-	uint32_t rc = -1;
-
-	for (block = pdb->global; block != NULL; block = block->next) {
-		decl = block->branch_list;
-		if (decl->decl_id > max_decl_id) {
-			max_decl_id = decl->decl_id;
-		}
-	}
-
-	typealias_lists = calloc(max_decl_id + 1, sizeof(*typealias_lists));
-	typealias_lists_len = max_decl_id + 1;
-
-	rc = hashtab_map(pdb->p_types.table, typealiases_gather_map, pdb);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	return 0;
-
-exit:
-	typealias_list_destroy();
-
-	return rc;
-}
-
-
-static int stack_destroy(struct stack **stack)
-{
-	if (stack == NULL || *stack == NULL) {
-		return 0;
-	}
-
-	free((*stack)->stack);
-	free(*stack);
-	*stack = NULL;
-
-	return 0;
-}
-
-static int stack_init(struct stack **stack)
-{
-	int rc = -1;
-	struct stack *s = calloc(1, sizeof(*s));
-	if (s == NULL) {
-		goto exit;
-	}
-
-	s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
-	if (s->stack == NULL) {
-		goto exit;
-	}
-
-	s->pos = -1;
-	s->size = STACK_SIZE;
-
-	*stack = s;
-
-	return 0;
-
-exit:
-	stack_destroy(&s);
-	return rc;
-}
-
-static int stack_push(struct stack *stack, void *ptr)
-{
-	int rc = -1;
-	void *new_stack;
-
-	if (stack->pos + 1 == stack->size) {
-		new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
-		if (new_stack == NULL) {
-			goto exit;
-		}
-		stack->stack = new_stack;
-		stack->size *= 2;
-	}
-
-	stack->pos++;
-	stack->stack[stack->pos] = ptr;
-
-	rc = 0;
-exit:
-	return rc;
-}
-
-static void *stack_pop(struct stack *stack)
-{
-	if (stack->pos == -1) {
-		return NULL;
-	}
-
-	stack->pos--;
-	return stack->stack[stack->pos + 1];
-}
-
-static void *stack_peek(struct stack *stack)
-{
-	if (stack->pos == -1) {
-		return NULL;
-	}
-
-	return stack->stack[stack->pos];
-}
-
-static int is_id_in_scope_with_start(struct policydb *pdb, struct stack *decl_stack, int start, uint32_t symbol_type, char *id)
-{
-	int i;
-	uint32_t j;
-	struct avrule_decl *decl;
-	struct scope_datum *scope;
-
-	scope = hashtab_search(pdb->scope[symbol_type].table, id);
-	if (scope == NULL) {
-		return 0;
-	}
-
-	for (i = start; i >= 0; i--) {
-		decl = decl_stack->stack[i];
-
-		for (j = 0; j < scope->decl_ids_len; j++) {
-			if (scope->decl_ids[j] == decl->decl_id) {
-				return 1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int is_id_in_ancestor_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
-{
-	int start = decl_stack->pos - 1;
-
-	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
-}
-
-static int is_id_in_scope(struct policydb *pdb, struct stack *decl_stack, char *type, uint32_t symbol_type)
-{
-	int start = decl_stack->pos;
-
-	return is_id_in_scope_with_start(pdb, decl_stack, start, symbol_type, type);
-}
-
-static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct mls_semantic_level *level)
-{
-	struct mls_semantic_cat *cat;
-
-	cil_printf("(%s ", pdb->p_sens_val_to_name[level->sens - sens_offset]);
-
-	if (level->cat != NULL) {
-		cil_printf("(");
-	}
-
-	for (cat = level->cat; cat != NULL; cat = cat->next) {
-		if (cat->low == cat->high) {
-			cil_printf("%s", pdb->p_cat_val_to_name[cat->low - 1]);
-		} else {
-			cil_printf("range %s %s", pdb->p_cat_val_to_name[cat->low - 1], pdb->p_cat_val_to_name[cat->high - 1]);
-		}
-
-		if (cat->next != NULL) {
-			cil_printf(" ");
-		}
-	}
-
-	if (level->cat != NULL) {
-		cil_printf(")");
-	}
-
-	cil_printf(")");
-
-	return 0;
-}
-
-static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms)
-{
-	int rc = -1;
-	const char *rule;
-	const struct class_perm_node *classperm;
-	char *perms;
-
-	switch (type) {
-	case AVRULE_ALLOWED:
-		rule = "allow";
-		break;
-	case AVRULE_AUDITALLOW:
-		rule = "auditallow";
-		break;
-	case AVRULE_AUDITDENY:
-		rule = "auditdenty";
-		break;
-	case AVRULE_DONTAUDIT:
-		rule = "dontaudit";
-		break;
-	case AVRULE_NEVERALLOW:
-		rule = "neverallow";
-		break;
-	case AVRULE_TRANSITION:
-		rule = "typetransition";
-		break;
-	case AVRULE_MEMBER:
-		rule = "typemember";
-		break;
-	case AVRULE_CHANGE:
-		rule = "typechange";
-		break;
-	default:
-		log_err("Unknown avrule type: %i", type);
-		rc = -1;
-		goto exit;
-	}
-
-	for (classperm = classperms; classperm != NULL; classperm = classperm->next) {
-		if (type & AVRULE_AV) {
-			perms = sepol_av_to_string(pdb, classperm->tclass, classperm->data);
-			if (perms == NULL) {
-				log_err("Failed to generate permission string");
-				rc = -1;
-				goto exit;
-			}
-			cil_println(indent, "(%s %s %s (%s (%s)))",
-					rule, src, tgt,
-					pdb->p_class_val_to_name[classperm->tclass - 1],
-					perms + 1);
-		} else {
-			cil_println(indent, "(%s %s %s %s %s)",
-					rule, src, tgt,
-					pdb->p_class_val_to_name[classperm->tclass - 1],
-					pdb->p_type_val_to_name[classperm->data - 1]);
-		}
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int num_digits(int n)
-{
-	int num = 1;
-	while (n >= 10) {
-		n /= 10;
-		num++;
-	}
-	return num;
-}
-
-static int set_to_cil_attr(struct policydb *pdb, int is_type, char ***names, uint32_t *num_names)
-{
-	static unsigned int num_attrs = 0;
-	int rc = -1;
-	int len, rlen;
-	const char *attr_infix;
-	char *attr;
-
-	num_attrs++;
-
-	if (is_type) {
-		attr_infix = "_typeattr_";
-	} else {
-		attr_infix = "_roleattr_";
-	}
-
-	len = strlen(pdb->name) + strlen(attr_infix) + num_digits(num_attrs) + 1;
-	attr = malloc(len);
-	if (attr == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-	rlen = snprintf(attr, len, "%s%s%i", pdb->name, attr_infix, num_attrs);
-	if (rlen < 0 || rlen >= len) {
-		log_err("Failed to generate attribute name");
-		rc = -1;
-		goto exit;
-	}
-
-	*names = malloc(sizeof(**names));
-	if (*names == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-
-	*names[0] = attr;
-	*num_names = 1;
-
-	rc = 0;
-
-exit:
-	return rc;
-}
-
-static int cil_print_attr_strs(int indent, struct policydb *pdb, int is_type, struct ebitmap *pos, struct ebitmap *neg, uint32_t flags, char *attr)
-{
-	// CIL doesn't support anonymous positive/negative/complemented sets.  So
-	// instead we create a CIL type/roleattributeset that matches the set. If
-	// the set has a negative set, then convert it to is (P & !N), where P is
-	// the list of members in the positive set , and N is the list of members
-	// in the negative set. Additonally, if the set is complemented, then wrap
-	// the whole thing with a negation.
-
-	int rc = 0;
-	struct ebitmap_node *node;
-	unsigned int i;
-	char *statement;
-	int has_positive = pos && (ebitmap_cardinality(pos) > 0);
-	int has_negative = neg && (ebitmap_cardinality(neg) > 0);
-	char **val_to_name;
-
-	if (is_type) {
-		statement = "type";
-		val_to_name = pdb->p_type_val_to_name;
-	} else {
-		statement = "role";
-		val_to_name = pdb->p_role_val_to_name;
-	}
-
-	cil_println(indent, "(%sattribute %s)", statement, attr);
-	cil_indent(indent);
-	cil_printf("(%sattributeset %s ", statement, attr);
-
-	if (flags & TYPE_STAR) {
-		cil_printf("(all)");
-	}
-
-	if (flags & TYPE_COMP) {
-		cil_printf("(not ");
-	}
-
-	if (has_positive && has_negative) {
-		cil_printf("(and ");
-	}
-
-	if (has_positive) {
-		cil_printf("(");
-		ebitmap_for_each_bit(pos, node, i) {
-			if (!ebitmap_get_bit(pos, i)) {
-				continue;
-			}
-			cil_printf("%s ", val_to_name[i]);
-		}
-		cil_printf(") ");
-	}
-
-	if (has_negative) {
-		cil_printf("(not (");
-
-		ebitmap_for_each_bit(neg, node, i) {
-			if (!ebitmap_get_bit(neg, i)) {
-				continue;
-			}
-			cil_printf("%s ", val_to_name[i]);
-		}
-
-		cil_printf("))");
-	}
-
-	if (has_positive && has_negative) {
-		cil_printf(")");
-	}
-
-	if (flags & TYPE_COMP) {
-		cil_printf(")");
-	}
-
-	cil_printf(")\n");
-
-	return rc;
-}
-
-static int ebitmap_to_cil(struct policydb *pdb, struct ebitmap *map, int type)
-{
-	struct ebitmap_node *node;
-	uint32_t i;
-	char **val_to_name = pdb->sym_val_to_name[type];
-
-	ebitmap_for_each_bit(map, node, i) {
-		if (!ebitmap_get_bit(map, i)) {
-			continue;
-		}
-		cil_printf("%s ", val_to_name[i]);
-	}
-
-	return 0;
-}
-
-static int ebitmap_to_names(char** vals_to_names, struct ebitmap map, char ***names, uint32_t *num_names)
-{
-	int rc = -1;
-	struct ebitmap_node *node;
-	uint32_t i;
-	uint32_t num = 0;
-	uint32_t max = 8;
-	char **name_arr = NULL;
-
-	name_arr = malloc(sizeof(*name_arr) * max);
-	if (name_arr == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-	ebitmap_for_each_bit(&map, node, i) {
-		if (!ebitmap_get_bit(&map, i)) {
-			continue;
-		}
-
-		if (num + 1 == max) {
-			max *= 2;
-			name_arr = realloc(name_arr, sizeof(*name_arr) * max);
-			if (name_arr == NULL) {
-				log_err("Out of memory");
-				rc = -1;
-				goto exit;
-			}
-		}
-
-		name_arr[num] = strdup(vals_to_names[i]);
-		if (name_arr[num] == NULL) {
-			log_err("Out of memory");
-			rc = -1;
-			goto exit;
-		}
-		num++;
-	}
-
-	*names = name_arr;
-	*num_names = num;
-
-	return 0;
-
-exit:
-	for (i = 0; i < num; i++) {
-		free(name_arr[i]);
-	}
-	free(name_arr);
-	return rc;
-}
-
-static int cil_add_attr_to_list(struct list *attr_list, char *attribute, int is_type, void *set)
-{
-	struct attr_list_node *attr_list_node = NULL;
-	int rc = -1;
-
-	attr_list_node = calloc(1, sizeof(*attr_list_node));
-	if (attr_list_node == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-	rc = list_prepend(attr_list, attr_list_node);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	attr_list_node->attribute = strdup(attribute);
-	if (attr_list_node->attribute == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-	attr_list_node->is_type = is_type;
-	if (is_type) {
-		attr_list_node->set.ts = set;
-	} else {
-		attr_list_node->set.rs = set;
-	}
-
-	return rc;
-
-exit:
-	if (attr_list_node != NULL) {
-		free(attr_list_node->attribute);
-	}
-	free(attr_list_node);
-	return rc;
-}
-
-/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
-static int typeset_to_names(struct policydb *pdb, struct type_set *ts, char ***names, uint32_t *num_names, char **generated_attribute)
-{
-	int rc = -1;
-	if (ebitmap_cardinality(&ts->negset) > 0 || ts->flags != 0) {
-		rc = set_to_cil_attr(pdb, 1, names, num_names);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		*generated_attribute = *names[0];
-	} else {
-		rc = ebitmap_to_names(pdb->p_type_val_to_name, ts->types, names, num_names);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-/* generated_attribute is only set if a new attribute was generated in set_to_cil_attr */
-static int roleset_to_names(struct policydb *pdb, struct role_set *rs, char ***names, uint32_t *num_names, char **generated_attribute)
-{
-	int rc = -1;
-	if (rs->flags != 0) {
-		rc = set_to_cil_attr(pdb, 0, names, num_names);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		*generated_attribute = *names[0];
-	} else {
-		rc = ebitmap_to_names(pdb->p_role_val_to_name, rs->roles, names, num_names);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int process_roleset(int indent, struct policydb *pdb, struct role_set *rs, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
-{
-	int rc = -1;
-	char *generated_attribute = NULL;
-	*num_type_names = 0;
-
-	rc = roleset_to_names(pdb, rs, type_names, num_type_names, &generated_attribute);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	if (generated_attribute == NULL) {
-		goto exit;
-	}
-
-	if (attr_list == NULL) {
-		rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
-		if (rc != 0) {
-			goto exit;
-		}
-	} else {
-		rc = cil_add_attr_to_list(attr_list, generated_attribute, 0, rs);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-exit:
-	return rc;
-}
-
-static int process_typeset(int indent, struct policydb *pdb, struct type_set *ts, struct list *attr_list, char ***type_names, uint32_t *num_type_names)
-{
-	int rc = -1;
-	char *generated_attribute = NULL;
-	*num_type_names = 0;
-
-	rc = typeset_to_names(pdb, ts, type_names, num_type_names, &generated_attribute);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	if (generated_attribute == NULL) {
-		rc = 0;
-		goto exit;
-	}
-
-	if (attr_list == NULL) {
-		rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
-		if (rc != 0) {
-			goto exit;
-		}
-	} else {
-		rc = cil_add_attr_to_list(attr_list, generated_attribute, 1, ts);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-exit:
-	return rc;
-}
-
-static void names_destroy(char ***names, uint32_t *num_names)
-{
-	char **arr = *names;
-	uint32_t num = *num_names;
-	uint32_t i;
-
-	for (i = 0; i < num; i++) {
-		free(arr[i]);
-		arr[i] = NULL;
-	}
-	free(arr);
-
-	*names = NULL;
-	*num_names = 0;
-}
-
-static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *decl_stack, char *type_name, int indent)
-{
-	struct list_node *curr;
-	char **tnames = NULL;
-	uint32_t num_tnames, i;
-	struct role_list_node *role_node = NULL;
-	int rc;
-	struct type_set *ts;
-
-	curr = role_list->head;
-	for (curr = role_list->head; curr != NULL; curr = curr->next) {
-		role_node = curr->data;
-		if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
-			continue;
-		}
-
-		ts = &role_node->role->types;
-		rc = process_typeset(indent, pdb, ts, NULL, &tnames, &num_tnames);
-		if (rc != 0) {
-			goto exit;
-		}
-		for (i = 0; i < num_tnames; i++) {
-			if (!strcmp(type_name, tnames[i])) {
-				cil_println(indent, "(roletype %s %s)", role_node->role_name, type_name);
-			}
-		}
-		names_destroy(&tnames, &num_tnames);
-	}
-
-	rc = 0;
-
-exit:
-	return rc;
-}
-
-
-static int name_list_to_string(char **names, int num_names, char **string)
-{
-	// create a space separated string of the names
-	int rc = -1;
-	int len = 0;
-	int i;
-	char *str;
-	char *strpos;
-	int name_len;
-	int rlen;
-
-	for (i = 0; i < num_names; i++) {
-		len += strlen(names[i]);
-	}
-
-	// add spaces + null terminator
-	len += (num_names - 1) + 1;
-
-	str = malloc(len);
-	if (str == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-	strpos = str;
-
-	for (i = 0; i < num_names; i++) {
-		name_len = strlen(names[i]);
-		rlen = snprintf(strpos, len - (strpos - str), "%s", names[i]);
-		if (rlen < 0 || rlen >= len) {
-			log_err("Failed to generate name list");
-			rc = -1;
-			goto exit;
-		}
-
-		if (i < num_names - 1) {
-			strpos[name_len] = ' ';
-		}
-		strpos += name_len + 1;
-	}
-
-	*string = str;
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *avrule_list, struct list *attr_list)
-{
-	int rc = -1;
-	struct avrule *avrule;
-	char **snames = NULL;
-	char **tnames = NULL;
-	uint32_t num_snames;
-	uint32_t num_tnames;
-	uint32_t s;
-	uint32_t t;
-	struct type_set *ts;
-
-	for (avrule = avrule_list; avrule != NULL; avrule = avrule->next) {
-		ts = &avrule->stypes;
-		rc = process_typeset(indent, pdb, ts, attr_list, &snames, &num_snames);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		ts = &avrule->ttypes;
-		rc = process_typeset(indent, pdb, ts, attr_list, &tnames, &num_tnames);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (s = 0; s < num_snames; s++) {
-			for (t = 0; t < num_tnames; t++) {
-				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms);
-				if (rc != 0) {
-					goto exit;
-				}
-			}
-
-			if (avrule->flags & RULE_SELF) {
-				rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms);
-				if (rc != 0) {
-					goto exit;
-				}
-			}
-		}
-
-		names_destroy(&snames, &num_snames);
-		names_destroy(&tnames, &num_tnames);
-	}
-
-	return 0;
-
-exit:
-	names_destroy(&snames, &num_snames);
-	names_destroy(&tnames, &num_tnames);
-
-	return rc;
-}
-
-static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *cond_expr, uint32_t flags)
-{
-	int rc = -1;
-	struct cond_expr *curr;
-	struct stack *stack = NULL;
-	int len = 0;
-	int rlen;
-	char *new_val = NULL;
-	char *val1 = NULL;
-	char *val2 = NULL;
-	int num_params;
-	const char *op;
-	const char *fmt_str;
-	const char *type;
-
-	rc = stack_init(&stack);
-	if (rc != 0) {
-		log_err("Out of memory");
-		goto exit;
-	}
-
-	for (curr = cond_expr; curr != NULL; curr = curr->next) {
-		if (curr->expr_type == COND_BOOL) {
-			val1 = pdb->p_bool_val_to_name[curr->bool - 1];
-			// length of boolean + 2 parens + null terminator
-			len = strlen(val1) + 2 + 1;
-			new_val = malloc(len);
-			if (new_val == NULL) {
-				log_err("Out of memory");
-				rc = -1;
-				goto exit;
-			}
-			rlen = snprintf(new_val, len, "(%s)", val1);
-			if (rlen < 0 || rlen >= len) {
-				log_err("Failed to generate conditional expression");
-				rc = -1;
-				goto exit;
-			}
-			num_params = 0;
-		} else {
-			switch(curr->expr_type) {
-			case COND_NOT:	op = "not";	break;
-			case COND_OR:	op = "or";	break;
-			case COND_AND:	op = "and";	break;
-			case COND_XOR:	op = "xor";	break;
-			case COND_EQ:	op = "eq";	break;
-			case COND_NEQ:	op = "neq";	break;
-			default:
-				rc = -1;
-				goto exit;
-			}
-
-			num_params = curr->expr_type == COND_NOT ? 1 : 2;
-
-			if (num_params == 1) {
-				val1 = stack_pop(stack);
-				val2 = strdup("");
-				if (val2 == NULL) {
-					log_err("Out of memory");
-					rc = -1;
-					goto exit;
-				}
-				fmt_str = "(%s %s)";
-			} else {
-				val2 = stack_pop(stack);
-				val1 = stack_pop(stack);
-				fmt_str = "(%s %s %s)";
-			}
-
-			if (val1 == NULL || val2 == NULL) {
-				log_err("Invalid conditional expression");
-				rc = -1;
-				goto exit;
-			}
-
-			// length = length of parameters +
-			//          length of operator +
-			//          1 space preceeding each parameter +
-			//          2 parens around the whole expression
-			//          + null terminator
-			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
-			new_val = malloc(len);
-			if (new_val == NULL) {
-				log_err("Out of memory");
-				rc = -1;
-				goto exit;
-			}
-
-			// although we always supply val2 and there isn't always a 2nd
-			// value, it should only be used when there are actually two values
-			// in the format strings
-			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
-			if (rlen < 0 || rlen >= len) {
-				log_err("Failed to generate conditional expression");
-				rc = -1;
-				goto exit;
-			}
-
-			free(val1);
-			free(val2);
-			val1 = NULL;
-			val2 = NULL;
-		}
-
-		rc = stack_push(stack, new_val);
-		if (rc != 0) {
-			log_err("Out of memory");
-			goto exit;
-		}
-		new_val = NULL;
-	}
-
-	if (flags & COND_NODE_FLAGS_TUNABLE) {
-		type = "tunableif";
-	} else {
-		type = "booleanif";
-	}
-
-	val1 = stack_pop(stack);
-	if (val1 == NULL || stack_peek(stack) != NULL) {
-		log_err("Invalid conditional expression");
-		rc = -1;
-		goto exit;
-	}
-
-	cil_println(indent, "(%s %s", type, val1);
-	free(val1);
-	val1 = NULL;
-
-	rc = 0;
-
-exit:
-	free(new_val);
-	free(val1);
-	free(val2);
-	while ((val1 = stack_pop(stack)) != NULL) {
-		free(val1);
-	}
-	stack_destroy(&stack);
-
-	return rc;
-}
-
-static int cil_print_attr_list(int indent, struct policydb *pdb, struct list *attr_list)
-{
-	struct list_node *curr;
-	struct attr_list_node *attr_list_node;
-	int rc = 0;
-	struct type_set *ts;
-	struct role_set *rs;
-	char *generated_attribute;
-
-	for (curr = attr_list->head; curr != NULL; curr = curr->next) {
-		attr_list_node = curr->data;
-		generated_attribute = attr_list_node->attribute;
-		if (generated_attribute == NULL) {
-			return -1;
-		}
-
-		if (attr_list_node->is_type) {
-			ts = attr_list_node->set.ts;
-			rc = cil_print_attr_strs(indent, pdb, 1, &ts->types, &ts->negset, ts->flags, generated_attribute);
-			if (rc != 0) {
-				return rc;
-			}
-		} else {
-			rs = attr_list_node->set.rs;
-			rc = cil_print_attr_strs(indent, pdb, 0, &rs->roles, NULL, rs->flags, generated_attribute);
-			if (rc != 0) {
-				return rc;
-			}
-		}
-	}
-
-	return rc;
-}
-
-static int cond_list_to_cil(int indent, struct policydb *pdb, struct cond_node *cond_list)
-{
-	int rc = -1;
-	struct cond_node *cond;
-	struct list *attr_list;
-
-	rc = list_init(&attr_list);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	for (cond = cond_list; cond != NULL; cond = cond->next) {
-
-		rc = cond_expr_to_cil(indent, pdb, cond->expr, cond->flags);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		if (cond->avtrue_list != NULL) {
-			cil_println(indent + 1, "(true");
-			rc = avrule_list_to_cil(indent + 2, pdb, cond->avtrue_list, attr_list);
-			if (rc != 0) {
-				goto exit;
-			}
-			cil_println(indent + 1, ")");
-		}
-
-		if (cond->avfalse_list != NULL) {
-			cil_println(indent + 1, "(false");
-			rc = avrule_list_to_cil(indent + 2, pdb, cond->avfalse_list, attr_list);
-			if (rc != 0) {
-				goto exit;
-			}
-			cil_println(indent + 1, ")");
-		}
-
-		cil_println(indent, ")");
-	}
-
-	rc = cil_print_attr_list(indent, pdb, attr_list);
-
-exit:
-	attr_list_destroy(&attr_list);
-	return rc;
-}
-
-static int role_trans_to_cil(int indent, struct policydb *pdb, struct role_trans_rule *rules)
-{
-	int rc = -1;
-	struct role_trans_rule *rule;
-	char **role_names = NULL;
-	uint32_t num_role_names = 0;
-	char **type_names = NULL;
-	uint32_t num_type_names = 0;
-	uint32_t type;
-	uint32_t role;
-	uint32_t i;
-	struct ebitmap_node *node;
-	struct type_set *ts;
-	struct role_set *rs;
-
-
-	for (rule = rules; rule != NULL; rule = rule->next) {
-		rs = &rule->roles;
-		rc = process_roleset(indent, pdb, rs, NULL, &role_names, &num_role_names);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		ts = &rule->types;
-		rc = process_typeset(indent, pdb, ts, NULL, &type_names, &num_type_names);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (role = 0; role < num_role_names; role++) {
-			for (type = 0; type < num_type_names; type++) {
-				ebitmap_for_each_bit(&rule->classes, node, i) {
-					if (!ebitmap_get_bit(&rule->classes, i)) {
-						continue;
-					}
-					cil_println(indent, "(roletransition %s %s %s %s)", role_names[role],
-					                                                    type_names[type],
-					                                                    pdb->p_class_val_to_name[i],
-					                                                    pdb->p_role_val_to_name[rule->new_role - 1]);
-				}
-			}
-		}
-
-		names_destroy(&role_names, &num_role_names);
-		names_destroy(&type_names, &num_type_names);
-	}
-
-	rc = 0;
-
-exit:
-	names_destroy(&role_names, &num_role_names);
-	names_destroy(&type_names, &num_type_names);
-
-	return rc;
-}
-
-static int role_allows_to_cil(int indent, struct policydb *pdb, struct role_allow_rule *rules)
-{
-	int rc = -1;
-	struct role_allow_rule *rule;
-	char **roles = NULL;
-	uint32_t num_roles = 0;
-	char **new_roles = NULL;
-	uint32_t num_new_roles = 0;
-	uint32_t i;
-	uint32_t j;
-	struct role_set *rs;
-
-	for (rule = rules; rule != NULL; rule = rule->next) {
-		rs = &rule->roles;
-		rc = process_roleset(indent, pdb, rs, NULL, &roles, &num_roles);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rs = &rule->new_roles;
-		rc = process_roleset(indent, pdb, rs, NULL, &new_roles, &num_new_roles);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (i = 0; i < num_roles; i++) {
-			for (j = 0; j < num_new_roles; j++) {
-				cil_println(indent, "(roleallow %s %s)", roles[i], new_roles[j]);
-			}
-		}
-
-		names_destroy(&roles, &num_roles);
-		names_destroy(&new_roles, &num_new_roles);
-	}
-
-	rc = 0;
-
-exit:
-	names_destroy(&roles, &num_roles);
-	names_destroy(&new_roles, &num_new_roles);
-
-	return rc;
-}
-
-static int range_trans_to_cil(int indent, struct policydb *pdb, struct range_trans_rule *rules)
-{
-	int rc = -1;
-	struct range_trans_rule *rule;
-	char **stypes = NULL;
-	uint32_t num_stypes = 0;
-	char **ttypes = NULL;
-	uint32_t num_ttypes = 0;
-	struct ebitmap_node *node;
-	uint32_t i;
-	uint32_t stype;
-	uint32_t ttype;
-	struct type_set *ts;
-
-	if (!pdb->mls) {
-		return 0;
-	}
-
-	for (rule = rules; rule != NULL; rule = rule->next) {
-		ts = &rule->stypes;
-		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		ts = &rule->ttypes;
-		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (stype = 0; stype < num_stypes; stype++) {
-			for (ttype = 0; ttype < num_ttypes; ttype++) {
-				ebitmap_for_each_bit(&rule->tclasses, node, i) {
-					if (!ebitmap_get_bit(&rule->tclasses, i)) {
-						continue;
-					}
-
-					cil_indent(indent);
-					cil_printf("(rangetransition %s %s %s ", stypes[stype], ttypes[ttype], pdb->p_class_val_to_name[i]);
-
-					cil_printf("(");
-
-					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[0]);
-					if (rc != 0) {
-						goto exit;
-					}
-
-					cil_printf(" ");
-
-					rc = semantic_level_to_cil(pdb, 1, &rule->trange.level[1]);
-					if (rc != 0) {
-						goto exit;
-					}
-
-					cil_printf("))\n");
-				}
-
-			}
-		}
-
-		names_destroy(&stypes, &num_stypes);
-		names_destroy(&ttypes, &num_ttypes);
-	}
-
-	rc = 0;
-
-exit:
-	names_destroy(&stypes, &num_stypes);
-	names_destroy(&ttypes, &num_ttypes);
-
-	return rc;
-}
-
-static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules)
-{
-	int rc = -1;
-	char **stypes = NULL;
-	uint32_t num_stypes = 0;
-	char **ttypes = NULL;
-	uint32_t num_ttypes = 0;
-	uint32_t stype;
-	uint32_t ttype;
-	struct type_set *ts;
-
-	struct filename_trans_rule *rule;
-
-	for (rule = rules; rule != NULL; rule = rule->next) {
-		ts = &rule->stypes;
-		rc = process_typeset(indent, pdb, ts, NULL, &stypes, &num_stypes);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		ts = &rule->ttypes;
-		rc = process_typeset(indent, pdb, ts, NULL, &ttypes, &num_ttypes);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (stype = 0; stype < num_stypes; stype++) {
-			for (ttype = 0; ttype < num_ttypes; ttype++) {
-				cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", stypes[stype],
-				                                                       ttypes[ttype],
-				                                                       pdb->p_class_val_to_name[rule->tclass - 1],
-				                                                       rule->name,
-				                                                       pdb->p_type_val_to_name[rule->otype - 1]);
-			}
-		}
-
-		names_destroy(&stypes, &num_stypes);
-		names_destroy(&ttypes, &num_ttypes);
-	}
-
-	rc = 0;
-exit:
-	names_destroy(&stypes, &num_stypes);
-	names_destroy(&ttypes, &num_ttypes);
-
-	return rc;
-}
-
-struct class_perm_datum {
-	char *name;
-	uint32_t val;
-};
-
-struct class_perm_array {
-	struct class_perm_datum *perms;
-	uint32_t count;
-};
-
-static int class_perm_to_array(char *key, void *data, void *args)
-{
-	struct class_perm_array *arr = args;
-	struct perm_datum *datum = data;
-	arr->perms[arr->count].name = key;
-	arr->perms[arr->count].val = datum->s.value;
-	arr->count++;
-
-	return 0;
-}
-
-static int class_perm_cmp(const void *a, const void *b)
-{
-	const struct class_perm_datum *aa = a;
-	const struct class_perm_datum *bb = b;
-
-	return aa->val - bb->val;
-}
-
-static int common_to_cil(char *key, void *data, void *UNUSED(arg))
-{
-	int rc = -1;
-	struct common_datum *common = data;
-	struct class_perm_array arr;
-	uint32_t i;
-
-	arr.count = 0;
-	arr.perms = calloc(common->permissions.nprim, sizeof(*arr.perms));
-	rc = hashtab_map(common->permissions.table, class_perm_to_array, &arr);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
-
-	cil_printf("(common %s (", key);
-	for (i = 0; i < arr.count; i++) {
-		cil_printf("%s ", arr.perms[i].name);
-	}
-	cil_printf("))\n");
-
-	rc = 0;
-
-exit:
-	free(arr.perms);
-	return rc;
-}
-
-
-static int constraint_expr_to_string(int indent, struct policydb *pdb, struct constraint_expr *exprs, char **expr_string)
-{
-	int rc = -1;
-	struct constraint_expr *expr;
-	struct stack *stack = NULL;
-	int len = 0;
-	int rlen;
-	char *new_val = NULL;
-	char *val1 = NULL;
-	char *val2 = NULL;
-	uint32_t num_params;
-	const char *op;
-	const char *fmt_str;
-	const char *attr1;
-	const char *attr2;
-	char *names;
-	char **name_list = NULL;
-	uint32_t num_names = 0;
-	struct type_set *ts;
-
-	rc = stack_init(&stack);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	for (expr = exprs; expr != NULL; expr = expr->next) {
-		if (expr->expr_type == CEXPR_ATTR || expr->expr_type == CEXPR_NAMES) {
-			switch (expr->op) {
-			case CEXPR_EQ:      op = "eq";     break;
-			case CEXPR_NEQ:     op = "neq";    break;
-			case CEXPR_DOM:     op = "dom";    break;
-			case CEXPR_DOMBY:   op = "domby";  break;
-			case CEXPR_INCOMP:  op = "incomp"; break;
-			default:
-				log_err("Unknown constraint operator type: %i", expr->op);
-				rc = -1;
-				goto exit;
-			}
-
-			switch (expr->attr) {
-			case CEXPR_USER:                 attr1 = "u1"; attr2 = "u2"; break;
-			case CEXPR_USER | CEXPR_TARGET:  attr1 = "u2"; attr2 = "";   break;
-			case CEXPR_USER | CEXPR_XTARGET: attr1 = "u3"; attr2 = "";   break;
-			case CEXPR_ROLE:                 attr1 = "r1"; attr2 = "r2"; break;
-			case CEXPR_ROLE | CEXPR_TARGET:  attr1 = "r2"; attr2 = "";   break;
-			case CEXPR_ROLE | CEXPR_XTARGET: attr1 = "r3"; attr2 = "";   break;
-			case CEXPR_TYPE:                 attr1 = "t1"; attr2 = "";   break;
-			case CEXPR_TYPE | CEXPR_TARGET:  attr1 = "t2"; attr2 = "";   break;
-			case CEXPR_TYPE | CEXPR_XTARGET: attr1 = "t3"; attr2 = "";   break;
-			case CEXPR_L1L2:                 attr1 = "l1"; attr2 = "l2"; break;
-			case CEXPR_L1H2:                 attr1 = "l1"; attr2 = "h2"; break;
-			case CEXPR_H1L2:                 attr1 = "h1"; attr2 = "l2"; break;
-			case CEXPR_H1H2:                 attr1 = "h1"; attr2 = "h2"; break;
-			case CEXPR_L1H1:                 attr1 = "l1"; attr2 = "h1"; break;
-			case CEXPR_L2H2:                 attr1 = "l2"; attr2 = "h2"; break;
-			default:
-				log_err("Unknown expression attribute type: %i", expr->attr);
-				rc = -1;
-				goto exit;
-			}
-
-			if (expr->expr_type == CEXPR_ATTR) {
-				// length of values/attrs + 2 separating spaces + 2 parens + null terminator
-				len = strlen(op) + strlen(attr1) + strlen(attr2) + 2 + 2 + 1;
-				new_val = malloc(len);
-				if (new_val == NULL) {
-					log_err("Out of memory");
-					rc = -1;
-					goto exit;
-				}
-				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, attr2);
-				if (rlen < 0 || rlen >= len) {
-					log_err("Failed to generate constraint expression");
-					rc = -1;
-					goto exit;
-				}
-			} else {
-				if (expr->attr & CEXPR_TYPE) {
-					ts = expr->type_names;
-					rc = process_typeset(indent, pdb, ts, NULL, &name_list, &num_names);
-					if (rc != 0) {
-						goto exit;
-					}
-				} else if (expr->attr & CEXPR_USER) {
-					rc = ebitmap_to_names(pdb->p_user_val_to_name, expr->names, &name_list, &num_names);
-					if (rc != 0) {
-						goto exit;
-					}
-				} else if (expr->attr & CEXPR_ROLE) {
-					rc = ebitmap_to_names(pdb->p_role_val_to_name, expr->names, &name_list, &num_names);
-					if (rc != 0) {
-						goto exit;
-					}
-				}
-				rc = name_list_to_string(name_list, num_names, &names);
-				if (rc != 0) {
-					goto exit;
-				}
-
-				// length of values/oper + 2 spaces + 2 parens + null terminator
-				len = strlen(op) + strlen(attr1) +  strlen(names) + 2 + 2 + 1;
-				new_val = malloc(len);
-				if (new_val == NULL) {
-					log_err("Out of memory");
-					rc = -1;
-					goto exit;
-				}
-				rlen = snprintf(new_val, len, "(%s %s %s)", op, attr1, names);
-				if (rlen < 0 || rlen >= len) {
-					log_err("Failed to generate constraint expression");
-					rc = -1;
-					goto exit;
-				}
-
-				names_destroy(&name_list, &num_names);
-				free(names);
-			}
-
-			num_params = 0;
-		} else {
-			switch (expr->expr_type) {
-			case CEXPR_NOT: op = "not"; break;
-			case CEXPR_AND: op = "and"; break;
-			case CEXPR_OR:  op = "or"; break;
-			default:
-				log_err("Unknown constraint expression type: %i", expr->expr_type);
-				rc = -1;
-				goto exit;
-			}
-
-			num_params = expr->expr_type == CEXPR_NOT ? 1 : 2;
-
-			if (num_params == 1) {
-				val1 = stack_pop(stack);
-				val2 = strdup("");
-				if (val2 == NULL) {
-					log_err("Out of memory");
-					rc = -1;
-					goto exit;
-				}
-				fmt_str = "(%s %s)";
-			} else {
-				val2 = stack_pop(stack);
-				val1 = stack_pop(stack);
-				fmt_str = "(%s %s %s)";
-			}
-
-			if (val1 == NULL || val2 == NULL) {
-				log_err("Invalid constraint expression");
-				rc = -1;
-				goto exit;
-			}
-
-			// length = length of parameters +
-			//          length of operator +
-			//          1 space preceeding each parameter +
-			//          2 parens around the whole expression
-			//          + null terminator
-			len = strlen(val1) + strlen(val2) + strlen(op) + (num_params * 1) + 2 + 1;
-			new_val = malloc(len);
-			if (new_val == NULL) {
-				log_err("Out of memory");
-				rc = -1;
-				goto exit;
-			}
-
-			// although we always supply val2 and there isn't always a 2nd
-			// value, it should only be used when there are actually two values
-			// in the format strings
-			rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
-			if (rlen < 0 || rlen >= len) {
-				log_err("Failed to generate constraint expression");
-				rc = -1;
-				goto exit;
-			}
-
-			free(val1);
-			free(val2);
-			val1 = NULL;
-			val2 = NULL;
-		}
-
-		rc = stack_push(stack, new_val);
-		if (rc != 0) {
-			log_err("Out of memory");
-			goto exit;
-		}
-
-		new_val = NULL;
-	}
-
-	new_val = stack_pop(stack);
-	if (new_val == NULL || stack_peek(stack) != NULL) {
-		log_err("Invalid constraint expression");
-		rc = -1;
-		goto exit;
-	}
-
-	*expr_string = new_val;
-	new_val = NULL;
-
-	rc = 0;
-
-exit:
-	names_destroy(&name_list, &num_names);
-
-	free(new_val);
-	free(val1);
-	free(val2);
-	while ((val1 = stack_pop(stack)) != NULL) {
-		free(val1);
-	}
-	stack_destroy(&stack);
-
-	return rc;
-}
-
-
-static int constraints_to_cil(int indent, struct policydb *pdb, char *classkey, struct class_datum *class, struct constraint_node *constraints, int is_constraint)
-{
-	int rc = -1;
-	struct constraint_node *node;
-	char *expr = NULL;
-	const char *mls;
-	char *perms;
-
-	mls = pdb->mls ? "mls" : "";
-
-	for (node = constraints; node != NULL; node = node->next) {
-
-		rc = constraint_expr_to_string(indent, pdb, node->expr, &expr);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		if (is_constraint) {
-			perms = sepol_av_to_string(pdb, class->s.value, node->permissions);
-			cil_println(indent, "(%sconstrain (%s (%s)) %s)", mls, classkey, perms + 1, expr);
-		} else {
-			cil_println(indent, "(%svalidatetrans %s %s)", mls, classkey, expr);
-		}
-
-		free(expr);
-		expr = NULL;
-	}
-
-	rc = 0;
-
-exit:
-	free(expr);
-	return rc;
-}
-
-static int class_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
-	int rc = -1;
-	struct class_datum *class = datum;
-	const char *dflt;
-	struct class_perm_array arr;
-	uint32_t i;
-
-	if (scope == SCOPE_REQ) {
-		return 0;
-	}
-
-	arr.count = 0;
-	arr.perms = calloc(class->permissions.nprim, sizeof(*arr.perms));
-	rc = hashtab_map(class->permissions.table, class_perm_to_array, &arr);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	qsort(arr.perms, arr.count, sizeof(*arr.perms), class_perm_cmp);
-
-	cil_indent(indent);
-	cil_printf("(class %s (", key);
-	for (i = 0; i < arr.count; i++) {
-		cil_printf("%s ", arr.perms[i].name);
-	}
-	cil_printf("))\n");
-
-	if (class->comkey != NULL) {
-		cil_println(indent, "(classcommon %s %s)", key, class->comkey);
-	}
-
-	if (class->default_user != 0) {
-		switch (class->default_user) {
-		case DEFAULT_SOURCE:	dflt = "source";	break;
-		case DEFAULT_TARGET:	dflt = "target";	break;
-		default:
-			log_err("Unknown default user value: %i", class->default_user);
-			rc = -1;
-			goto exit;
-		}
-		cil_println(indent, "(defaultuser %s %s)", key, dflt);
-	}
-
-	if (class->default_role != 0) {
-		switch (class->default_role) {
-		case DEFAULT_SOURCE:	dflt = "source";	break;
-		case DEFAULT_TARGET:	dflt = "target";	break;
-		default:
-			log_err("Unknown default role value: %i", class->default_role);
-			rc = -1;
-			goto exit;
-		}
-		cil_println(indent, "(defaultrole %s %s)", key, dflt);
-	}
-
-	if (class->default_type != 0) {
-		switch (class->default_type) {
-		case DEFAULT_SOURCE:	dflt = "source";	break;
-		case DEFAULT_TARGET:	dflt = "target";	break;
-		default:
-			log_err("Unknown default type value: %i", class->default_type);
-			rc = -1;
-			goto exit;
-		}
-		cil_println(indent, "(defaulttype %s %s)", key, dflt);
-	}
-
-	if (class->default_range != 0) {
-		switch (class->default_range) {
-		case DEFAULT_SOURCE_LOW:		dflt = "source low";	break;
-		case DEFAULT_SOURCE_HIGH:		dflt = "source high";	break;
-		case DEFAULT_SOURCE_LOW_HIGH:	dflt = "source low-high";	break;
-		case DEFAULT_TARGET_LOW:		dflt = "target low";	break;
-		case DEFAULT_TARGET_HIGH:		dflt = "target high";	break;
-		case DEFAULT_TARGET_LOW_HIGH:	dflt = "target low-high";	break;
-		default:
-			log_err("Unknown default range value: %i", class->default_range);
-			rc = -1;
-			goto exit;
-		}
-		cil_println(indent, "(defaultrange %s %s)", key, dflt);
-
-	}
-
-	if (class->constraints != NULL) {
-		rc = constraints_to_cil(indent, pdb, key, class, class->constraints, 1);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	if (class->validatetrans != NULL) {
-		rc = constraints_to_cil(indent, pdb, key, class, class->validatetrans, 0);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	rc = 0;
-
-exit:
-	free(arr.perms);
-	return rc;
-}
-
-static int class_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
-	struct ebitmap_node *node;
-	uint32_t i;
-
-	if (ebitmap_cardinality(&order) == 0) {
-		return 0;
-	}
-
-	cil_indent(indent);
-	cil_printf("(classorder (");
-
-	ebitmap_for_each_bit(&order, node, i) {
-		if (!ebitmap_get_bit(&order, i)) {
-			continue;
-		}
-		cil_printf("%s ", pdb->sym_val_to_name[SYM_CLASSES][i]);
-	}
-
-	cil_printf("))\n");
-
-	return 0;
-}
-
-static int role_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
-{
-	int rc = -1;
-	struct ebitmap_node *node;
-	uint32_t i;
-	char **types = NULL;
-	uint32_t num_types = 0;
-	struct role_datum *role = datum;
-	struct type_set *ts;
-
-	if (scope == SCOPE_REQ) {
-		// if a role/roleattr is in the REQ scope, then it could cause an
-		// optional block to fail, even if it is never used. However in CIL,
-		// symbols must be used in order to cause an optional block to fail. So
-		// for symbols in the REQ scope, add them to a roleattribute as a way
-		// to 'use' them in the optional without affecting the resulting policy.
-		cil_println(indent, "(roleattributeset " GEN_REQUIRE_ATTR " %s)", key);
-	}
-
-	switch (role->flavor) {
-	case ROLE_ROLE:
-		if (scope == SCOPE_DECL) {
-			// Only declare certain roles if we are reading a base module.
-			// These roles are defined in the base module and sometimes in
-			// other non-base modules. If we generated the roles regardless of
-			// the policy type, it would result in duplicate declarations,
-			// which isn't allowed in CIL. Patches have been made to refpolicy
-			// to remove these duplicate role declarations, but we need to be
-			// backwards compatable and support older policies. Since we know
-			// these roles are always declared in base, only print them when we
-			// see them in the base module. If the declarations appear in a
-			// non-base module, ignore their declarations.
-			//
-			// Note that this is a hack, and if a policy author does not define
-			// one of these roles in base, the declaration will not appeaer in
-			// the resulting policy, likely resulting in a compilation error in
-			// CIL.
-			int is_base_role = (!strcmp(key, "user_r") ||
-			                    !strcmp(key, "staff_r") ||
-			                    !strcmp(key, "sysadm_r") ||
-			                    !strcmp(key, "system_r") ||
-			                    !strcmp(key, "unconfined_r"));
-			if ((is_base_role && pdb->policy_type == SEPOL_POLICY_BASE) || !is_base_role) {
-				cil_println(indent, "(role %s)", key);
-			}
-		}
-
-		if (ebitmap_cardinality(&role->dominates) > 1) {
-			log_err("Warning: role 'dominance' statement unsupported in CIL. Dropping from output.");
-		}
-
-		ts = &role->types;
-		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		for (i = 0; i < num_types; i++) {
-			if (is_id_in_scope(pdb, decl_stack, types[i], SYM_TYPES)) {
-				cil_println(indent, "(roletype %s %s)", key, types[i]);
-			}
-		}
-
-		if (role->bounds > 0) {
-			cil_println(indent, "(rolebounds %s %s)", key, pdb->p_role_val_to_name[role->bounds - 1]);
-		}
-		break;
-
-	case ROLE_ATTRIB:
-		if (scope == SCOPE_DECL) {
-			cil_println(indent, "(roleattribute %s)", key);
-		}
-
-		if (ebitmap_cardinality(&role->roles) > 0) {
-			cil_indent(indent);
-			cil_printf("(roleattributeset %s (", key);
-			ebitmap_for_each_bit(&role->roles, node, i) {
-				if (!ebitmap_get_bit(&role->roles, i)) {
-					continue;
-				}
-				cil_printf("%s ", pdb->p_role_val_to_name[i]);
-			}
-			cil_printf("))\n");
-		}
-
-		ts = &role->types;
-		rc = process_typeset(indent, pdb, ts, NULL, &types, &num_types);
-		if (rc != 0) {
-			goto exit;
-		}
-
-
-		for (i = 0; i < num_types; i++) {
-			cil_println(indent, "(roletype %s %s)", key, types[i]);
-		}
-
-		break;
-
-	default:
-		log_err("Unknown role type: %i", role->flavor);
-		rc = -1;
-		goto exit;
-	}
-
-	rc = 0;
-exit:
-	names_destroy(&types, &num_types);
-
-	return rc;
-}
-
-static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack, char *key, void *datum, int scope)
-{
-	int rc = -1;
-	struct type_datum *type = datum;
-
-	if (scope == SCOPE_REQ) {
-		// if a type/typeattr is in the REQ scope, then it could cause an
-		// optional block to fail, even if it is never used. However in CIL,
-		// symbols must be used in order to cause an optional block to fail. So
-		// for symbols in the REQ scope, add them to a typeattribute as a way
-		// to 'use' them in the optional without affecting the resulting policy.
-		cil_println(indent, "(typeattributeset " GEN_REQUIRE_ATTR " %s)", key);
-	}
-
-	rc = roletype_role_in_ancestor_to_cil(pdb, decl_stack, key, indent);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	switch(type->flavor) {
-	case TYPE_TYPE:
-		if (scope == SCOPE_DECL) {
-			cil_println(indent, "(type %s)", key);
-			// object_r is implicit in checkmodule, but not with CIL,
-			// create it as part of base
-			cil_println(indent, "(roletype " DEFAULT_OBJECT " %s)", key);
-		}
-
-		if (type->flags & TYPE_FLAGS_PERMISSIVE) {
-			cil_println(indent, "(typepermissive %s)", key);
-		}
-
-		if (type->bounds > 0) {
-			cil_println(indent, "(typebounds %s %s)", pdb->p_type_val_to_name[type->bounds - 1], key);
-		}
-		break;
-	case TYPE_ATTRIB:
-		if (scope == SCOPE_DECL) {
-			cil_println(indent, "(typeattribute %s)", key);
-		}
-
-		if (ebitmap_cardinality(&type->types) > 0) {
-			cil_indent(indent);
-			cil_printf("(typeattributeset %s (", key);
-			ebitmap_to_cil(pdb, &type->types, SYM_TYPES);
-			cil_printf("))\n");
-		}
-		break;
-	default:
-		log_err("Unknown flavor (%i) of type %s", type->flavor, key);
-		rc = -1;
-		goto exit;
-	}
-
-	rc = 0;
-
-exit:
-	return rc;
-}
-
-static int user_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
-{
-	struct user_datum *user = datum;
-	struct ebitmap roles = user->roles.roles;
-	struct mls_semantic_level level = user->dfltlevel;
-	struct mls_semantic_range range = user->range;
-	struct ebitmap_node *node;
-	uint32_t i;
-	int sens_offset = 1;
-
-	if (scope == SCOPE_DECL) {
-		cil_println(indent, "(user %s)", key);
-		// object_r is implicit in checkmodule, but not with CIL, create it
-		// as part of base
-		cil_println(indent, "(userrole %s " DEFAULT_OBJECT ")", key);
-	}
-
-	ebitmap_for_each_bit(&roles, node, i) {
-		if (!ebitmap_get_bit(&roles, i)) {
-			continue;
-		}
-		cil_println(indent, "(userrole %s %s)", key, pdb->p_role_val_to_name[i]);
-	}
-
-	if (block->flags & AVRULE_OPTIONAL) {
-		// sensitivites in user statements in optionals do not have the
-		// standard -1 offest
-		sens_offset = 0;
-	}
-
-	cil_indent(indent);
-	cil_printf("(userlevel %s ", key);
-	if (pdb->mls) {
-		semantic_level_to_cil(pdb, sens_offset, &level);
-	} else {
-		cil_printf(DEFAULT_LEVEL);
-	}
-	cil_printf(")\n");
-
-	cil_indent(indent);
-	cil_printf("(userrange %s (", key);
-	if (pdb->mls) {
-		semantic_level_to_cil(pdb, sens_offset, &range.level[0]);
-		cil_printf(" ");
-		semantic_level_to_cil(pdb, sens_offset, &range.level[1]);
-	} else {
-		cil_printf(DEFAULT_LEVEL " " DEFAULT_LEVEL);
-	}
-	cil_printf("))\n");
-
-
-	return 0;
-}
-
-static int boolean_to_cil(int indent, struct policydb *UNUSED(pdb), struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
-{
-	struct cond_bool_datum *boolean = datum;
-	const char *type;
-
-	if (scope == SCOPE_DECL) {
-		if (boolean->flags & COND_BOOL_FLAGS_TUNABLE) {
-			type = "tunable";
-		} else {
-			type = "boolean";
-		}
-
-		cil_println(indent, "(%s %s %s)", type, key, boolean->state ? "true" : "false");
-	}
-
-	return 0;
-}
-
-static int sens_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum, int scope)
-{
-	struct level_datum *level = datum;
-
-	if (scope == SCOPE_DECL) {
-		if (!level->isalias) {
-			cil_println(indent, "(sensitivity %s)", key);
-		} else {
-			cil_println(indent, "(sensitivityalias %s)", key);
-			cil_println(indent, "(sensitivityaliasactual %s %s)", key, pdb->p_sens_val_to_name[level->level->sens - 1]);
-		}
-	}
-
-	if (ebitmap_cardinality(&level->level->cat) > 0) {
-		cil_indent(indent);
-		cil_printf("(sensitivitycategory %s (", key);
-		ebitmap_to_cil(pdb, &level->level->cat, SYM_CATS);
-		cil_printf("))\n");
-	}
-
-	return 0;
-}
-
-static int sens_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
-	struct ebitmap_node *node;
-	uint32_t i;
-
-	if (ebitmap_cardinality(&order) == 0) {
-		return 0;
-	}
-
-	cil_indent(indent);
-	cil_printf("(sensitivityorder (");
-
-	ebitmap_for_each_bit(&order, node, i) {
-		if (!ebitmap_get_bit(&order, i)) {
-			continue;
-		}
-		cil_printf("%s ", pdb->p_sens_val_to_name[i]);
-	}
-
-	cil_printf("))\n");
-
-	return 0;
-}
-
-static int cat_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *UNUSED(decl_stack), char *key, void *datum,  int scope)
-{
-	struct cat_datum *cat = datum;
-
-	if (scope == SCOPE_REQ) {
-		return 0;
-	}
-
-	if (!cat->isalias) {
-		cil_println(indent, "(category %s)", key);
-	} else {
-		cil_println(indent, "(categoryalias %s)", key);
-		cil_println(indent, "(categoryaliasactual %s %s)", key, pdb->p_cat_val_to_name[cat->s.value - 1]);
-	}
-
-	return 0;
-}
-
-static int cat_order_to_cil(int indent, struct policydb *pdb, struct ebitmap order)
-{
-	int rc = -1;
-	struct ebitmap_node *node;
-	uint32_t i;
-
-	if (ebitmap_cardinality(&order) == 0) {
-		rc = 0;
-		goto exit;
-	}
-
-	cil_indent(indent);
-	cil_printf("(categoryorder (");
-
-	ebitmap_for_each_bit(&order, node, i) {
-		if (!ebitmap_get_bit(&order, i)) {
-			continue;
-		}
-		cil_printf("%s ", pdb->p_cat_val_to_name[i]);
-	}
-
-	cil_printf("))\n");
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int polcaps_to_cil(struct policydb *pdb)
-{
-	int rc = -1;
-	struct ebitmap *map;
-	struct ebitmap_node *node;
-	uint32_t i;
-	const char *name;
-
-	map = &pdb->policycaps;
-
-	ebitmap_for_each_bit(map, node, i) {
-		if (!ebitmap_get_bit(map, i)) {
-			continue;
-		}
-		name = sepol_polcap_getname(i);
-		if (name == NULL) {
-			log_err("Unknown policy capability id: %i", i);
-			rc = -1;
-			goto exit;
-		}
-
-		cil_println(0, "(policycap %s)", name);
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int level_to_cil(struct policydb *pdb, struct mls_level *level)
-{
-	struct ebitmap *map = &level->cat;
-
-	cil_printf("(%s", pdb->p_sens_val_to_name[level->sens - 1]);
-
-	if (ebitmap_cardinality(map) > 0) {
-		cil_printf("(");
-		ebitmap_to_cil(pdb, map, SYM_CATS);
-		cil_printf(")");
-	}
-
-	cil_printf(")");
-
-	return 0;
-}
-
-static int context_to_cil(struct policydb *pdb, struct context_struct *con)
-{
-	cil_printf("(%s %s %s (",
-		pdb->p_user_val_to_name[con->user - 1],
-		pdb->p_role_val_to_name[con->role - 1],
-		pdb->p_type_val_to_name[con->type - 1]);
-
-	if (pdb->mls) {
-		level_to_cil(pdb, &con->range.level[0]);
-		cil_printf(" ");
-		level_to_cil(pdb, &con->range.level[1]);
-	} else {
-		cil_printf(DEFAULT_LEVEL);
-		cil_printf(" ");
-		cil_printf(DEFAULT_LEVEL);
-	}
-
-	cil_printf("))");
-
-	return 0;
-}
-
-static int ocontext_isid_to_cil(struct policydb *pdb, const char **sid_to_string, struct ocontext *isids)
-{
-	int rc = -1;
-
-	struct ocontext *isid;
-
-	struct sid_item {
-		const char *sid_key;
-		struct sid_item *next;
-	};
-
-	struct sid_item *head = NULL;
-	struct sid_item *item = NULL;
-
-	for (isid = isids; isid != NULL; isid = isid->next) {
-		cil_println(0, "(sid %s)", sid_to_string[isid->sid[0]]);
-		cil_printf("(sidcontext %s ", sid_to_string[isid->sid[0]]);
-		context_to_cil(pdb, &isid->context[0]);
-		cil_printf(")\n");
-
-		// get the sid names in the correct order (reverse from the isids
-		// ocontext) for sidorder statement
-		item = malloc(sizeof(*item));
-		if (item == NULL) {
-			log_err("Out of memory");
-			rc = -1;
-			goto exit;
-		}
-		item->sid_key = sid_to_string[isid->sid[0]];
-		item->next = head;
-		head = item;
-	}
-
-	if (head != NULL) {
-		cil_printf("(sidorder (");
-		for (item = head; item != NULL; item = item->next) {
-			cil_printf("%s ", item->sid_key);
-		}
-		cil_printf("))\n");
-	}
-
-	rc = 0;
-
-exit:
-	while(head) {
-		item = head;
-		head = item->next;
-		free(item);
-	}
-	return rc;
-}
-
-static int ocontext_selinux_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
-{
-	int rc = -1;
-
-	// initial sid names aren't actually stored in the pp files, need to a have
-	// a mapping, taken from the linux kernel
-	static const char *selinux_sid_to_string[] = {
-		"null",
-		"kernel",
-		"security",
-		"unlabeled",
-		"fs",
-		"file",
-		"file_labels",
-		"init",
-		"any_socket",
-		"port",
-		"netif",
-		"netmsg",
-		"node",
-		"igmp_packet",
-		"icmp_socket",
-		"tcp_socket",
-		"sysctl_modprobe",
-		"sysctl",
-		"sysctl_fs",
-		"sysctl_kernel",
-		"sysctl_net",
-		"sysctl_net_unix",
-		"sysctl_vm",
-		"sysctl_dev",
-		"kmod",
-		"policy",
-		"scmp_packet",
-		"devnull",
-		NULL
-	};
-
-	rc = ocontext_isid_to_cil(pdb, selinux_sid_to_string, isids);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int ocontext_selinux_fs_to_cil(struct policydb *UNUSED(pdb), struct ocontext *fss)
-{
-	if (fss != NULL) {
-		log_err("Warning: 'fscon' statement unsupported in CIL. Dropping from output.");
-	}
-
-	return 0;
-}
-
-static int ocontext_selinux_port_to_cil(struct policydb *pdb, struct ocontext *portcons)
-{
-	int rc = -1;
-	struct ocontext *portcon;
-	const char *protocol;
-	uint16_t high;
-	uint16_t low;
-
-	for (portcon = portcons; portcon != NULL; portcon = portcon->next) {
-
-		switch (portcon->u.port.protocol) {
-		case IPPROTO_TCP: protocol = "tcp"; break;
-		case IPPROTO_UDP: protocol = "udp"; break;
-		default:
-			log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
-			rc = -1;
-			goto exit;
-		}
-
-		low = portcon->u.port.low_port;
-		high = portcon->u.port.high_port;
-
-		if (low == high) {
-			cil_printf("(portcon %s %i ", protocol, low);
-		} else {
-			cil_printf("(portcon %s (%i %i) ", protocol, low, high);
-		}
-
-		context_to_cil(pdb, &portcon->context[0]);
-
-		cil_printf(")\n");
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int ocontext_selinux_netif_to_cil(struct policydb *pdb, struct ocontext *netifs)
-{
-	struct ocontext *netif;
-
-	for (netif = netifs; netif != NULL; netif = netif->next) {
-		cil_printf("(netifcon %s ", netif->u.name);
-		context_to_cil(pdb, &netif->context[0]);
-
-		cil_printf(" ");
-		context_to_cil(pdb, &netif->context[1]);
-		cil_printf(")\n");
-	}
-
-	return 0;
-}
-
-static int ocontext_selinux_node_to_cil(struct policydb *pdb, struct ocontext *nodes)
-{
-	int rc = -1;
-	struct ocontext *node;
-	char addr[INET_ADDRSTRLEN];
-	char mask[INET_ADDRSTRLEN];
-
-	for (node = nodes; node != NULL; node = node->next) {
-		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
-			log_err("Nodecon address is invalid: %s", strerror(errno));
-			rc = -1;
-			goto exit;
-		}
-
-		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
-			log_err("Nodecon mask is invalid: %s", strerror(errno));
-			rc = -1;
-			goto exit;
-		}
-
-		cil_printf("(nodecon %s %s ", addr, mask);
-
-		context_to_cil(pdb, &node->context[0]);
-
-		cil_printf(")\n");
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int ocontext_selinux_node6_to_cil(struct policydb *pdb, struct ocontext *nodes)
-{
-	int rc = -1;
-	struct ocontext *node;
-	char addr[INET6_ADDRSTRLEN];
-	char mask[INET6_ADDRSTRLEN];
-
-	for (node = nodes; node != NULL; node = node->next) {
-		if (inet_ntop(AF_INET6, &node->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
-			log_err("Nodecon address is invalid: %s", strerror(errno));
-			rc = -1;
-			goto exit;
-		}
-
-		if (inet_ntop(AF_INET6, &node->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
-			log_err("Nodecon mask is invalid: %s", strerror(errno));
-			rc = -1;
-			goto exit;
-		}
-
-		cil_printf("(nodecon %s %s ", addr, mask);
-
-		context_to_cil(pdb, &node->context[0]);
-
-		cil_printf(")\n");
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-
-static int ocontext_selinux_fsuse_to_cil(struct policydb *pdb, struct ocontext *fsuses)
-{
-	int rc = -1;
-	struct ocontext *fsuse;
-	const char *behavior;
-
-
-	for (fsuse = fsuses; fsuse != NULL; fsuse = fsuse->next) {
-		switch (fsuse->v.behavior) {
-		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
-		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
-		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
-		default:
-			log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
-			rc = -1;
-			goto exit;
-		}
-
-		cil_printf("(fsuse %s %s ", behavior, fsuse->u.name);
-
-		context_to_cil(pdb, &fsuse->context[0]);
-
-		cil_printf(")\n");
-
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-
-static int ocontext_xen_isid_to_cil(struct policydb *pdb, struct ocontext *isids)
-{
-	int rc = -1;
-
-	// initial sid names aren't actually stored in the pp files, need to a have
-	// a mapping, taken from the xen kernel
-	static const char *xen_sid_to_string[] = {
-		"null",
-		"xen",
-		"dom0",
-		"domio",
-		"domxen",
-		"unlabeled",
-		"security",
-		"ioport",
-		"iomem",
-		"irq",
-		"device",
-		NULL,
-	};
-
-	rc = ocontext_isid_to_cil(pdb, xen_sid_to_string, isids);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int ocontext_xen_pirq_to_cil(struct policydb *pdb, struct ocontext *pirqs)
-{
-	struct ocontext *pirq;
-
-	for (pirq = pirqs; pirq != NULL; pirq = pirq->next) {
-		cil_printf("(pirqcon %i ", pirq->u.pirq);
-		context_to_cil(pdb, &pirq->context[0]);
-		cil_printf(")\n");
-	}
-
-	return 0;
-}
-
-static int ocontext_xen_ioport_to_cil(struct policydb *pdb, struct ocontext *ioports)
-{
-	struct ocontext *ioport;
-	uint32_t low;
-	uint32_t high;
-
-	for (ioport = ioports; ioport != NULL; ioport = ioport->next) {
-		low = ioport->u.ioport.low_ioport;
-		high = ioport->u.ioport.high_ioport;
-
-		if (low == high) {
-			cil_printf("(ioportcon %i ", low);
-		} else {
-			cil_printf("(ioportcon (%i %i) ", low, high);
-		}
-
-		context_to_cil(pdb, &ioport->context[0]);
-
-		cil_printf(")\n");
-	}
-
-	return 0;
-}
-
-static int ocontext_xen_iomem_to_cil(struct policydb *pdb, struct ocontext *iomems)
-{
-	struct ocontext *iomem;
-	uint64_t low;
-	uint64_t high;
-
-	for (iomem = iomems; iomem != NULL; iomem = iomem->next) {
-		low = iomem->u.iomem.low_iomem;
-		high = iomem->u.iomem.high_iomem;
-
-		if (low == high) {
-			cil_printf("(iomemcon %#lX ", (unsigned long)low);
-		} else {
-			cil_printf("(iomemcon (%#lX %#lX) ", (unsigned long)low, (unsigned long)high);
-		}
-
-		context_to_cil(pdb, &iomem->context[0]);
-
-		cil_printf(")\n");
-	}
-
-	return 0;
-}
-
-static int ocontext_xen_pcidevice_to_cil(struct policydb *pdb, struct ocontext *pcids)
-{
-	struct ocontext *pcid;
-
-	for (pcid = pcids; pcid != NULL; pcid = pcid->next) {
-		cil_printf("(pcidevicecon %#lx ", (unsigned long)pcid->u.device);
-		context_to_cil(pdb, &pcid->context[0]);
-		cil_printf(")\n");
-	}
-
-	return 0;
-}
-
-static int ocontexts_to_cil(struct policydb *pdb)
-{
-	int rc = -1;
-	int ocon;
-
-	static int (**ocon_funcs)(struct policydb *pdb, struct ocontext *ocon);
-	static int (*ocon_selinux_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
-		ocontext_selinux_isid_to_cil,
-		ocontext_selinux_fs_to_cil,
-		ocontext_selinux_port_to_cil,
-		ocontext_selinux_netif_to_cil,
-		ocontext_selinux_node_to_cil,
-		ocontext_selinux_fsuse_to_cil,
-		ocontext_selinux_node6_to_cil,
-	};
-	static int (*ocon_xen_funcs[OCON_NUM])(struct policydb *pdb, struct ocontext *ocon) = {
-		ocontext_xen_isid_to_cil,
-		ocontext_xen_pirq_to_cil,
-		ocontext_xen_ioport_to_cil,
-		ocontext_xen_iomem_to_cil,
-		ocontext_xen_pcidevice_to_cil,
-		NULL,
-		NULL,
-	};
-
-	switch (pdb->target_platform) {
-	case SEPOL_TARGET_SELINUX:
-		ocon_funcs = ocon_selinux_funcs;
-		break;
-	case SEPOL_TARGET_XEN:
-		ocon_funcs = ocon_xen_funcs;
-		break;
-	default:
-		log_err("Unknown target platform: %i", pdb->target_platform);
-		rc = -1;
-		goto exit;
-	}
-
-	for (ocon = 0; ocon < OCON_NUM; ocon++) {
-		if (ocon_funcs[ocon] != NULL) {
-			rc = ocon_funcs[ocon](pdb, pdb->ocontexts[ocon]);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int genfscon_to_cil(struct policydb *pdb)
-{
-	struct genfs *genfs;
-	struct ocontext *ocon;
-
-	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
-		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
-			cil_printf("(genfscon %s %s ", genfs->fstype, ocon->u.name);
-			context_to_cil(pdb, &ocon->context[0]);
-			cil_printf(")\n");
-		}
-	}
-
-	return 0;
-}
-
-static int level_string_to_cil(char *levelstr)
-{
-	int rc = -1;
-	char *sens = NULL;
-	char *cats = NULL;
-	int matched;
-	char *saveptr = NULL;
-	char *token = NULL;
-	char *ranged = NULL;
-
-	matched = sscanf(levelstr, "%m[^:]:%ms", &sens, &cats);
-	if (matched < 1 || matched > 2) {
-		log_err("Invalid level: %s", levelstr);
-		rc = -1;
-		goto exit;
-	}
-
-	cil_printf("(%s", sens);
-
-	if (matched == 2) {
-		cil_printf("(");
-		token = strtok_r(cats, ",", &saveptr);
-		while (token != NULL) {
-			ranged = strchr(token, '.');
-			if (ranged == NULL) {
-				cil_printf("%s ", token);
-			} else {
-				*ranged = '\0';
-				cil_printf("(range %s %s) ", token, ranged + 1);
-			}
-			token = strtok_r(NULL, ",", &saveptr);
-		}
-		cil_printf(")");
-	}
-
-	cil_printf(")");
-
-	rc = 0;
-exit:
-	free(sens);
-	free(cats);
-	return rc;
-}
-
-static int level_range_string_to_cil(char *levelrangestr)
-{
-	char *ranged = NULL;
-	char *low;
-	char *high;
-
-	ranged = strchr(levelrangestr, '-');
-	if (ranged == NULL) {
-		low = high = levelrangestr;
-	} else {
-		*ranged = '\0';
-		low = levelrangestr;
-		high = ranged + 1;
-	}
-
-	level_string_to_cil(low);
-	cil_printf(" ");
-	level_string_to_cil(high);
-
-	return 0;
-}
-
-static int context_string_to_cil(char *contextstr)
-{
-	int rc = -1;
-	int matched;
-	char *user = NULL;
-	char *role = NULL;
-	char *type = NULL;
-	char *level = NULL;
-
-	matched = sscanf(contextstr, "%m[^:]:%m[^:]:%m[^:]:%ms", &user, &role, &type, &level);
-	if (matched < 3 || matched > 4) {
-		log_err("Invalid context: %s", contextstr);
-		rc = -1;
-		goto exit;
-	}
-
-	cil_printf("(%s %s %s (", user, role, type);
-
-	if (matched == 3) {
-		cil_printf(DEFAULT_LEVEL);
-		cil_printf(" ");
-		cil_printf(DEFAULT_LEVEL);
-	} else {
-		level_range_string_to_cil(level);
-	}
-
-	cil_printf("))");
-
-	rc = 0;
-
-exit:
-	free(user);
-	free(role);
-	free(type);
-	free(level);
-
-	return rc;
-}
-
-static int seusers_to_cil(struct sepol_module_package *mod_pkg)
-{
-	int rc = -1;
-	FILE *fp = NULL;
-	char *seusers = sepol_module_package_get_seusers(mod_pkg);
-	size_t seusers_len = sepol_module_package_get_seusers_len(mod_pkg);
-	size_t len = 0;
-	char *line = NULL;
-	ssize_t line_len = 0;
-	char *buf = NULL;
-
-	char *user = NULL;
-	char *seuser = NULL;
-	char *level = NULL;
-	int matched;
-
-	if (seusers_len == 0) {
-		return 0;
-	}
-
-	fp = fmemopen(seusers, seusers_len, "r");
-
-	while ((line_len = getline(&line, &len, fp)) != -1) {
-		buf = line;
-		buf[line_len - 1] = '\0';
-		while (*buf && isspace(buf[0])) {
-			buf++;
-		}
-		if (buf[0] == '#' || buf[0] == '\0') {
-			continue;
-		}
-
-		matched = sscanf(buf, "%m[^:]:%m[^:]:%ms", &user, &seuser, &level);
-
-		if (matched < 2 || matched > 3) {
-			log_err("Invalid seuser line: %s", line);
-			rc = -1;
-			goto exit;
-		}
-
-		if (!strcmp(user, "__default__")) {
-			cil_printf("(selinuxuserdefault %s (", seuser);
-		} else {
-			cil_printf("(selinuxuser %s %s (", user, seuser);
-		}
-
-		switch (matched) {
-		case 2:
-			cil_printf("systemlow systemlow");
-			break;
-		case 3:
-			level_range_string_to_cil(level);
-			break;
-		}
-
-		cil_printf("))\n");
-
-		free(user);
-		free(seuser);
-		free(level);
-		user = seuser = level = NULL;
-	}
-	if (ferror(fp)) {
-		cil_printf("Failed to read seusers\n");
-		rc = -1;
-		goto exit;
-	}
-
-	rc = 0;
-
-exit:
-	if (fp != NULL) {
-		fclose(fp);
-	}
-	free(line);
-	free(user);
-	free(seuser);
-	free(level);
-
-	return rc;
-}
-
-static int netfilter_contexts_to_cil(struct sepol_module_package *mod_pkg)
-{
-	size_t netcons_len = sepol_module_package_get_netfilter_contexts_len(mod_pkg);
-
-	if (netcons_len > 0) {
-		log_err("Warning: netfilter_contexts are unsupported in CIL. Dropping from output.");
-	}
-
-	return 0;
-}
-
-static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
-{
-	int rc = -1;
-	char *userx = sepol_module_package_get_user_extra(mod_pkg);
-	size_t userx_len = sepol_module_package_get_user_extra_len(mod_pkg);
-	FILE *fp = NULL;
-	size_t len = 0;
-	char *line = NULL;
-	ssize_t line_len = 0;
-	int matched;
-	char *user = NULL;
-	char *prefix = NULL;
-
-	if (userx_len == 0) {
-		return 0;
-	}
-
-	fp = fmemopen(userx, userx_len, "r");
-
-	while ((line_len = getline(&line, &len, fp)) != -1) {
-		line[line_len - 1] = '\0';
-
-		matched = sscanf(line, "user %ms prefix %m[^;];", &user, &prefix);
-		if (matched != 2) {
-			rc = -1;
-			log_err("Invalid file context line: %s", line);
-			goto exit;
-		}
-
-		cil_println(0, "(userprefix %s %s)", user, prefix);
-		free(user);
-		free(prefix);
-		user = prefix = NULL;
-	}
-
-	if (ferror(fp)) {
-		cil_printf("Failed to read user_extra\n");
-		rc = -1;
-		goto exit;
-	}
-
-	rc = 0;
-exit:
-	if (fp != NULL) {
-		fclose(fp);
-	}
-	free(line);
-	free(user);
-	free(prefix);
-
-	return rc;
-}
-
-static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
-{
-	int rc = -1;
-	char *fc = sepol_module_package_get_file_contexts(mod_pkg);
-	size_t fc_len = sepol_module_package_get_file_contexts_len(mod_pkg);
-	FILE *fp = NULL;
-	size_t len = 0;
-	char *line = NULL;
-	char *buf = NULL;
-	ssize_t line_len = 0;
-	int matched;
-	char *regex = NULL;
-	char *mode = NULL;
-	char *context = NULL;
-	const char *cilmode;
-
-	if (fc_len == 0) {
-		return 0;
-	}
-
-	fp = fmemopen(fc, fc_len, "r");
-	while ((line_len = getline(&line, &len, fp)) != -1) {
-		buf = line;
-		if (buf[line_len - 1] == '\n') {
-			buf[line_len - 1] = '\0';
-		}
-		while (*buf && isspace(buf[0])) {
-			buf++;
-		}
-		if (buf[0] == '#' || buf[0] == '\0') {
-			continue;
-		}
-
-		matched = sscanf(buf, "%ms %ms %ms", &regex, &mode, &context);
-		if (matched < 2 || matched > 3) {
-			rc = -1;
-			log_err("Invalid file context line: %s", line);
-			goto exit;
-		}
-
-		if (matched == 2) {
-			context = mode;
-			mode = NULL;
-		}
-
-		if (mode == NULL) {
-			cilmode = "any";
-		} else if (!strcmp(mode, "--")) {
-			cilmode = "file";
-		} else if (!strcmp(mode, "-d")) {
-			cilmode = "dir";
-		} else if (!strcmp(mode, "-c")) {
-			cilmode = "char";
-		} else if (!strcmp(mode, "-b")) {
-			cilmode = "block";
-		} else if (!strcmp(mode, "-s")) {
-			cilmode = "socket";
-		} else if (!strcmp(mode, "-p")) {
-			cilmode = "pipe";
-		} else if (!strcmp(mode, "-l")) {
-			cilmode = "symlink";
-		} else {
-			rc = -1;
-			log_err("Invalid mode in file context line: %s", line);
-			goto exit;
-		}
-
-		cil_printf("(filecon \"%s\" %s ", regex, cilmode);
-
-		if (!strcmp(context, "<<none>>")) {
-			cil_printf("()");
-		} else {
-			context_string_to_cil(context);
-		}
-
-		cil_printf(")\n");
-
-		free(regex);
-		free(mode);
-		free(context);
-		regex = mode = context = NULL;
-	}
-
-	if (ferror(fp)) {
-		cil_printf("Failed to read user_extra\n");
-		rc = -1;
-		goto exit;
-	}
-
-	rc = 0;
-exit:
-	free(line);
-	free(regex);
-	free(mode);
-	free(context);
-	if (fp != NULL) {
-		fclose(fp);
-	}
-
-	return rc;
-}
-
-
-static int (*func_to_cil[SYM_NUM])(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack, char *key, void *datum, int scope) = {
-	NULL,	// commons, only stored in the global symtab, handled elsewhere
-	class_to_cil,
-	role_to_cil,
-	type_to_cil,
-	user_to_cil,
-	boolean_to_cil,
-	sens_to_cil,
-	cat_to_cil
-};
-
-static int typealiases_to_cil(int indent, struct policydb *pdb, struct avrule_block *UNUSED(block), struct stack *decl_stack)
-{
-	struct type_datum *alias_datum;
-	char *alias_name;
-	struct list_node *curr;
-	struct avrule_decl *decl = stack_peek(decl_stack);
-	struct list *alias_list = typealias_lists[decl->decl_id];
-	int rc = -1;
-
-	if (alias_list == NULL) {
-		return 0;
-	}
-
-	for (curr = alias_list->head; curr != NULL; curr = curr->next) {
-		alias_name = curr->data;
-		alias_datum = hashtab_search(pdb->p_types.table, alias_name);
-		if (alias_datum == NULL) {
-			rc = -1;
-			goto exit;
-		}
-
-		cil_println(indent, "(typealias %s)", alias_name);
-		cil_println(indent, "(typealiasactual %s %s)", alias_name, pdb->p_type_val_to_name[alias_datum->s.value - 1]);
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int declared_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
-	int rc = -1;
-	struct ebitmap map;
-	struct ebitmap_node *node;
-	unsigned int i;
-	char * key;
-	struct scope_datum *scope;
-	int sym;
-	void *datum;
-	struct avrule_decl *decl = stack_peek(decl_stack);
-
-	for (sym = 0; sym < SYM_NUM; sym++) {
-		if (func_to_cil[sym] == NULL) {
-			continue;
-		}
-
-		map = decl->declared.scope[sym];
-		ebitmap_for_each_bit(&map, node, i) {
-			if (!ebitmap_get_bit(&map, i)) {
-				continue;
-			}
-			key = pdb->sym_val_to_name[sym][i];
-			datum = hashtab_search(pdb->symtab[sym].table, key);
-			if (datum == NULL) {
-				rc = -1;
-				goto exit;
-			}
-			scope = hashtab_search(pdb->scope[sym].table, key);
-			if (scope == NULL) {
-				rc = -1;
-				goto exit;
-			}
-			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, scope->scope);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-
-		if (sym == SYM_CATS) {
-			rc = cat_order_to_cil(indent, pdb, map);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-
-		if (sym == SYM_LEVELS) {
-			rc = sens_order_to_cil(indent, pdb, map);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-
-		if (sym == SYM_CLASSES) {
-			rc = class_order_to_cil(indent, pdb, map);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int required_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
-	int rc = -1;
-	struct ebitmap map;
-	struct ebitmap_node *node;
-	unsigned int i;
-	unsigned int j;
-	char * key;
-	int sym;
-	void *datum;
-	struct avrule_decl *decl = stack_peek(decl_stack);
-	struct scope_datum *scope_datum;
-
-	for (sym = 0; sym < SYM_NUM; sym++) {
-		if (func_to_cil[sym] == NULL) {
-			continue;
-		}
-
-		map = decl->required.scope[sym];
-		ebitmap_for_each_bit(&map, node, i) {
-			if (!ebitmap_get_bit(&map, i)) {
-				continue;
-			}
-			key = pdb->sym_val_to_name[sym][i];
-
-			scope_datum = hashtab_search(pdb->scope[sym].table, key);
-			for (j = 0; j < scope_datum->decl_ids_len; j++) {
-				if (scope_datum->decl_ids[j] == decl->decl_id) {
-					break;
-				}
-			}
-			if (j >= scope_datum->decl_ids_len) {
-				// Symbols required in the global scope are also in the
-				// required scope ebitmap of all avrule decls (i.e. required
-				// in all optionals). So we need to look at the scopes of each
-				// symbol in this avrule_decl to determine if it actually is
-				// required in this decl, or if it's just required in the
-				// global scope. If we got here, then this symbol is not
-				// actually required in this scope, so skip it.
-				continue;
-			}
-
-			datum = hashtab_search(pdb->symtab[sym].table, key);
-			if (datum == NULL) {
-				rc = -1;
-				goto exit;
-			}
-			rc = func_to_cil[sym](indent, pdb, block, decl_stack, key, datum, SCOPE_REQ);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-
-static int additive_scopes_to_cil_map(char *key, void *data, void *arg)
-{
-	int rc = -1;
-	struct map_args *args = arg;
-
-	rc = func_to_cil[args->sym_index](args->indent, args->pdb, args->block, args->decl_stack, key, data, SCOPE_REQ);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int additive_scopes_to_cil(int indent, struct policydb *pdb, struct avrule_block *block, struct stack *decl_stack)
-{
-	int rc = -1;
-	struct map_args args;
-	args.pdb = pdb;
-	args.block = block;
-	args.decl_stack = decl_stack;
-	args.indent = indent;
-	struct avrule_decl *decl = stack_peek(decl_stack);
-
-	for (args.sym_index = 0; args.sym_index < SYM_NUM; args.sym_index++) {
-		rc = hashtab_map(decl->symtab[args.sym_index].table, additive_scopes_to_cil_map, &args);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int is_scope_superset(struct scope_index *sup, struct scope_index *sub)
-{
-	// returns 1 if sup is a superset of sub, returns 0 otherwise
-
-	int rc = 0;
-
-	uint32_t i;
-	struct ebitmap sup_map;
-	struct ebitmap sub_map;
-	struct ebitmap res;
-
-	ebitmap_init(&res);
-
-	for (i = 0; i < SYM_NUM; i++) {
-		sup_map = sup->scope[i];
-		sub_map = sub->scope[i];
-
-		ebitmap_and(&res, &sup_map, &sub_map);
-		if (!ebitmap_cmp(&res, &sub_map)) {
-			goto exit;
-		}
-		ebitmap_destroy(&res);
-	}
-
-	if (sup->class_perms_len < sub->class_perms_len) {
-		goto exit;
-	}
-
-	for (i = 0; i < sub->class_perms_len; i++) {
-		sup_map = sup->class_perms_map[i];
-		sub_map = sub->class_perms_map[i];
-
-		ebitmap_and(&res, &sup_map, &sub_map);
-		if (!ebitmap_cmp(&res, &sub_map)) {
-			goto exit;
-		}
-		ebitmap_destroy(&res);
-	}
-
-	rc = 1;
-
-exit:
-
-	ebitmap_destroy(&res);
-	return rc;
-}
-
-static int blocks_to_cil(struct policydb *pdb)
-{
-	int rc = -1;
-	struct avrule_block *block;
-	struct avrule_decl *decl;
-	struct avrule_decl *decl_tmp;
-	int indent = 0;
-	struct stack *stack;
-	struct list *attr_list;
-
-	rc = stack_init(&stack);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	for (block = pdb->global; block != NULL; block = block->next) {
-		rc = list_init(&attr_list);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		decl = block->branch_list;
-		if (decl == NULL) {
-			continue;
-		}
-
-		if (decl->next != NULL) {
-			log_err("Warning: 'else' blocks in optional statements are unsupported in CIL. Dropping from output.");
-		}
-
-		if (block->flags & AVRULE_OPTIONAL) {
-			while (stack->pos > 0) {
-				decl_tmp = stack_peek(stack);
-				if (is_scope_superset(&decl->required, &decl_tmp->required)) {
-					break;
-				}
-
-				stack_pop(stack);
-				indent--;
-				cil_println(indent, ")");
-			}
-
-			cil_println(indent, "(optional %s_optional_%i", pdb->name, decl->decl_id);
-			indent++;
-		}
-
-		stack_push(stack, decl);
-
-		if (stack->pos == 0) {
-			// type aliases and commons are only stored in the global symtab.
-			// However, to get scoping correct, we assume they are in the
-			// global block
-			struct map_args args;
-			args.pdb = pdb;
-			args.block = block;
-			args.decl_stack = stack;
-			args.indent = 0;
-			args.scope = SCOPE_DECL;
-
-			rc = hashtab_map(pdb->p_commons.table, common_to_cil, &args);
-			if (rc != 0) {
-				goto exit;
-			}
-		}
-
-		rc = typealiases_to_cil(indent, pdb, block, stack);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = declared_scopes_to_cil(indent, pdb, block, stack);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = required_scopes_to_cil(indent, pdb, block, stack);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = additive_scopes_to_cil(indent, pdb, block, stack);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = avrule_list_to_cil(indent, pdb, decl->avrules, attr_list);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = role_trans_to_cil(indent, pdb, decl->role_tr_rules);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = role_allows_to_cil(indent, pdb, decl->role_allow_rules);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = range_trans_to_cil(indent, pdb, decl->range_tr_rules);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = cond_list_to_cil(indent, pdb, decl->cond_list);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		rc = cil_print_attr_list(indent, pdb, attr_list);
-		if (rc != 0) {
-			goto exit;
-		}
-		attr_list_destroy(&attr_list);
-	}
-
-	while (indent > 0) {
-		indent--;
-		cil_println(indent, ")");
-	}
-
-	rc = 0;
-
-exit:
-	stack_destroy(&stack);
-	attr_list_destroy(&attr_list);
-
-	return rc;
-}
-
-static int handle_unknown_to_cil(struct policydb *pdb)
-{
-	int rc = -1;
-	const char *hu;
-
-	switch (pdb->handle_unknown) {
-	case SEPOL_DENY_UNKNOWN:
-		hu = "deny";
-		break;
-	case SEPOL_REJECT_UNKNOWN:
-		hu = "reject";
-		break;
-	case SEPOL_ALLOW_UNKNOWN:
-		hu = "allow";
-		break;
-	default:
-		log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
-		rc = -1;
-		goto exit;
-	}
-
-	cil_println(0, "(handleunknown %s)", hu);
-
-	return 0;
-
-exit:
-	return rc;
-}
-
-static int generate_mls(struct policydb *pdb)
-{
-	const char *mls_str = pdb->mls ? "true" : "false";
-	cil_println(0, "(mls %s)", mls_str);
-
-	return 0;
-}
-
-static int generate_default_level(void)
-{
-	cil_println(0, "(sensitivity s0)");
-	cil_println(0, "(sensitivityorder (s0))");
-	cil_println(0, "(level " DEFAULT_LEVEL " (s0))");
-
-	return 0;
-}
-
-static int generate_default_object(void)
-{
-	cil_println(0, "(role " DEFAULT_OBJECT ")");
-
-	return 0;
-}
-
-static int generate_gen_require_attribute(void)
-{
-	cil_println(0, "(typeattribute " GEN_REQUIRE_ATTR ")");
-	cil_println(0, "(roleattribute " GEN_REQUIRE_ATTR ")");
-
-	return 0;
-}
-
-static int fix_module_name(struct policydb *pdb)
-{
-	char *letter;
-	int rc = -1;
-
-	// The base module doesn't have its name set, but we use that for some
-	// autogenerated names, like optionals and attributes, to prevent naming
-	// collisions. However, they sometimes need to be fixed up.
-
-	// the base module isn't given a name, so just call it "base"
-	if (pdb->policy_type == POLICY_BASE) {
-		pdb->name = strdup("base");
-		if (pdb->name == NULL) {
-			log_err("Out of memory");
-			rc = -1;
-			goto exit;
-		}
-	}
-
-	// CIL is more restrictive in module names than checkmodule. Convert bad
-	// characters to underscores
-	for (letter = pdb->name; *letter != '\0'; letter++) {
-		if (isalnum(*letter)) {
-			continue;
-		}
-
-		*letter = '_';
-	}
-
-	return 0;
-exit:
-	return rc;
-}
-
-static int module_package_to_cil(struct sepol_module_package *mod_pkg)
-{
-	int rc = -1;
-	struct sepol_policydb *pdb;
-
-	pdb = sepol_module_package_get_policy(mod_pkg);
-	if (pdb == NULL) {
-		log_err("Failed to get policydb");
-		rc = -1;
-		goto exit;
-	}
-
-	if (pdb->p.policy_type != SEPOL_POLICY_BASE &&
-		pdb->p.policy_type != SEPOL_POLICY_MOD) {
-		log_err("Policy pakcage is not a base or module");
-		rc = -1;
-		goto exit;
-	}
-
-	rc = fix_module_name(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	if (pdb->p.policy_type == SEPOL_POLICY_BASE && !pdb->p.mls) {
-		// If this is a base non-mls policy, we need to define a default level
-		// range that can be used for contexts by other non-mls modules, since
-		// CIL requires that all contexts have a range, even if they are
-		// ignored as in non-mls policies
-		rc = generate_default_level();
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	if (pdb->p.policy_type == SEPOL_POLICY_BASE) {
-		// object_r is implicit in checkmodule, but not with CIL, create it
-		// as part of base
-		rc = generate_default_object();
-		if (rc != 0) {
-			goto exit;
-		}
-
-		// default attribute to be used to mimic gen_require in CIL
-		rc = generate_gen_require_attribute();
-		if (rc != 0) {
-			goto exit;
-		}
-
-		// handle_unknown is used from only the base module
-		rc = handle_unknown_to_cil(&pdb->p);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		// mls is used from only the base module	
-		rc = generate_mls(&pdb->p);
-		if (rc != 0) {
-			goto exit;
-		}
-	}
-
-	rc = role_list_create(pdb->p.p_roles.table);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = typealias_list_create(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = polcaps_to_cil(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = ocontexts_to_cil(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = genfscon_to_cil(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = seusers_to_cil(mod_pkg);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = netfilter_contexts_to_cil(mod_pkg);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = user_extra_to_cil(mod_pkg);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = file_contexts_to_cil(mod_pkg);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	// now print everything that is scoped
-	rc = blocks_to_cil(&pdb->p);
-	if (rc != 0) {
-		goto exit;
-	}
-
-	rc = 0;
-
-exit:
-	role_list_destroy();
-	typealias_list_destroy();
-
-	return rc;
-}
-
-static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
-{
-	int rc = -1;
-	char *d = NULL;
-	size_t d_len = 0;
-	size_t read_len = 0;
-	size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
-
-	d = malloc(max_len);
-	if (d == NULL) {
-		log_err("Out of memory");
-		rc = -1;
-		goto exit;
-	}
-
-	while ((read_len = fread(d + d_len, 1, max_len - d_len, fp)) > 0) {
-		d_len += read_len;
-		if (d_len == max_len) {
-			max_len *= 2;
-			d = realloc(d, max_len);
-			if (d == NULL) {
-				log_err("Out of memory");
-				rc = -1;
-				goto exit;
-			}
-		}
-	}
-
-	if (ferror(fp) != 0) {
-		log_err("Failed to read pp file");
-		rc = -1;
-		goto exit;
-	}
-
-	*data = d;
-	*data_len = d_len;
-
-	return 0;
-
-exit:
-	free(d);
-	return rc;
-}
-
-static int ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
-{
-	int rc = -1;
-	FILE *f = NULL;
-	struct sepol_policy_file *pf = NULL;
-	struct sepol_module_package *pkg = NULL;
-	char *data = NULL;
-	size_t data_len;
-	int fd;
-	struct stat sb;
-
-	rc = sepol_policy_file_create(&pf);
-	if (rc != 0) {
-		log_err("Failed to create policy file");
-		goto exit;
-	}
-
-	fd = fileno(fp);
-	if (fstat(fd, &sb) == -1) {
-		rc = -1;
-		goto exit;
-	}
-
-	if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) {
-		// libsepol fails when trying to read a policy package from a pipe or a
-		// socket due its use of lseek. In this case, read the data into a
-		// buffer and provide that to libsepol
-		rc = fp_to_buffer(fp, &data, &data_len);
-		if (rc != 0) {
-			goto exit;
-		}
-
-		sepol_policy_file_set_mem(pf, data, data_len);
-	} else {
-		sepol_policy_file_set_fp(pf, fp);
-	}
-
-	rc = sepol_module_package_create(&pkg);
-	if (rc != 0) {
-		log_err("Failed to create module package");
-		goto exit;
-	}
-
-	rc = sepol_module_package_read(pkg, pf, 0);
-	if (rc != 0) {
-		log_err("Failed to read policy package");
-		goto exit;
-	}
-
-	*mod_pkg = pkg;
-
-exit:
-	free(data);
-
-	sepol_policy_file_free(pf);
-	if (f != NULL) {
-		fclose(f);
-	}
-
-	if (rc != 0) {
-		sepol_module_package_free(pkg);
-	}
-
-	return rc;
-}
-
 static void usage(int err)
 {
 	fprintf(stderr, "Usage: %s [OPTIONS] [IN_FILE [OUT_FILE]]\n", progname);
@@ -3932,21 +109,20 @@ int main(int argc, char **argv)
 	} else {
 		out = stdout;
 	}
-	out_file = out;
 
 	if (argc >= optind + 3) {
 		log_err("Too many arguments");
 		usage(1);
 	}
 
-	rc = ppfile_to_module_package(in, &mod_pkg);
+	rc = sepol_ppfile_to_module_package(in, &mod_pkg);
 	if (rc != 0) {
 		goto exit;
 	}
 	fclose(in);
 	in = NULL;
 
-	rc = module_package_to_cil(mod_pkg);
+	rc = sepol_module_package_to_cil(out, mod_pkg);
 	if (rc != 0) {
 		goto exit;
 	}
-- 
1.9.3

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux