diff mbox

[1/2,v2] libsepol/cil: Add ability to write policy.conf file from CIL AST

Message ID 1480431057-8768-2-git-send-email-jwcart2@tycho.nsa.gov (mailing list archive)
State Not Applicable
Headers show

Commit Message

James Carter Nov. 29, 2016, 2:50 p.m. UTC
The ability to create a policy.conf file from the CIL AST has been
a desire from the beginning to assist in debugging and for general
flexibility. Some work towards this end was started early in CIL's
history, but cil_policy.c has not been remotely functional in a long
time. Until now.

The function cil_write_policy_conf() will write a policy.conf file
from a CIL AST after cil_build_ast(), cil_resolve_ast(),
cil_fqn_qualify(), and cil_post_process() have been called.

Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
---
 libsepol/cil/include/cil/cil.h |    1 +
 libsepol/cil/src/cil.c         |    6 +
 libsepol/cil/src/cil_policy.c  | 2714 ++++++++++++++++++++++++----------------
 libsepol/cil/src/cil_policy.h  |   12 +-
 libsepol/src/libsepol.map.in   |    1 +
 5 files changed, 1629 insertions(+), 1105 deletions(-)
diff mbox

Patch

diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h
index e4b10c5..c4a6fb9 100644
--- a/libsepol/cil/include/cil/cil.h
+++ b/libsepol/cil/include/cil/cil.h
@@ -52,6 +52,7 @@  extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown);
 extern void cil_set_mls(cil_db_t *db, int mls);
 extern void cil_set_target_platform(cil_db_t *db, int target_platform);
 extern void cil_set_policy_version(cil_db_t *db, int policy_version);
+extern void cil_write_policy_conf(FILE *out, struct cil_db *db);
 
 enum cil_log_level {
 	CIL_ERR = 1,
diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 9b18773..15833c13 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -461,6 +461,12 @@  exit:
 	return rc;
 }
 
+void cil_write_policy_conf(FILE *out, struct cil_db *db)
+{
+	cil_log(CIL_INFO, "Writing policy.conf file\n");
+	cil_gen_policy(out, db);
+}
+
 void cil_destroy_data(void **data, enum cil_flavor flavor)
 {
 	if (*data == NULL) {
diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c
index 382129b..bb832f2 100644
--- a/libsepol/cil/src/cil_policy.c
+++ b/libsepol/cil/src/cil_policy.c
@@ -1,16 +1,16 @@ 
 /*
  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
- * 
+ *
  *    1. Redistributions of source code must retain the above copyright notice,
  *       this list of conditions and the following disclaimer.
- * 
+ *
  *    2. Redistributions in binary form must reproduce the above copyright notice,
  *       this list of conditions and the following disclaimer in the documentation
  *       and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
@@ -21,7 +21,7 @@ 
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  * The views and conclusions contained in the software and documentation are those
  * of the authors and should not be interpreted as representing official policies,
  * either expressed or implied, of Tresys Technology, LLC.
@@ -39,1388 +39,1914 @@ 
 
 #include "cil_internal.h"
 #include "cil_flavor.h"
-#include "cil_log.h"
+#include "cil_find.h"
 #include "cil_mem.h"
 #include "cil_tree.h"
 #include "cil_list.h"
-#include "cil_policy.h"
 #include "cil_symtab.h"
-#include "cil_strpool.h"
-
-#define SEPOL_DONE			555
-
-#define CLASS_DECL			0
-#define ISIDS				1
-#define COMMONS				2
-#define CLASSES				3
-#define INTERFACES			4
-#define SENS				5
-#define CATS				6
-#define LEVELS				7
-#define CONSTRAINS			8
-#define TYPEATTRTYPES			9
-#define ALIASES				10
-#define ALLOWS				11
-#define CONDS				12
-#define USERROLES			13
-#define SIDS				14
-#define NETIFCONS			15 
-
-#define BUFFER				1024
-#define NUM_POLICY_FILES		16
-
-struct cil_args_genpolicy {
-	struct cil_list *users;
-	struct cil_list *sens;
-	struct cil_list *cats;
-	FILE **file_arr;
-};
-
-struct cil_args_booleanif {
-	FILE **file_arr;
-	uint32_t *file_index;
-};
 
 
-int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
+enum cil_statement_list {
+	CIL_LIST_COMMON = 1,
+	CIL_LIST_DEFAULT_USER,
+	CIL_LIST_DEFAULT_ROLE,
+	CIL_LIST_DEFAULT_TYPE,
+	CIL_LIST_DEFAULT_RANGE,
+	CIL_LIST_SENSALIAS,
+	CIL_LIST_CATALIAS,
+	CIL_LIST_MLSCONSTRAIN,
+	CIL_LIST_MLSVALIDATETRANS,
+	CIL_LIST_POLICYCAP,
+	CIL_LIST_TYPEATTRIBUTE,
+	CIL_LIST_ROLEATTRIBUTE,
+	CIL_LIST_BOOL,
+	CIL_LIST_TYPE,
+	CIL_LIST_TYPEALIAS,
+	CIL_LIST_ROLE,
+	CIL_LIST_ROLEALLOW,
+	CIL_LIST_ROLETRANSITION,
+	CIL_LIST_USER,
+	CIL_LIST_CONSTRAINT,
+	CIL_LIST_VALIDATETRANS,
+	CIL_LIST_NUM_LISTS
+};
 
-int cil_combine_policy(FILE **file_arr, FILE *policy_file)
+static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
 {
-	char temp[BUFFER];
-	int i, rc, rc_read, rc_write;
+	struct cil_list **lists;
+	int kind = 0;
 
-	for(i=0; i<NUM_POLICY_FILES; i++) {
-		fseek(file_arr[i], 0, SEEK_SET);
-		while (!feof(file_arr[i])) {
-			rc_read = fread(temp, 1, BUFFER, file_arr[i]);
-			if (rc_read == 0 && ferror(file_arr[i])) {
-				cil_log(CIL_ERR, "Error reading temp policy file\n");
-				return SEPOL_ERR;
-			}
-			rc_write = 0;
-			while (rc_read > rc_write) {
-				rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file);
-				rc_write += rc;
-				if (rc == 0 && ferror(file_arr[i])) {
-					cil_log(CIL_ERR, "Error writing to policy.conf\n");
-					return SEPOL_ERR;
-				}
-			}
+	lists = (struct cil_list **)extra_args;
+
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+		break;
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_BOOLEANIF:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_COMMON:
+		kind = CIL_LIST_COMMON;
+		break;
+	case CIL_DEFAULTUSER:
+		kind = CIL_LIST_DEFAULT_USER;
+		break;
+	case CIL_DEFAULTROLE:
+		kind = CIL_LIST_DEFAULT_ROLE;
+		break;
+	case CIL_DEFAULTTYPE:
+		kind = CIL_LIST_DEFAULT_TYPE;
+		break;
+	case CIL_DEFAULTRANGE:
+		kind = CIL_LIST_DEFAULT_RANGE;
+		break;
+	case CIL_SENSALIAS:
+		kind = CIL_LIST_SENSALIAS;
+		break;
+	case CIL_CATALIAS:
+		kind = CIL_LIST_CATALIAS;
+		break;
+	case CIL_MLSCONSTRAIN:
+		kind = CIL_LIST_MLSCONSTRAIN;
+		break;
+	case CIL_MLSVALIDATETRANS:
+		kind = CIL_LIST_MLSVALIDATETRANS;
+		break;
+	case CIL_POLICYCAP:
+		kind = CIL_LIST_POLICYCAP;
+		break;
+	case CIL_TYPEATTRIBUTE: {
+		struct cil_typeattribute *attr = node->data;
+		if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) {
+			kind = CIL_LIST_TYPEATTRIBUTE;
+		}
+		break;
+	}
+	case CIL_ROLEATTRIBUTE: {
+		struct cil_roleattribute *attr = node->data;
+		if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) {
+			kind = CIL_LIST_ROLEATTRIBUTE;
+		}
+		break;
+	}
+	case CIL_BOOL:
+		kind = CIL_LIST_BOOL;
+		break;
+	case CIL_TYPE:
+		kind = CIL_LIST_TYPE;
+		break;
+	case CIL_TYPEALIAS:
+		kind = CIL_LIST_TYPEALIAS;
+		break;
+	case CIL_ROLE: {
+		struct cil_role *role = node->data;
+		if (strcmp(role->datum.fqn, "object_r") != 0) {
+			kind = CIL_LIST_ROLE;
 		}
+		break;
+	}
+	case CIL_ROLEALLOW:
+		kind = CIL_LIST_ROLEALLOW;
+		break;
+	case CIL_ROLETRANSITION:
+		kind = CIL_LIST_ROLETRANSITION;
+		break;
+	case CIL_USER:
+		kind = CIL_LIST_USER;
+		break;
+	case CIL_CONSTRAIN:
+		kind = CIL_LIST_CONSTRAINT;
+		break;
+	case CIL_VALIDATETRANS:
+		kind = CIL_LIST_VALIDATETRANS;
+		break;
+	default:
+		break;
+	}
+
+	if (kind > 0) {
+		cil_list_append(lists[kind], node->flavor, node->data);
 	}
 
 	return SEPOL_OK;
 }
 
-int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static void cil_gather_statements(struct cil_tree_node *start, struct cil_list *lists[])
 {
-	uint32_t i = 0;
+	cil_tree_walk(start, __cil_gather_statements_helper, NULL, NULL, lists);
+}
 
-	for (i=0; i<sort->count; i++) {
-		struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "portcon ");
-		if (portcon->proto == CIL_PROTOCOL_UDP) {
-			fprintf(file_arr[NETIFCONS], "udp ");
-		} else if (portcon->proto == CIL_PROTOCOL_TCP) {
-			fprintf(file_arr[NETIFCONS], "tcp ");
-		} else if (portcon->proto == CIL_PROTOCOL_DCCP) {
-			fprintf(file_arr[NETIFCONS], "dccp ");
-		}
-		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low);
-		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high);
-		cil_context_to_policy(file_arr, NETIFCONS, portcon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
-	}
+static void cil_simple_rules_to_policy(FILE *out, struct cil_list *rules, char *kind)
+{
+	struct cil_list_item *i1;
 
-	return SEPOL_OK;
+	cil_list_for_each(i1, rules) {
+		fprintf(out, "%s %s;\n", kind, DATUM(i1->data)->fqn);
+	}
 }
 
-int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static void cil_cats_to_policy(FILE *out, struct cil_cats *cats)
 {
-	uint32_t i = 0;
-
-	for (i=0; i<sort->count; i++) {
-		struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str);
-		fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str);
-		cil_context_to_policy(file_arr, NETIFCONS, genfscon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+	char *lead = "";
+	struct cil_cat *first = NULL, *last = NULL, *cat;
+	struct cil_list_item *i1;
+
+	cil_list_for_each(i1, cats->datum_expr) {
+		cat = i1->data;
+		if (first == NULL) {
+			first = cat;
+		} else if (last == NULL) {
+			if (cat->value == first->value + 1) {
+				last = cat;
+			} else {
+				fprintf(out, "%s%s", lead, DATUM(first)->fqn);
+				lead = ",";
+				first = cat;
+			}
+		} else if (cat->value == last->value + 1) {
+			last = cat;
+		} else {
+			fprintf(out, "%s%s", lead, DATUM(first)->fqn);
+			lead = ",";
+			if (last->value >= first->value + 1) {
+				fprintf(out, ".");
+			} else {
+				fprintf(out, ",");
+			}
+			fprintf(out, "%s", DATUM(last)->fqn);
+			first = cat;
+			last = NULL;
+		}
+	}
+	if (first) {
+		fprintf(out, "%s%s", lead, DATUM(first)->fqn);
+		if (last != NULL) {
+			if (last->value >= first->value + 1) {
+				fprintf(out, ".");
+			} else {
+				fprintf(out, ",");
+			}
+			fprintf(out, "%s", DATUM(last)->fqn);
+		}
 	}
+}
 
-	return SEPOL_OK;
+static void cil_level_to_policy(FILE *out, struct cil_level *level)
+{
+	fprintf(out, "%s", DATUM(level->sens)->fqn);
+	if (level->cats != NULL) {
+		fprintf(out, ":");
+		cil_cats_to_policy(out, level->cats);
+	}
 }
 
-int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static int cil_levels_simple_and_equal(struct cil_level *l1, struct cil_level *l2)
 {
-	uint32_t i = 0;
+	/* Mostly just want to detect s0 - s0 ranges */
+	if (l1 == l2)
+		return CIL_TRUE;
 
-	for (i=0; i<sort->count; i++) {
-		struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str);
-		cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context);
-		fprintf(file_arr[NETIFCONS], " ");
-		cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context);
-		fprintf(file_arr[NETIFCONS], ";\n");
-	}
+	if (l1->sens == l2->sens && (l1->cats == NULL && l2->cats == NULL))
+		return CIL_TRUE;
 
-	return SEPOL_OK;
+	return CIL_FALSE;
 }
 
-int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static void cil_levelrange_to_policy(FILE *out, struct cil_levelrange *lvlrange)
 {
-	uint32_t i = 0;
-	int rc = SEPOL_ERR;
+	cil_level_to_policy(out, lvlrange->low);
+	if (cil_levels_simple_and_equal(lvlrange->low, lvlrange->high) == CIL_FALSE) {
+		fprintf(out, " - ");
+		cil_level_to_policy(out, lvlrange->high);
+	}
+}
 
-	for (i=0; i<sort->count; i++) {
-		struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i];
-		char *buf = NULL;
-		errno = 0;
-		if (nodecon->addr->family == AF_INET) {
-			buf = cil_malloc(INET_ADDRSTRLEN);
-			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN);
-		} else if (nodecon->addr->family == AF_INET6) {
-			buf = cil_malloc(INET6_ADDRSTRLEN);
-			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN);
-		}
+static void cil_context_to_policy(FILE *out, struct cil_context *context, int mls)
+{
+	fprintf(out, "%s:", DATUM(context->user)->fqn);
+	fprintf(out, "%s:", DATUM(context->role)->fqn);
+	fprintf(out, "%s", DATUM(context->type)->fqn);
+	if (mls) {
+		fprintf(out, ":");
+		cil_levelrange_to_policy(out, context->range);
+	}
+}
 
-		if (errno != 0) {
-			cil_log(CIL_INFO, "Failed to convert ip address to string\n");
-			rc = SEPOL_ERR;
-			goto exit;
+static void cil_cond_expr_to_policy(FILE *out, struct cil_list *expr, int first)
+{
+	struct cil_list_item *i1 = expr->head;
+
+	if (i1->flavor == CIL_OP) {
+		enum cil_flavor op = (enum cil_flavor)i1->data;
+		fprintf(out, "(");
+		switch (op) {
+		case CIL_NOT:
+			fprintf(out, "! ");
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			break;
+		case CIL_OR:
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			fprintf(out, " || ");
+			cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE);
+			break;
+		case CIL_AND:
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			fprintf(out, " && ");
+			cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE);
+			break;
+		case CIL_XOR:
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			fprintf(out, " ^ ");
+			cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE);
+			break;
+		case CIL_EQ:
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			fprintf(out, " == ");
+			cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE);
+			break;
+		case CIL_NEQ:
+			cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE);
+			fprintf(out, " != ");
+			cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE);
+			break;
+		default:
+			fprintf(out, "???");
+			break;
 		}
-
-		fprintf(file_arr[NETIFCONS], "nodecon %s ", buf);
-		free(buf);
-
-		if (nodecon->mask->family == AF_INET) {
-			buf = cil_malloc(INET_ADDRSTRLEN);
-			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN);
-		} else if (nodecon->mask->family == AF_INET6) {
-			buf = cil_malloc(INET6_ADDRSTRLEN);
-			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN);
+		fprintf(out, ")");
+	} else if (i1->flavor == CIL_DATUM) {
+		if (first == CIL_TRUE) {
+			fprintf(out, "(");
 		}
-
-		if (errno != 0) {
-			cil_log(CIL_INFO, "Failed to convert mask to string\n");
-			rc = SEPOL_ERR;
-			goto exit;
+		fprintf(out, "%s", DATUM(i1->data)->fqn);
+		if (first == CIL_TRUE) {
+			fprintf(out, ")");
 		}
+	} else if (i1->flavor == CIL_LIST) {
+		cil_cond_expr_to_policy(out, i1->data, CIL_FALSE);
+	} else {
+		fprintf(out, "???");
+	}
+}
 
-		fprintf(file_arr[NETIFCONS], "%s ", buf);
-		free(buf);
+static size_t __cil_userattribute_len(struct cil_db *db, struct cil_userattribute *attr)
+{
+	ebitmap_node_t *unode;
+	unsigned int i;
+	size_t len = 0;
 
-		cil_context_to_policy(file_arr, NETIFCONS, nodecon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+	ebitmap_for_each_bit(attr->users, unode, i) {
+		if (!ebitmap_get_bit(attr->users, i))
+			continue;
+		len += strlen(DATUM(db->val_to_user[i])->fqn);
+		len++;
 	}
 
-	return SEPOL_OK;
-
-exit:
-	return rc;
+	return len;
 }
 
+static size_t __cil_cons_leaf_operand_len(struct cil_db *db, struct cil_list_item *operand)
+{
+	struct cil_list_item *i1;
+	enum cil_flavor flavor = operand->flavor;
+	size_t len = 0;
+
+	if (flavor == CIL_CONS_OPERAND) {
+		len = 2;
+	} else if (flavor == CIL_DATUM) {
+		struct cil_tree_node *node = NODE(operand->data);
+		if (node->flavor == CIL_USERATTRIBUTE) {
+			len = __cil_userattribute_len(db, operand->data);
+			len++; /* "{" */
+		} else {
+			len = strlen(DATUM(operand->data)->fqn);
+		}
+	} else if (flavor == CIL_LIST) {
+		len = 1; /* "{" */
+		cil_list_for_each(i1, (struct cil_list *)operand->data) {
+			struct cil_tree_node *node = NODE(operand->data);
+			if (node->flavor == CIL_USERATTRIBUTE) {
+				len = __cil_userattribute_len(db, operand->data);
+			} else {
+				len += strlen(DATUM(operand->data)->fqn);
+				len++; /* " " or "}" */
+			}
+		}
+	}
+
+	return len;
+}
 
-int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static size_t __cil_cons_leaf_op_len(struct cil_list_item *op)
 {
-	uint32_t i = 0;
+	enum cil_flavor flavor = (enum cil_flavor)op->data;
+	size_t len;
 
-	for (i = 0; i < sort->count; i++) {
-		struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq);
-		cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+	switch (flavor) {
+	case CIL_EQ:
+		len = 4; /* " == " */
+		break;
+	case CIL_NEQ:
+		len = 4; /* " != " */
+		break;
+	case CIL_CONS_DOM:
+		len = 5; /* " dom " */
+		break;
+	case CIL_CONS_DOMBY:
+		len = 7; /* " domby " */
+		break;
+	case CIL_CONS_INCOMP:
+		len = 8; /* " incomp " */
+		break;
+	default:
+		/* Should be impossible to be here */
+		len = 5; /* " ??? " */
 	}
 
-	return SEPOL_OK;
+	return len;
 }
-int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+
+static size_t cil_cons_expr_len(struct cil_db *db, struct cil_list *cons_expr)
 {
-	uint32_t i = 0;
+	struct cil_list_item *i1;
+	enum cil_flavor op;
+	size_t len;
 
-	for (i = 0; i < sort->count; i++) {
-		struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high);
-		cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+	i1 = cons_expr->head;
+
+	op = (enum cil_flavor)i1->data;
+	switch (op) {
+	case CIL_NOT:
+		len = 6; /* "(not )" */
+		len += cil_cons_expr_len(db, i1->next->data);
+		break;
+	case CIL_AND:
+		len = 7; /* "( and )" */
+		len += cil_cons_expr_len(db, i1->next->data);
+		len += cil_cons_expr_len(db, i1->next->next->data);
+		break;
+	case CIL_OR:
+		len = 6; /* "( or )" */
+		len += cil_cons_expr_len(db, i1->next->data);
+		len += cil_cons_expr_len(db, i1->next->next->data);
+		break;
+	default:
+		len = 2; /* "()" */
+		len += __cil_cons_leaf_operand_len(db, i1->next);
+		len += __cil_cons_leaf_op_len(i1);
+		len += __cil_cons_leaf_operand_len(db, i1->next->next);
 	}
 
-	return SEPOL_OK;
+	return len;
 }
 
-int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static char *__cil_userattribute_to_string(struct cil_db *db, struct cil_userattribute *attr, char *new)
 {
-	uint32_t i = 0;
+	ebitmap_node_t *unode;
+	unsigned int i;
+	char *str;
+	size_t len;
+
+	ebitmap_for_each_bit(attr->users, unode, i) {
+		if (!ebitmap_get_bit(attr->users, i))
+			continue;
+		str = DATUM(db->val_to_user[i])->fqn;
+		len = strlen(str);
+		memcpy(new, str, len);
+		new += len;
+		*new++ = ' ';
+	}
+
+	return new;
+}
 
-	for (i = 0; i < sort->count; i++) {
-		struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
-		cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+static char *__cil_cons_leaf_operand_to_string(struct cil_db *db, struct cil_list_item *operand, char *new)
+{
+	struct cil_list_item *i1;
+	enum cil_flavor flavor = operand->flavor;
+	char *o_str;
+	size_t o_len;
+
+	if (flavor == CIL_CONS_OPERAND) {
+		enum cil_flavor o_flavor = (enum cil_flavor)operand->data;
+		switch (o_flavor) {
+		case CIL_CONS_U1:
+			o_str = "u1";
+			break;
+		case CIL_CONS_U2:
+			o_str = "u2";
+			break;
+		case CIL_CONS_U3:
+			o_str = "u3";
+			break;
+		case CIL_CONS_R1:
+			o_str = "r1";
+			break;
+		case CIL_CONS_R2:
+			o_str = "r2";
+			break;
+		case CIL_CONS_R3:
+			o_str = "r3";
+			break;
+		case CIL_CONS_T1:
+			o_str = "t1";
+			break;
+		case CIL_CONS_T2:
+			o_str = "t2";
+			break;
+		case CIL_CONS_T3:
+			o_str = "t3";
+			break;
+		case CIL_CONS_L1:
+			o_str = "l1";
+			break;
+		case CIL_CONS_L2:
+			o_str = "l2";
+			break;
+		case CIL_CONS_H1:
+			o_str = "h1";
+			break;
+		case CIL_CONS_H2:
+			o_str = "h2";
+			break;
+		default:
+			/* Impossible */
+			o_str = "??";
+		}
+		strcpy(new, o_str);
+		new += 2;
+	} else if (flavor == CIL_DATUM) {
+		struct cil_tree_node *node = NODE(operand->data);
+		if (node->flavor == CIL_USERATTRIBUTE) {
+			*new++ = '{';
+			new = __cil_userattribute_to_string(db, operand->data, new);
+			new--;
+			*new++ = '}';
+		} else {
+			o_str = DATUM(operand->data)->fqn;
+			o_len = strlen(o_str);
+			memcpy(new, o_str, o_len);
+			new += o_len;
+		}
+	} else if (flavor == CIL_LIST) {
+		*new++ = '{';
+		cil_list_for_each(i1, (struct cil_list *)operand->data) {
+			struct cil_tree_node *node = NODE(operand->data);
+			if (node->flavor == CIL_USERATTRIBUTE) {
+				new = __cil_userattribute_to_string(db, operand->data, new);
+			} else {
+				o_str = DATUM(operand->data)->fqn;
+				o_len = strlen(o_str);
+				memcpy(new, o_str, o_len);
+				new += o_len;
+				*new++ = ' ';
+			}
+		}
+		new--;
+		*new++ = '}';
 	}
 
-	return SEPOL_OK;
+	return new;
 }
 
-int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort)
+static char *__cil_cons_leaf_op_to_string(struct cil_list_item *op, char *new)
 {
-	uint32_t i = 0;
+	enum cil_flavor flavor = (enum cil_flavor)op->data;
+	char *op_str;
+	size_t len;
+
+	switch (flavor) {
+	case CIL_EQ:
+		op_str = " == ";
+		len = 4;
+		break;
+	case CIL_NEQ:
+		op_str = " != ";
+		len = 4;
+		break;
+	case CIL_CONS_DOM:
+		op_str = " dom ";
+		len = 5;
+		break;
+	case CIL_CONS_DOMBY:
+		op_str = " domby ";
+		len = 7;
+		break;
+	case CIL_CONS_INCOMP:
+		op_str = " incomp ";
+		len = 8;
+		break;
+	default:
+		/* Should be impossible to be here */
+		op_str = " ??? ";
+		len = 5;
+	}
+
+	strcpy(new, op_str);
+	new += len;
+
+	return new;
+}
 
-	for (i = 0; i < sort->count; i++) {
-		struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i];
-		fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev);
-		cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
+static char *__cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr, char *new)
+{
+	struct cil_list_item *i1;
+	enum cil_flavor op;
+
+	i1 = cons_expr->head;
+
+	op = (enum cil_flavor)i1->data;
+	switch (op) {
+	case CIL_NOT:
+		*new++ = '(';
+		strcpy(new, "not ");
+		new += 4;
+		new = __cil_cons_expr_to_string(db, i1->next->data, new);
+		*new++ = ')';
+		break;
+	case CIL_AND:
+		*new++ = '(';
+		new = __cil_cons_expr_to_string(db, i1->next->data, new);
+		strcpy(new, " and ");
+		new += 5;
+		new = __cil_cons_expr_to_string(db, i1->next->next->data, new);
+		*new++ = ')';
+		break;
+	case CIL_OR:
+		*new++ = '(';
+		new = __cil_cons_expr_to_string(db, i1->next->data, new);
+		strcpy(new, " or ");
+		new += 4;
+		new = __cil_cons_expr_to_string(db, i1->next->next->data, new);
+		*new++ = ')';
+		break;
+	default:
+		*new++ = '(';
+		new = __cil_cons_leaf_operand_to_string(db, i1->next, new);
+		new = __cil_cons_leaf_op_to_string(i1, new);
+		new = __cil_cons_leaf_operand_to_string(db, i1->next->next, new);
+		*new++ = ')';
 	}
 
-	return SEPOL_OK;
+	return new;
 }
 
-int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort)
+static char *cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr)
 {
-	uint32_t i = 0;
+	char *new, *tail;
+	size_t len = cil_cons_expr_len(db, cons_expr);
 
-	for (i=0; i<sort->count; i++) {
-		struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i];
-		if (fsuse->type == CIL_FSUSE_XATTR) {
-			fprintf(file_arr[NETIFCONS], "fs_use_xattr ");
-		} else if (fsuse->type == CIL_FSUSE_TASK) {
-			fprintf(file_arr[NETIFCONS], "fs_use_task ");
-		} else if (fsuse->type == CIL_FSUSE_TRANS) {
-			fprintf(file_arr[NETIFCONS], "fs_use_trans ");
-		} else {
-			return SEPOL_ERR;
-		}
-		fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str);
-		cil_context_to_policy(file_arr, NETIFCONS, fsuse->context);
-		fprintf(file_arr[NETIFCONS], ";\n");
-	}
+	new = cil_malloc(len+1);
+	tail = __cil_cons_expr_to_string(db, cons_expr, new);
+	*tail = '\0';
 
-	return SEPOL_OK;
+	return new;
 }
 
-int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor)
+static void cil_classperms_to_string(struct cil_classperms *classperms, struct cil_list *classperms_strs)
 {
-	struct cil_list_item *curr_key;
-	struct cil_multimap_item *new_data;
+	struct cil_list_item *i1;
+	size_t len = 0;
+	char *new, *curr;
 
-	if (list == NULL || key == NULL) {
-		return SEPOL_ERR;
+	len += strlen(DATUM(classperms->class)->fqn) + 1;
+	cil_list_for_each(i1, classperms->perms) {
+		len += strlen(DATUM(i1->data)->fqn) + 1;
 	}
+	len += 4; /* for "{ " and " }" */
 
-	cil_list_for_each(curr_key, list) {
-		struct cil_multimap_item *curr_multimap_item = curr_key->data;
-		if (curr_multimap_item != NULL) {
-			if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) {
-				struct cil_list_item *curr_value;
-				cil_list_for_each(curr_value, curr_multimap_item->values) {
-					if (curr_value == (struct cil_list_item*)value) {
-						return SEPOL_OK;;
-					}
+	new = cil_malloc(len);
+	curr = new;
+
+	curr[len-1] = '\0';
+
+	len = strlen(DATUM(classperms->class)->fqn);
+	memcpy(curr, DATUM(classperms->class)->fqn, len);
+	curr += len;
+	*curr++ = ' ';
+
+	*curr++ = '{';
+	*curr++ = ' ';
+	cil_list_for_each(i1, classperms->perms) {
+		len = strlen(DATUM(i1->data)->fqn);
+		memcpy(curr, DATUM(i1->data)->fqn, len);
+		curr += len;
+		*curr++ = ' ';
+	}
+	*curr++ = '}';
+
+	cil_list_append(classperms_strs, CIL_STRING, new);
+}
+
+static void cil_classperms_to_strings(struct cil_list *classperms, struct cil_list *classperms_strs)
+{
+	struct cil_list_item *i1;
+
+	cil_list_for_each(i1, classperms) {
+		if (i1->flavor == CIL_CLASSPERMS) {
+			struct cil_classperms *cp = i1->data;
+			if (FLAVOR(cp->class) == CIL_CLASS) {
+				cil_classperms_to_string(cp, classperms_strs);
+			} else { /* MAP */
+				struct cil_list_item *i2 = NULL;
+				cil_list_for_each(i2, cp->perms) {
+					struct cil_perm *cmp = i2->data;
+					cil_classperms_to_strings(cmp->classperms, classperms_strs);
 				}
-				cil_list_append(curr_multimap_item->values, val_flavor, value);
 			}
-		} else {
-			cil_log(CIL_INFO, "No data in list item\n");
-			return SEPOL_ERR;
+		} else { /* SET */
+			struct cil_classperms_set *cp_set = i1->data;
+			struct cil_classpermission *cp = cp_set->set;
+			cil_classperms_to_strings(cp->classperms, classperms_strs);
 		}
 	}
+}
 
-	new_data = cil_malloc(sizeof(*new_data));
-	new_data->key = key;
-	cil_list_init(&new_data->values, CIL_LIST_ITEM);
-	if (value != NULL) {
-		cil_list_append(new_data->values, val_flavor, value);
-	}
-	cil_list_append(list, key_flavor, new_data);
+static void cil_class_decls_to_policy(FILE *out, struct cil_list *classorder)
+{
+	struct cil_list_item *i1;
 
-	return SEPOL_OK;
+	cil_list_for_each(i1, classorder) {
+		fprintf(out, "class %s\n", DATUM(i1->data)->fqn);
+	}
 }
 
-int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles)
+static void cil_sid_decls_to_policy(FILE *out, struct cil_list *sidorder)
 {
-	struct cil_list_item *current_user;
+	struct cil_list_item *i1;
 
-	if (userroles == NULL) {
-		return SEPOL_OK;
+	cil_list_for_each(i1, sidorder) {
+		fprintf(out, "sid %s\n", DATUM(i1->data)->fqn);
 	}
-	
-	cil_list_for_each(current_user, userroles) {
-		struct cil_multimap_item *user_multimap_item = current_user->data;
-		struct cil_list_item *current_role;
-		if (user_multimap_item->values->head == NULL) {
-			cil_log(CIL_INFO, "No roles associated with user %s\n",  
-					user_multimap_item->key->name);
-			return SEPOL_ERR;
+}
+
+static void cil_commons_to_policy(FILE *out, struct cil_list *commons)
+{
+	struct cil_list_item *i1;
+	struct cil_class* common;
+	struct cil_tree_node *node;
+	struct cil_tree_node *perm;
+
+	cil_list_for_each(i1, commons) {
+		common = i1->data;
+		node = NODE(&common->datum);
+		perm = node->cl_head;
+
+		fprintf(out, "common %s {", common->datum.fqn);
+		while (perm != NULL) {
+			fprintf(out, "%s ", DATUM(perm->data)->fqn);
+			perm = perm->next;
 		}
+		fprintf(out, "}\n");
+	}
+}
 
-		fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name);
+static void cil_classes_to_policy(FILE *out, struct cil_list *classorder)
+{
+	struct cil_list_item *i1;
+	struct cil_class *class;
+	struct cil_tree_node *node;
 
-		cil_list_for_each(current_role, user_multimap_item->values) {
-			fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name);
+	cil_list_for_each(i1, classorder) {
+		class = i1->data;
+		node = NODE(&class->datum);
+
+		fprintf(out, "class %s", class->datum.fqn);
+		if (class->common != NULL) {
+			fprintf(out, " inherits %s", class->common->datum.fqn);
+		}
+		if (node->cl_head != NULL) {
+			struct cil_tree_node *perm = node->cl_head;
+			fprintf(out, " {");
+			while (perm != NULL) {
+				fprintf(out, " %s", DATUM(perm->data)->fqn);
+				perm = perm->next;
+			}
+			fprintf(out, " }");
 		}
-		fprintf(file_arr[USERROLES], " };\n"); 
+		fprintf(out, "\n");
 	}
+}
 
-	return SEPOL_OK;
+static void cil_defaults_to_policy(FILE *out, struct cil_list *defaults, char *kind)
+{
+	struct cil_list_item *i1, *i2, *i3;
+	struct cil_default *def;
+	struct cil_list *class_list;
+
+	cil_list_for_each(i1, defaults) {
+		def = i1->data;
+		fprintf(out, "%s {",kind);
+		cil_list_for_each(i2, def->class_datums) {
+			class_list = cil_expand_class(i2->data);
+			cil_list_for_each(i3, class_list) {
+				fprintf(out, " %s", DATUM(i3->data)->fqn);
+			}
+			cil_list_destroy(&class_list, CIL_FALSE);
+		}
+		fprintf(out, " }");
+		if (def->object == CIL_DEFAULT_SOURCE) {
+			fprintf(out," %s",CIL_KEY_SOURCE);
+		} else if (def->object == CIL_DEFAULT_TARGET) {
+			fprintf(out," %s",CIL_KEY_TARGET);
+		}
+		fprintf(out,";\n");
+	}
 }
 
-int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats)
+static void cil_default_ranges_to_policy(FILE *out, struct cil_list *defaults)
 {
-	struct cil_list_item *curr_cat;
+	struct cil_list_item *i1, *i2, *i3;
+	struct cil_defaultrange *def;
+	struct cil_list *class_list;
+
+	cil_list_for_each(i1, defaults) {
+		def = i1->data;
+		fprintf(out, "default_range {");
+		cil_list_for_each(i2, def->class_datums) {
+			class_list = cil_expand_class(i2->data);
+			cil_list_for_each(i3, class_list) {
+				fprintf(out, " %s", DATUM(i3->data)->fqn);
+			}
+			cil_list_destroy(&class_list, CIL_FALSE);
+		}
+		fprintf(out, " }");
 
-	if (cats == NULL) {
-		return SEPOL_OK;
+		switch (def->object_range) {
+		case CIL_DEFAULT_SOURCE_LOW:
+			fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW);
+			break;
+		case CIL_DEFAULT_SOURCE_HIGH:
+			fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_HIGH);
+			break;
+		case CIL_DEFAULT_SOURCE_LOW_HIGH:
+			fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW_HIGH);
+			break;
+		case CIL_DEFAULT_TARGET_LOW:
+			fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW);
+			break;
+		case CIL_DEFAULT_TARGET_HIGH:
+			fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_HIGH);
+			break;
+		case CIL_DEFAULT_TARGET_LOW_HIGH:
+			fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW_HIGH);
+			break;
+		default:
+			break;
+		}
+		fprintf(out,";\n");
 	}
+}
 
-	cil_list_for_each(curr_cat, cats) {
-		struct cil_multimap_item *cat_multimap_item = curr_cat->data;
-		fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name);
-		if (cat_multimap_item->values->head == NULL) {
-			fprintf(file_arr[CATS], ";\n");
-		} else {
-			struct cil_list_item *curr_catalias;
-			fprintf(file_arr[CATS], " alias");
-			cil_list_for_each(curr_catalias, cat_multimap_item->values) {
-				fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name);
+static void cil_sensitivities_to_policy(FILE *out, struct cil_list *sensorder, struct cil_list *all_aliases)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_sens *sens;
+	struct cil_list *aliases = NULL;
+	struct cil_alias *alias;
+	struct cil_sens *actual;
+	int num_aliases;
+
+	cil_list_for_each(i1, sensorder) {
+		sens = i1->data;
+		num_aliases = 0;
+		cil_list_for_each(i2, all_aliases) {
+			alias = i2->data;
+			actual = alias->actual;
+			if (sens == actual) {
+				if (num_aliases == 0) {
+					cil_list_init(&aliases, CIL_LIST);
+				}
+				cil_list_append(aliases, CIL_SENSALIAS, alias);
+				num_aliases++;
 			}
-			fprintf(file_arr[CATS], ";\n"); 
 		}
+		fprintf(out, "sensitivity %s", sens->datum.fqn);
+		if (num_aliases > 0) {
+			fprintf(out, " alias");
+			if (num_aliases > 1) {
+				fprintf(out, " {");
+			}
+			cil_list_for_each(i2, aliases) {
+				alias = i2->data;
+				fprintf(out, " %s", alias->datum.fqn);
+			}
+			if (num_aliases > 1) {
+				fprintf(out, " }");
+			}
+			cil_list_destroy(&aliases, CIL_FALSE);
+		}
+		fprintf(out, ";\n");
 	}
-
-	return SEPOL_OK;
 }
 
-int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens)
+static void cil_dominance_to_policy(FILE *out, struct cil_list *sensorder)
 {
-	struct cil_list_item *curr_sens;
+	struct cil_list_item *item;
+	struct cil_sens *sens;
 
-	if (sens == NULL) {
-		return SEPOL_OK;
+	fprintf(out, "dominance {");
+	cil_list_for_each(item, sensorder) {
+		sens = item->data;
+		fprintf(out, " %s", sens->datum.fqn);
 	}
+	fprintf(out, " }\n");
+}
 
-	cil_list_for_each(curr_sens, sens) {
-		struct cil_multimap_item *sens_multimap_item = curr_sens->data;
-		fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name);
-		if (sens_multimap_item->values->head == NULL) 
-			fprintf(file_arr[SENS], ";\n");
-		else {
-			struct cil_list_item *curr_sensalias;
-			fprintf(file_arr[SENS], " alias");
-			cil_list_for_each(curr_sensalias, sens_multimap_item->values) {
-				fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name);
+static void cil_categories_to_policy(FILE *out, struct cil_list *catorder, struct cil_list *all_aliases)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_sens *cat;
+	struct cil_list *aliases = NULL;
+	struct cil_alias *alias;
+	struct cil_sens *actual;
+	int num_aliases;
+
+	cil_list_for_each(i1, catorder) {
+		cat = i1->data;
+		num_aliases = 0;
+		cil_list_for_each(i2, all_aliases) {
+			alias = i2->data;
+			actual = alias->actual;
+			if (cat == actual) {
+				if (num_aliases == 0) {
+					cil_list_init(&aliases, CIL_LIST);
+				}
+				cil_list_append(aliases, CIL_CATALIAS, alias);
+				num_aliases++;
 			}
-			fprintf(file_arr[SENS], ";\n"); 
 		}
+		fprintf(out, "category %s",cat->datum.fqn);
+		if (num_aliases > 0) {
+			fprintf(out, " alias");
+			if (num_aliases > 1) {
+				fprintf(out, " { ");
+			}
+			cil_list_for_each(i2, aliases) {
+				alias = i2->data;
+				fprintf(out, " %s", alias->datum.fqn);
+			}
+			if (num_aliases > 1) {
+				fprintf(out, " }");
+			}
+			cil_list_destroy(&aliases, CIL_FALSE);
+		}
+		fprintf(out, ";\n");
 	}
-
-	return SEPOL_OK;
 }
 
-void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats)
+static void cil_levels_to_policy(FILE *out, struct cil_list *sensorder)
 {
-	cil_expr_to_policy(file_arr, file_index, cats->datum_expr);
+	struct cil_list_item *i1, *i2;
+	struct cil_sens *sens;
+
+	cil_list_for_each(i1, sensorder) {
+		sens = i1->data;
+		if (sens->cats_list) {
+			cil_list_for_each(i2, sens->cats_list) {
+				fprintf(out, "level %s:",sens->datum.fqn);
+				cil_cats_to_policy(out, i2->data);
+				fprintf(out,";\n");
+			}
+		} else {
+			fprintf(out, "level %s;\n",sens->datum.fqn);
+		}
+	}
 }
 
-void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level)
+static void cil_mlsconstrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *mlsconstrains)
 {
-	char *sens_str = level->sens->datum.name;
-
-	fprintf(file_arr[file_index], "%s", sens_str);
-	if (level->cats != NULL) {
-		fprintf(file_arr[file_index], ":");
-		cil_cats_to_policy(file_arr, file_index, level->cats);
+	struct cil_list_item *i1, *i2;
+	struct cil_constrain *cons;
+	struct cil_list *classperms_strs;
+	char *cp_str;
+	char *expr_str;
+
+	cil_list_for_each(i1, mlsconstrains) {
+		cons = i1->data;
+		cil_list_init(&classperms_strs, CIL_LIST);
+		cil_classperms_to_strings(cons->classperms, classperms_strs);
+		expr_str = cil_cons_expr_to_string(db, cons->datum_expr);
+		cil_list_for_each(i2, classperms_strs) {
+			cp_str = i2->data;
+			fprintf(out, "mlsconstrain %s %s;\n", cp_str, expr_str);
+			free(cp_str);
+		}
+		free(expr_str);
+		cil_list_destroy(&classperms_strs, CIL_FALSE);
 	}
 }
 
-void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange)
+static void cil_validatetrans_to_policy(FILE *out, struct cil_db *db, struct cil_list *validatetrans, char *kind)
 {
-	struct cil_level *low = lvlrange->low;
-	struct cil_level *high = lvlrange->high;
-
-	cil_level_to_policy(file_arr, file_index, low);
-	fprintf(file_arr[file_index], "-");
-	cil_level_to_policy(file_arr, file_index, high);
+	struct cil_list_item *i1, *i2;
+	struct cil_validatetrans *trans;
+	struct cil_list *class_list;
+	struct cil_class *class;
+	char *expr_str;
+
+	cil_list_for_each(i1, validatetrans) {
+		trans = i1->data;
+		class_list = cil_expand_class(trans->class);
+		expr_str = cil_cons_expr_to_string(db, trans->datum_expr);
+		cil_list_for_each(i2, class_list) {
+			class = i2->data;
+			fprintf(out, "%s %s %s;\n", kind, class->datum.fqn, expr_str);
+		}
+		free(expr_str);
+		cil_list_destroy(&class_list, CIL_FALSE);
+	}
 }
 
-void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context)
+static void cil_bools_to_policy(FILE *out, struct cil_list *bools)
 {
-	char *user_str = ((struct cil_symtab_datum*)context->user)->name;
-	char *role_str = ((struct cil_symtab_datum*)context->role)->name;
-	char *type_str = ((struct cil_symtab_datum*)context->type)->name;
-	struct cil_levelrange *lvlrange = context->range;
+	struct cil_list_item *i1;
+	struct cil_bool *bool;
+	char *value;
 
-	fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str);
-	cil_levelrange_to_policy(file_arr, file_index, lvlrange);
+	cil_list_for_each(i1, bools) {
+		bool = i1->data;
+		value = bool->value ? "true" : "false";
+		fprintf(out, "bool %s %s;\n", bool->datum.fqn, value);
+	}
 }
 
-void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list)
+static void cil_typealiases_to_policy(FILE *out, struct cil_list *types, struct cil_list *all_aliases)
 {
-	struct cil_list_item *curr;
-
-	fprintf(file_arr[file_index], " {");
-	cil_list_for_each(curr, list) {
-		switch (curr->flavor) {
-		case CIL_LIST:
-			cil_perms_to_policy(file_arr, file_index, curr->data);
-			break;
-		case CIL_STRING:
-			fprintf(file_arr[file_index], " %s", (char *)curr->data);
-			break;
-		case CIL_DATUM:
-			fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name);
-			break;
-		case CIL_OP: {
-			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
-			char *op_str = NULL;
-
-			switch (op_flavor) {
-			case CIL_AND:
-				op_str = CIL_KEY_AND;
-				break;
-			case CIL_OR:
-				op_str = CIL_KEY_OR;
-				break;
-			case CIL_NOT:
-				op_str = CIL_KEY_NOT;
-				break;
-			case CIL_ALL:
-				op_str = CIL_KEY_ALL;
-				break;
-			case CIL_XOR:
-				op_str = CIL_KEY_XOR;
-				break;
-			default:
-				cil_log(CIL_ERR, "Unknown operator in expression\n");
-				break;
+	struct cil_list_item *i1, *i2;
+	struct cil_type *type;
+	struct cil_list *aliases = NULL;
+	struct cil_alias *alias;
+	struct cil_type *actual;
+	int num_aliases;
+
+	cil_list_for_each(i1, types) {
+		type = i1->data;
+		num_aliases = 0;
+		cil_list_for_each(i2, all_aliases) {
+			alias = i2->data;
+			actual = alias->actual;
+			if (type == actual) {
+				if (num_aliases == 0) {
+					cil_list_init(&aliases, CIL_LIST);
+				}
+				cil_list_append(aliases, CIL_TYPEALIAS, alias);
+				num_aliases++;
 			}
-			fprintf(file_arr[file_index], " %s", op_str);
-			break;
 		}
-		default:
-			cil_log(CIL_ERR, "Unknown flavor in expression\n");
-			break;
+		if (num_aliases > 0) {
+			fprintf(out, "typealias %s alias", type->datum.fqn);
+			if (num_aliases > 1) {
+				fprintf(out, " {");
+			}
+			cil_list_for_each(i2, aliases) {
+				alias = i2->data;
+				fprintf(out, " %s", alias->datum.fqn);
+			}
+			if (num_aliases > 1) {
+				fprintf(out, " }");
+			}
+			fprintf(out, ";\n");
+			cil_list_destroy(&aliases, CIL_FALSE);
 		}
 	}
-	fprintf(file_arr[file_index], " }");
 }
 
-void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr)
+static void cil_typebounds_to_policy(FILE *out, struct cil_list *types)
 {
-	struct cil_list_item *curr;
+	struct cil_list_item *i1;
+	struct cil_type *child;
+	struct cil_type *parent;
+
+	cil_list_for_each(i1, types) {
+		child = i1->data;
+		if (child->bounds != NULL) {
+			parent = child->bounds;
+			fprintf(out, "typebounds %s %s\n", parent->datum.fqn, child->datum.fqn);
+		}
+	}
+}
 
-	cil_list_for_each(curr, classperms) {
-		if (curr->flavor == CIL_CLASSPERMS) {
-			struct cil_classperms *cp = curr->data;
-			if (FLAVOR(cp->class) == CIL_CLASS) {
-				fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name);
-				cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms);
-				fprintf(file_arr[CONSTRAINS], "\n\t");
-				cil_expr_to_policy(file_arr, CONSTRAINS, expr);
-				fprintf(file_arr[CONSTRAINS], ";\n");
-			} else { /* MAP */
-				struct cil_list_item *i = NULL;
-				cil_list_for_each(i, cp->perms) {
-					struct cil_perm *cmp = i->data;
-					cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr);
+static void cil_typeattributes_to_policy(FILE *out, struct cil_list *types, struct cil_list *attributes)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_type *type;
+	struct cil_typeattribute *attribute;
+	int first = CIL_TRUE;
+
+	cil_list_for_each(i1, types) {
+		type = i1->data;
+		cil_list_for_each(i2, attributes) {
+			attribute = i2->data;
+			if (!attribute->used)
+				continue;
+			if (ebitmap_get_bit(attribute->types, type->value)) {
+				if (first) {
+					fprintf(out, "typeattribute %s %s", type->datum.fqn, attribute->datum.fqn);
+					first = CIL_FALSE;
+				} else {
+					fprintf(out, ", %s", attribute->datum.fqn);
 				}
-			}	
-		} else { /* SET */
-			struct cil_classperms_set *cp_set = curr->data;
-			struct cil_classpermission *cp = cp_set->set;
-			cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr);
+			}
+		}
+		if (!first) {
+			fprintf(out, ";\n");
+			first = CIL_TRUE;
 		}
 	}
 }
 
-void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor)
+static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx)
 {
-	char *kind = NULL;
+	ebitmap_node_t *node;
+	unsigned int i, first = 0, last = 0;
+	int need_first = CIL_TRUE, need_last = CIL_TRUE;
+	char *kind;
 
-	if (flavor == CIL_CONSTRAIN) {
-		kind = CIL_KEY_CONSTRAIN;
-	} else if (flavor == CIL_MLSCONSTRAIN) {
-		kind = CIL_KEY_MLSCONSTRAIN;
+	if (permx->kind == CIL_PERMX_KIND_IOCTL) {
+		kind = "ioctl";
+	} else {
+		kind = "???";
 	}
 
-	cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr);
-}
+	fprintf(out, "%s %s {", DATUM(permx->obj)->fqn, kind);
 
-void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms)
-{
-	struct cil_list_item *i;
-
-	cil_list_for_each(i, classperms) {
-		if (i->flavor == CIL_CLASSPERMS) {
-			struct cil_classperms *cp = i->data;
-			if (FLAVOR(cp->class) == CIL_CLASS) {
-				fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name);
-				cil_perms_to_policy(file_arr, file_index, cp->perms);
-				fprintf(file_arr[file_index], ";\n");
-			} else { /* MAP */
-				struct cil_list_item *j = NULL;
-				cil_list_for_each(j, cp->perms) {
-					struct cil_perm *cmp = j->data;
-					cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms);
-				}
+	ebitmap_for_each_bit(permx->perms, node, i) {
+		if (!ebitmap_get_bit(permx->perms, i))
+			continue;
+		if (need_first == CIL_TRUE) {
+			first = i;
+			need_first = CIL_FALSE;
+		} else if (need_last == CIL_TRUE) {
+			if (i == first+1) {
+				last = i;
+				need_last = CIL_FALSE;
+			} else {
+				fprintf(out, " 0x%x", first);
+				first = i;
 			}
-		} else { /* SET */
-			struct cil_list_item *j;
-			struct cil_classperms_set *cp_set = i->data;
-			struct cil_classpermission *cp = cp_set->set;
-			cil_list_for_each(j, cp->classperms) {
-				cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data);
+		} else if (i == last+1) {
+			last = i;
+		} else {
+			if (last > first+1) {
+				fprintf(out, " 0x%x-0x%x", first, last);
+			} else {
+				fprintf(out, " 0x%x 0x%x", first, last);
 			}
+			first = i;
+			need_last = CIL_TRUE;
 		}
 	}
+	if (need_first == CIL_FALSE) {
+		if (need_last == CIL_FALSE) {
+			fprintf(out, " 0x%x-0x%x", first, last);
+		} else {
+			fprintf(out, " 0x%x", first);
+		}
+	}
+	fprintf(out," }");
+}
+
+static void cil_av_rulex_to_policy(FILE *out, struct cil_avrule *rule)
+{
+	char *kind;
+	struct cil_symtab_datum *src, *tgt;
+
+	src = rule->src;
+	tgt = rule->tgt;
+
+	switch (rule->rule_kind) {
+	case CIL_AVRULE_ALLOWED:
+		kind = "allowxperm";
+		break;
+	case CIL_AVRULE_AUDITALLOW:
+		kind = "auditallowxperm";
+		break;
+	case CIL_AVRULE_DONTAUDIT:
+		kind = "dontauditxperm";
+		break;
+	case CIL_AVRULE_NEVERALLOW:
+		kind = "neverallowxperm";
+		break;
+	default:
+		kind = "???";
+		break;
+	}
+
+	fprintf(out, "%s %s %s : ", kind, src->fqn, tgt->fqn);
+	cil_xperms_to_policy(out, rule->perms.x.permx);
+	fprintf(out, ";\n");
 }
 
-int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule)
+static void cil_av_rule_to_policy(FILE *out, struct cil_avrule *rule)
 {
-	const char *kind_str = NULL;
-	const char *src_str = DATUM(rule->src)->name;
-	const char *tgt_str = DATUM(rule->tgt)->name;
+	char *kind;
+	struct cil_symtab_datum *src, *tgt;
+	struct cil_list *classperms_strs;
+	struct cil_list_item *i1;
 
+	src = rule->src;
+	tgt = rule->tgt;
 
 	switch (rule->rule_kind) {
 	case CIL_AVRULE_ALLOWED:
-		kind_str = "allow";
+		kind = "allow";
 		break;
 	case CIL_AVRULE_AUDITALLOW:
-		kind_str = "auditallow";
+		kind = "auditallow";
 		break;
 	case CIL_AVRULE_DONTAUDIT:
-		kind_str = "dontaudit";
+		kind = "dontaudit";
 		break;
 	case CIL_AVRULE_NEVERALLOW:
-		kind_str = "neverallow";
+		kind = "neverallow";
+		break;
+	default:
+		kind = "???";
 		break;
-	default :
-		cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n",
-				rule->rule_kind, src_str, tgt_str);
-		return SEPOL_ERR;
 	}
 
-	cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->perms.classperms);
-
-	return SEPOL_OK;
+	cil_list_init(&classperms_strs, CIL_LIST);
+	cil_classperms_to_strings(rule->perms.classperms, classperms_strs);
+	cil_list_for_each(i1, classperms_strs) {
+		char *cp_str = i1->data;
+		fprintf(out, "%s %s %s : %s;\n", kind, src->fqn, tgt->fqn, cp_str);
+		free(cp_str);
+	}
+	cil_list_destroy(&classperms_strs, CIL_FALSE);
 }
 
-int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule)
+static void cil_type_rule_to_policy(FILE *out, struct cil_type_rule *rule)
 {
-	char *src_str = ((struct cil_symtab_datum*)rule->src)->name;
-	char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name;
-	char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name;
-	char *result_str = ((struct cil_symtab_datum*)rule->result)->name;
-		
+	char *kind;
+	struct cil_symtab_datum *src, *tgt, *res;
+	struct cil_list *class_list;
+	struct cil_list_item *i1;
+
+	src = rule->src;
+	tgt = rule->tgt;
+	res = rule->result;
+
 	switch (rule->rule_kind) {
 	case CIL_TYPE_TRANSITION:
-		fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
-		break;
-	case CIL_TYPE_CHANGE:
-		fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str);
+		kind = "type_transition";
 		break;
 	case CIL_TYPE_MEMBER:
-		fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
+		kind = "type_member";
+		break;
+	case CIL_TYPE_CHANGE:
+		kind = "type_change";
 		break;
 	default:
-		cil_log(CIL_INFO, "Unknown type_rule\n");
-		return SEPOL_ERR;
+		kind = "???";
+		break;
 	}
 
-	return SEPOL_OK;
+	class_list = cil_expand_class(rule->obj);
+	cil_list_for_each(i1, class_list) {
+		fprintf(out, "%s %s %s : %s %s;\n", kind, src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn);
+	}
+	cil_list_destroy(&class_list, CIL_FALSE);
 }
 
-int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans)
+static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetransition *trans)
 {
-	char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name;
-	char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name;
-	char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name;
-	char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name;
+	struct cil_symtab_datum *src, *tgt, *res;
+	struct cil_name *name;
+	struct cil_list *class_list;
+	struct cil_list_item *i1;
 
-	fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str);
-	return SEPOL_OK;
+	src = trans->src;
+	tgt = trans->tgt;
+	name = trans->name;
+	res = trans->result;
+
+	class_list = cil_expand_class(trans->obj);
+	cil_list_for_each(i1, class_list) {
+		fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn);
+	}
+	cil_list_destroy(&class_list, CIL_FALSE);
+}
+
+static void cil_rangetransition_to_policy(FILE *out, struct cil_rangetransition *trans)
+{
+	struct cil_symtab_datum *src, *exec;
+	struct cil_list *class_list;
+	struct cil_list_item *i1;
+
+	src = trans->src;
+	exec = trans->exec;
+
+	class_list = cil_expand_class(trans->obj);
+	cil_list_for_each(i1, class_list) {
+		fprintf(out, "range_transition %s %s : %s ", src->fqn, exec->fqn, DATUM(i1->data)->fqn);
+		cil_levelrange_to_policy(out, trans->range);
+		fprintf(out, ";\n");
+	}
+	cil_list_destroy(&class_list, CIL_FALSE);
+}
+
+static void cil_typepermissive_to_policy(FILE *out, struct cil_typepermissive *rule)
+{
+	fprintf(out, "permissive %s;\n", DATUM(rule->type)->fqn);
 }
 
-static int cil_expr_to_string(struct cil_list *expr, char **out)
+struct block_te_rules_extra {
+	FILE *out;
+	enum cil_flavor flavor;
+	uint32_t rule_kind;
+};
+
+static int __cil_block_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
 {
-	int rc = SEPOL_ERR;
-	struct cil_list_item *curr;
-	char *stack[COND_EXPR_MAXDEPTH] = {};
-	int pos = 0;
-	int i;
+	struct block_te_rules_extra *args = extra_args;
 
-	cil_list_for_each(curr, expr) {
-		if (pos > COND_EXPR_MAXDEPTH) {
-			rc = SEPOL_ERR;
-			goto exit;
+	switch (node->flavor) {
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
 		}
-		switch (curr->flavor) {
-		case CIL_LIST:
-			rc = cil_expr_to_string(curr->data, &stack[pos]);
-			if (rc != SEPOL_OK) {
-				goto exit;
-			}
-			pos++;
-			break;
-		case CIL_STRING:
-			stack[pos] = curr->data;
-			pos++;
-			break;
-		case CIL_DATUM:
-			stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
-			pos++;
-			break;
-		case CIL_OP: {
-			int len;
-			char *expr_str;
-			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
-			char *op_str = NULL;
-
-			if (pos == 0) {
-				rc = SEPOL_ERR;
-				goto exit;
-			}
-			switch (op_flavor) {
-			case CIL_AND:
-				op_str = CIL_KEY_AND;
-				break;
-			case CIL_OR:
-				op_str = CIL_KEY_OR;
-				break;
-			case CIL_NOT:
-				op_str = CIL_KEY_NOT;
-				break;
-			case CIL_ALL:
-				op_str = CIL_KEY_ALL;
-				break;
-			case CIL_EQ:
-				op_str = CIL_KEY_EQ;
-				break;
-			case CIL_NEQ:
-				op_str = CIL_KEY_NEQ;
-				break;
-			case CIL_XOR:
-				op_str = CIL_KEY_XOR;
-				break;
-			case CIL_CONS_DOM:
-				op_str = CIL_KEY_CONS_DOM;
-				break;
-			case CIL_CONS_DOMBY:
-				op_str = CIL_KEY_CONS_DOMBY;
-				break;
-			case CIL_CONS_INCOMP:
-				op_str = CIL_KEY_CONS_INCOMP;
-				break;
-			default:
-				cil_log(CIL_ERR, "Unknown operator in expression\n");
-				goto exit;
-				break;
-			}
-			if (op_flavor == CIL_NOT) {
-				len = strlen(stack[pos-1]) + strlen(op_str) + 4;
-				expr_str = cil_malloc(len);
-				snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
-				free(stack[pos-1]);
-				stack[pos-1] = NULL;
-				pos--;
-			} else {
-				if (pos < 2) {
-					rc = SEPOL_ERR;
-					goto exit;
+		break;
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_BOOLEANIF:
+		*finished = CIL_TREE_SKIP_HEAD;
+		break;
+	case CIL_AVRULE:
+	case CIL_AVRULEX:
+		if (args->flavor == node->flavor) {
+			struct cil_avrule *rule = node->data;
+			if (args->rule_kind == rule->rule_kind) {
+				if (rule->is_extended) {
+					cil_av_rulex_to_policy(args->out, rule);
+				} else {
+					cil_av_rule_to_policy(args->out, rule);
 				}
-				len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
-				expr_str = cil_malloc(len);
-				snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]);
-				free(stack[pos-2]);
-				free(stack[pos-1]);
-				stack[pos-2] = NULL;
-				stack[pos-1] = NULL;
-				pos -= 2;
 			}
-			stack[pos] = expr_str;
-			pos++;
-			break;
 		}
-		case CIL_CONS_OPERAND: {
-			enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
-			char *operand_str = NULL;
-			switch (operand_flavor) {
-			case CIL_CONS_U1:
-				operand_str = CIL_KEY_CONS_U1;
-				break;
-			case CIL_CONS_U2:
-				operand_str = CIL_KEY_CONS_U2;
-				break;
-			case CIL_CONS_U3:
-				operand_str = CIL_KEY_CONS_U3;
-				break;
-			case CIL_CONS_T1:
-				operand_str = CIL_KEY_CONS_T1;
-				break;
-			case CIL_CONS_T2:
-				operand_str = CIL_KEY_CONS_T2;
-				break;
-			case CIL_CONS_T3:
-				operand_str = CIL_KEY_CONS_T3;
-				break;
-			case CIL_CONS_R1:
-				operand_str = CIL_KEY_CONS_R1;
-				break;
-			case CIL_CONS_R2:
-				operand_str = CIL_KEY_CONS_R2;
-				break;
-			case CIL_CONS_R3:
-				operand_str = CIL_KEY_CONS_R3;
-				break;
-			case CIL_CONS_L1:
-				operand_str = CIL_KEY_CONS_L1;
-				break;
-			case CIL_CONS_L2:
-				operand_str = CIL_KEY_CONS_L2;
-				break;
-			case CIL_CONS_H1:
-				operand_str = CIL_KEY_CONS_H1;
-				break;
-			case CIL_CONS_H2:
-				operand_str = CIL_KEY_CONS_H2;
-				break;
-			default:
-				cil_log(CIL_ERR, "Unknown operand in expression\n");
-				goto exit;
-				break;
+		break;
+	case CIL_TYPE_RULE:
+		if (args->flavor == node->flavor) {
+			struct cil_type_rule *rule = node->data;
+			if (args->rule_kind == rule->rule_kind) {
+				cil_type_rule_to_policy(args->out, rule);
 			}
-			stack[pos] = operand_str;
-			pos++;
-			break;
 		}
-		default:
-			cil_log(CIL_ERR, "Unknown flavor in expression\n");
-			goto exit;
-			break;
+
+		break;
+	case CIL_NAMETYPETRANSITION:
+		if (args->flavor == node->flavor) {
+			cil_nametypetransition_to_policy(args->out, node->data);
+		}
+		break;
+	case CIL_RANGETRANSITION:
+		if (args->flavor == node->flavor) {
+			cil_rangetransition_to_policy(args->out, node->data);
 		}
-	}
 
-	*out = stack[0];
+		break;
+	case CIL_TYPEPERMISSIVE:
+		if (args->flavor == node->flavor) {
+			cil_typepermissive_to_policy(args->out, node->data);
+		}
+		break;
+	default:
+		break;
+	}
 
 	return SEPOL_OK;
-
-exit:
-	for (i = 0; i < pos; i++) {
-		free(stack[i]);
-	}
-	return rc;
 }
 
-int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr)
+static void cil_block_te_rules_to_policy(FILE *out, struct cil_tree_node *start, int mls)
 {
-	int rc = SEPOL_ERR;
-	char *str_out;
-
-	rc = cil_expr_to_string(expr, &str_out);
-	if (rc != SEPOL_OK) {
-		goto out;
+	struct block_te_rules_extra args;
+
+	args.out = out;
+
+	args.flavor = CIL_TYPEPERMISSIVE;
+	args.rule_kind = 0;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+
+	args.flavor = CIL_AVRULE;
+	args.rule_kind = CIL_AVRULE_ALLOWED;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_AUDITALLOW;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_DONTAUDIT;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_NEVERALLOW;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+
+	args.flavor = CIL_AVRULEX;
+	args.rule_kind = CIL_AVRULE_ALLOWED;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_AUDITALLOW;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_DONTAUDIT;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_NEVERALLOW;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+
+	args.flavor = CIL_TYPE_RULE;
+	args.rule_kind = CIL_TYPE_TRANSITION;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_TYPE_MEMBER;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_TYPE_CHANGE;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+	args.rule_kind = CIL_AVRULE_TYPE;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+
+	args.flavor = CIL_NAMETYPETRANSITION;
+	args.rule_kind = 0;
+	cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
+
+	if (mls == CIL_TRUE) {
+		args.flavor = CIL_RANGETRANSITION;
+		args.rule_kind = 0;
+		cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args);
 	}
-	fprintf(file_arr[file_index], "%s", str_out);
-	free(str_out);
-
-	return SEPOL_OK;
-
-out:
-	return rc;
 }
 
-int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
-{
-	int rc = SEPOL_ERR;
-	struct cil_args_booleanif *args;
-	FILE **file_arr;
-	uint32_t *file_index;
+struct te_rules_extra {
+	FILE *out;
+	int mls;
+};
 
-	args = extra_args;
-	file_arr = args->file_arr;
-	file_index = args->file_index;
+static int __cil_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	struct te_rules_extra *args = extra_args;
 
 	switch (node->flavor) {
-	case CIL_AVRULE:
-		rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc);
-			return rc;
-		}
-		break;
-	case CIL_TYPE_RULE:
-		rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc);
-			return rc;
+	case CIL_BLOCK: {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
 		}
 		break;
-	case CIL_FALSE:
-		fprintf(file_arr[*file_index], "else {\n");
+	}
+	case CIL_MACRO:
+		*finished = CIL_TREE_SKIP_HEAD;
 		break;
-	case CIL_TRUE:
+	case CIL_BOOLEANIF: {
+		struct cil_booleanif *bool = node->data;
+		struct cil_tree_node *n;
+		struct cil_condblock *cb;
+
+		fprintf(args->out, "if ");
+		cil_cond_expr_to_policy(args->out, bool->datum_expr, CIL_TRUE);
+		fprintf(args->out," {\n");
+		n = node->cl_head;
+		cb = n != NULL ? n->data : NULL;
+		if (cb && cb->flavor == CIL_CONDTRUE) {
+			cil_block_te_rules_to_policy(args->out, n, args->mls);
+			n = n->next;
+			cb = n != NULL ? n->data : NULL;
+		}
+		if (cb && cb->flavor == CIL_CONDFALSE) {
+			fprintf(args->out,"} else {\n");
+			cil_block_te_rules_to_policy(args->out, n, args->mls);
+		}
+		fprintf(args->out,"}\n");
+		*finished = CIL_TREE_SKIP_HEAD;
 		break;
+	}
 	default:
-		return SEPOL_ERR;
+		break;
 	}
 
 	return SEPOL_OK;
 }
 
-int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args)
+static void cil_te_rules_to_policy(FILE *out, struct cil_tree_node *head, int mls)
 {
-	struct cil_args_booleanif *args;
-	FILE **file_arr;
-	uint32_t *file_index;
+	struct te_rules_extra args;
 
-	args = extra_args;
-	file_arr = args->file_arr;
-	file_index = args->file_index;
+	args.out = out;
+	args.mls = mls;
 
-	if (node->parent->flavor == CIL_FALSE) {
-		fprintf(file_arr[*file_index], "}\n");
-	}
-	
-	return SEPOL_OK;
+	cil_block_te_rules_to_policy(out, head, mls);
+	cil_tree_walk(head, __cil_te_rules_to_policy_helper, NULL, NULL, &args);
 }
 
-int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node)
+static void cil_roles_to_policy(FILE *out, struct cil_list *rules)
 {
-	int rc = SEPOL_ERR;
-	struct cil_booleanif *bif = node->data;
-	struct cil_list *expr = bif->datum_expr;
-	struct cil_args_booleanif extra_args;
-	struct cil_tree_node *true_node = NULL;
-	struct cil_tree_node *false_node = NULL;
-	struct cil_condblock *cb = NULL;
+	struct cil_list_item *i1;
+	struct cil_role *role;
 
-	extra_args.file_arr = file_arr;
-	extra_args.file_index = &file_index;;
-
-	fprintf(file_arr[file_index], "if ");
-
-	rc = cil_expr_to_policy(file_arr, file_index, expr);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Failed to write expression\n");
-		return rc;
+	cil_list_for_each(i1, rules) {
+		role = i1->data;
+		if (strcmp(role->datum.fqn,"object_r") == 0)
+			continue;
+		fprintf(out, "role %s;\n", role->datum.fqn);
 	}
+}
 
-	if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) {
-		cb = node->cl_head->data;
-		if (cb->flavor == CIL_CONDTRUE) {
-			true_node = node->cl_head;
-		} else if (cb->flavor == CIL_CONDFALSE) {
-			false_node = node->cl_head;
+static void cil_role_types_to_policy(FILE *out, struct cil_list *roles, struct cil_list *types)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_role *role;
+	struct cil_type *type;
+	int first = CIL_TRUE;
+
+	cil_list_for_each(i1, roles) {
+		role = i1->data;
+		if (strcmp(role->datum.fqn,"object_r") == 0)
+			continue;
+		if (role->types) {
+			cil_list_for_each(i2, types) {
+				type = i2->data;
+				if (ebitmap_get_bit(role->types, type->value)) {
+					if (first) {
+						fprintf(out, "role %s types { %s", role->datum.fqn, type->datum.fqn);
+						first = CIL_FALSE;
+					} else {
+						fprintf(out, " %s", type->datum.fqn);
+					}
+				}
+			}
+			if (!first) {
+				fprintf(out, " }");
+				first = CIL_TRUE;
+			}
+			fprintf(out, ";\n");
 		}
 	}
+}
 
-	if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) {
-		cb = node->cl_head->next->data;
-		if (cb->flavor == CIL_CONDTRUE) {
-			true_node = node->cl_head->next;
-		} else if (cb->flavor == CIL_CONDFALSE) {
-			false_node = node->cl_head->next;
+static void cil_roleattributes_to_policy(FILE *out, struct cil_list *roles, struct cil_list *attributes)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_role *role;
+	struct cil_roleattribute *attribute;
+	int first = CIL_TRUE;
+
+	cil_list_for_each(i1, roles) {
+		role = i1->data;
+		if (strcmp(role->datum.fqn,"object_r") == 0)
+			continue;
+		cil_list_for_each(i2, attributes) {
+			attribute = i2->data;
+			if (ebitmap_get_bit(attribute->roles, role->value)) {
+				if (first) {
+					fprintf(out, "roleattribute %s %s", role->datum.fqn, attribute->datum.fqn);
+					first = CIL_FALSE;
+				} else {
+					fprintf(out, ", %s", attribute->datum.fqn);
+				}
+			}
 		}
-	}
-
-	fprintf(file_arr[file_index], "{\n");
-	if (true_node != NULL) {
-		rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc);
-			return rc;
+		if (!first) {
+			fprintf(out, ";\n");
+			first = CIL_TRUE;
 		}
 	}
-	fprintf(file_arr[file_index], "}\n");
+}
 
-	if (false_node != NULL) {
-		fprintf(file_arr[file_index], "else {\n");
-		rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc);
-			return rc;
-		}
-		fprintf(file_arr[file_index], "}\n");
-	}
+static void cil_roleallows_to_policy(FILE *out, struct cil_list *roleallows)
+{
+	struct cil_list_item *i1;
+	struct cil_roleallow *allow;
 
-	return SEPOL_OK;
+	cil_list_for_each(i1, roleallows) {
+		allow = i1->data;
+		fprintf(out, "allow %s %s;\n", DATUM(allow->src)->fqn, DATUM(allow->tgt)->fqn);
+	}
 }
 
-int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) 
+static void cil_roletransitions_to_policy(FILE *out, struct cil_list *roletransitions)
 {
-	uint32_t flavor = current->flavor;
-	int rc = SEPOL_ERR;
+	struct cil_list_item *i1, *i2;
+	struct cil_list *class_list;
+	struct cil_roletransition *trans;
 
-	switch(flavor) {
-	case CIL_TYPEATTRIBUTE:
-		fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	case CIL_TYPE:
-		fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	case CIL_TYPEALIAS: {
-		struct cil_alias *alias = current->data;
-		fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	}
-	case CIL_TYPEBOUNDS: {
-		struct cil_bounds *bnds = current->data;
-		fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str);
-		break;
-	}
-	case CIL_TYPEPERMISSIVE: {
-		struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data;
-		fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name);
-		break;
-	}
-	case CIL_ROLE:
-		fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	case CIL_BOOL: {
-		const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false";
-		fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean);
-		break;
-	}
-	case CIL_COMMON:
-		fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name);
 
-		if (current->cl_head != NULL) {
-			current = current->cl_head;
-			fprintf(file_arr[COMMONS], " {");
-		} else {
-			cil_log(CIL_INFO, "No permissions given\n");
-			return SEPOL_ERR;
+	cil_list_for_each(i1, roletransitions) {
+		trans = i1->data;
+		class_list = cil_expand_class(trans->obj);
+		cil_list_for_each(i2, class_list) {
+			fprintf(out, "role_transition %s %s : %s %s;\n", DATUM(trans->src)->fqn, DATUM(trans->tgt)->fqn, DATUM(i2->data)->fqn, DATUM(trans->result)->fqn);
 		}
+		cil_list_destroy(&class_list, CIL_FALSE);
+	}
+}
 
-		while (current != NULL) {
-			if (current->flavor == CIL_PERM) {
-				fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name);
-			} else {
-				cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor);
-				return SEPOL_ERR;
+static void cil_users_to_policy(FILE *out, int mls, struct cil_list *users, struct cil_list *all_roles)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_user *user;
+	struct cil_list *roles = NULL;
+	struct cil_role *role;
+	int num_roles;
+
+	cil_list_for_each(i1, users) {
+		user = i1->data;
+		num_roles = 0;
+		fprintf(out, "user %s",user->datum.fqn);
+		cil_list_for_each(i2, all_roles) {
+			role = i2->data;
+			if (ebitmap_get_bit(user->roles, role->value)) {
+				if (num_roles == 0) {
+					cil_list_init(&roles, CIL_LIST);
+				}
+				cil_list_append(roles, CIL_ROLE, role);
+				num_roles++;
+			}
+		}
+		if (num_roles > 0) {
+			fprintf(out, " roles");
+			if (num_roles > 1) {
+				fprintf(out, " {");
+			}
+			cil_list_for_each(i2, roles) {
+				role = i2->data;
+				fprintf(out, " %s", role->datum.fqn);
 			}
-			current = current->next;
+			if (num_roles > 1) {
+				fprintf(out, " }");
+			}
+			cil_list_destroy(&roles, CIL_FALSE);
 		}
-		fprintf(file_arr[COMMONS], "}\n");
-
-		return SEPOL_DONE;
-	case CIL_AVRULE: {
-		struct cil_avrule *avrule = (struct cil_avrule*)current->data;
-		rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "Failed to write avrule to policy\n");
-			return rc;
+
+		if (mls == CIL_TRUE && user->dftlevel != NULL) {
+			fprintf(out, " level ");
+			cil_level_to_policy(out, user->dftlevel);
 		}
-		break;
-	}
-	case CIL_TYPE_RULE: {
-		struct cil_type_rule *rule = (struct cil_type_rule*)current->data;
-		rc = cil_typerule_to_policy(file_arr, ALLOWS, rule);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "Failed to write type rule to policy\n");
-			return rc;
+
+		if (mls == CIL_TRUE && user->range != NULL) {
+			fprintf(out, " range ");
+			cil_levelrange_to_policy(out, user->range);
 		}
-		break;
+
+		fprintf(out,";\n");
 	}
-	case CIL_NAMETYPETRANSITION: {
-		struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data;
-		rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans);
-		if (rc != SEPOL_OK) {
-			cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n");
-			return rc;
+}
+
+static void cil_constrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *constrains)
+{
+	struct cil_list_item *i1, *i2;
+	struct cil_constrain *cons;
+	struct cil_list *classperms_strs;
+	char *cp_str;
+	char *expr_str;
+
+	cil_list_for_each(i1, constrains) {
+		cons = i1->data;
+		cil_list_init(&classperms_strs, CIL_LIST);
+		cil_classperms_to_strings(cons->classperms, classperms_strs);
+		expr_str = cil_cons_expr_to_string(db, cons->datum_expr);
+		cil_list_for_each(i2, classperms_strs) {
+			cp_str = i2->data;
+			fprintf(out, "constrain %s %s;\n",cp_str, expr_str);
+			free(cp_str);
 		}
+		free(expr_str);
+		cil_list_destroy(&classperms_strs, CIL_FALSE);
 	}
-	case CIL_ROLETRANSITION: {
-		struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data;
-		char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name;
-		char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name;
-		char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name;
-		char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name;
-		
-		fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str);
-		break;
-	}
-	case CIL_ROLEALLOW: {
-		struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data;
-		char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name;
-		char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name;
+}
 
-		fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str);
-		break;
-	}
-	case CIL_ROLETYPE: {
-		struct cil_roletype *roletype = (struct cil_roletype*)current->data;
-		char *role_str = ((struct cil_symtab_datum*)roletype->role)->name;
-		char *type_str = ((struct cil_symtab_datum*)roletype->type)->name;
+static void cil_sid_contexts_to_policy(FILE *out, struct cil_list *sids, int mls)
+{
+	struct cil_list_item *i1;
+	struct cil_sid *sid;
 
-		fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str);
-		break;
-	}
-	case CIL_LEVEL:
-		fprintf(file_arr[LEVELS], "level ");
-		cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data);
-			fprintf(file_arr[LEVELS], ";\n");
-			break;
-	case CIL_CONSTRAIN:
-		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
-		break;
-	case CIL_MLSCONSTRAIN:
-		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
-		break;
-	case CIL_VALIDATETRANS: {
-		struct cil_validatetrans *vt = current->data;
-		fprintf(file_arr[CONSTRAINS], "validatetrans");
-		fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name);
-		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
-		fprintf(file_arr[CONSTRAINS], ";\n");
-		break;
+	cil_list_for_each(i1, sids) {
+		sid = i1->data;
+		fprintf(out, "sid %s ", sid->datum.fqn);
+		cil_context_to_policy(out, sid->context, mls);
+		fprintf(out,"\n");
 	}
-	case CIL_MLSVALIDATETRANS: {
-		struct cil_validatetrans *vt = current->data;
-		fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans");
-		fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name);
-		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
-		fprintf(file_arr[CONSTRAINS], ";\n");
-		break;
+}
+
+static void cil_fsuses_to_policy(FILE *out, struct cil_sort *fsuses, int mls)
+{
+	unsigned i;
+	struct cil_fsuse *fsuse;
+
+	for (i=0; i<fsuses->count; i++) {
+		fsuse = fsuses->array[i];
+		if (fsuse->type == CIL_FSUSE_XATTR) {
+			fprintf(out, "fs_use_xattr %s ", fsuse->fs_str);
+			cil_context_to_policy(out, fsuse->context, mls);
+			fprintf(out,";\n");
+		}
 	}
-	case CIL_SID:
-		fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	case CIL_SIDCONTEXT: {
-		struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data;
-		fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str);
-		cil_context_to_policy(file_arr, SIDS, sidcon->context);
-		fprintf(file_arr[SIDS], "\n");
-		break;
+
+	for (i=0; i<fsuses->count; i++) {
+		fsuse = fsuses->array[i];
+		if (fsuse->type == CIL_FSUSE_TASK) {
+			fprintf(out, "fs_use_task %s ", fsuse->fs_str);
+			cil_context_to_policy(out, fsuse->context, mls);
+			fprintf(out,";\n");
+		}
 	}
-	case CIL_POLICYCAP:
-		fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name);
-		break;
-	default:
-		break;
+
+	for (i=0; i<fsuses->count; i++) {
+		fsuse = fsuses->array[i];
+		if (fsuse->type == CIL_FSUSE_TRANS) {
+			fprintf(out, "fs_use_trans %s ", fsuse->fs_str);
+			cil_context_to_policy(out, fsuse->context, mls);
+			fprintf(out,";\n");
+		}
 	}
+}
 
-	return SEPOL_OK;
+static void cil_genfscons_to_policy(FILE *out, struct cil_sort *genfscons, int mls)
+{
+	unsigned i;
+	struct cil_genfscon *genfscon;
+
+	for (i=0; i<genfscons->count; i++) {
+		genfscon = genfscons->array[i];
+		fprintf(out, "genfscon %s %s ", genfscon->fs_str, genfscon->path_str);
+		cil_context_to_policy(out, genfscon->context, mls);
+		fprintf(out, "\n");
+	}
 }
 
-int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls)
 {
-	int rc = SEPOL_ERR;
-	struct cil_args_genpolicy *args = NULL;
-	struct cil_list *users = NULL;
-	struct cil_list *sens = NULL;
-	struct cil_list *cats = NULL;
-	FILE **file_arr = NULL;
+	unsigned i;
+	struct cil_portcon *portcon;
 
-	if (extra_args == NULL) {
-		return SEPOL_ERR;
+	for (i=0; i<portcons->count; i++) {
+		portcon = portcons->array[i];
+		fprintf(out, "portcon ");
+		if (portcon->proto == CIL_PROTOCOL_UDP) {
+			fprintf(out, "udp ");
+		} else if (portcon->proto == CIL_PROTOCOL_TCP) {
+			fprintf(out, "tcp ");
+		} else if (portcon->proto == CIL_PROTOCOL_DCCP) {
+			fprintf(out, "dccp ");
+		}
+		if (portcon->port_low == portcon->port_high) {
+			fprintf(out, "%d ", portcon->port_low);
+		} else {
+			fprintf(out, "%d-%d ", portcon->port_low, portcon->port_high);
+		}
+		cil_context_to_policy(out, portcon->context, mls);
+		fprintf(out, "\n");
 	}
+}
 
-	*finished = CIL_TREE_SKIP_NOTHING;
+static void cil_netifcons_to_policy(FILE *out, struct cil_sort *netifcons, int mls)
+{
+	unsigned i;
+	struct cil_netifcon *netifcon;
 
-	args = extra_args;
-	users = args->users;
-	sens = args->sens;
-	cats = args->cats;
-	file_arr = args->file_arr;
+	for (i=0; i<netifcons->count; i++) {
+		netifcon = netifcons->array[i];
+		fprintf(out, "netifcon %s ", netifcon->interface_str);
+		cil_context_to_policy(out, netifcon->if_context, mls);
+		fprintf(out, " ");
+		cil_context_to_policy(out, netifcon->packet_context, mls);
+		fprintf(out, ";\n");
+	}
+}
 
-	if (node->cl_head != NULL) {
-		if (node->flavor == CIL_MACRO) {
-			*finished = CIL_TREE_SKIP_HEAD;
-			return SEPOL_OK;
-		}
+static void cil_nodecons_to_policy(FILE *out, struct cil_sort *nodecons, int mls)
+{
+	unsigned i;
+	struct cil_nodecon *nodecon;
+	char *addr, *mask;
 
-		if (node->flavor == CIL_BOOLEANIF) {
-			rc = cil_booleanif_to_policy(file_arr, CONDS, node);
-			if (rc != SEPOL_OK) {
-				cil_log(CIL_INFO, "Failed to write booleanif contents to file\n");
-				return rc;
-			}
-			*finished = CIL_TREE_SKIP_HEAD;
-			return SEPOL_OK;
-		}
+	for (i=0; i<nodecons->count; i++) {
+		nodecon = nodecons->array[i];
+		fprintf(out, "nodecon ");
 
-		if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) {
-			*finished = CIL_TREE_SKIP_HEAD;
-			return SEPOL_OK;
-		}
+		if (nodecon->addr->family == AF_INET) {
+			errno = 0;
+			addr = cil_malloc(INET_ADDRSTRLEN);
+			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, addr, INET_ADDRSTRLEN);
+			if (errno == 0) {
+				fprintf(out, "%s ",addr);
+			} else {
+				fprintf(out, "[INVALID] ");
+			}
+			free(addr);
 
-		if (node->flavor != CIL_ROOT) {
-			rc = cil_name_to_policy(file_arr, node);
-			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
-				cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor);
-				return SEPOL_ERR;
+			errno = 0;
+			mask = cil_malloc(INET_ADDRSTRLEN);
+			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, mask, INET_ADDRSTRLEN);
+			if (errno == 0) {
+				fprintf(out, "%s ",mask);
+			} else {
+				fprintf(out, "[INVALID] ");
 			}
-		}
-	} else {
-		switch (node->flavor) {
-		case CIL_USER:
-			cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
-			break;
-		case CIL_CATALIAS: {
-			struct cil_alias *alias = node->data;
-			struct cil_symtab_datum *datum = alias->actual;
-			cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
-		}
-			break;
-		case CIL_SENSALIAS: {
-			struct cil_alias *alias = node->data;
-			struct cil_symtab_datum *datum = alias->actual;
-			cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
-		}
-			break;
-		default:
-			rc = cil_name_to_policy(file_arr, node);
-			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
-				cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
-				return SEPOL_ERR;
+			free(mask);
+		} else {
+			errno = 0;
+			addr = cil_malloc(INET6_ADDRSTRLEN);
+			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, addr, INET6_ADDRSTRLEN);
+			if (errno == 0) {
+				fprintf(out, "%s ",addr);
+			} else {
+				fprintf(out, "[INVALID] ");
 			}
-			break;
+			free(addr);
+
+			errno = 0;
+			mask = cil_malloc(INET6_ADDRSTRLEN);
+			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, mask, INET6_ADDRSTRLEN);
+			if (errno == 0) {
+				fprintf(out, "%s ",mask);
+			} else {
+				fprintf(out, "[INVALID] ");
+			}
+			free(mask);
 		}
-	}
 
-	return SEPOL_OK;
+		cil_context_to_policy(out, nodecon->context, mls);
+		fprintf(out, ";\n");
+	}
 }
 
-int cil_gen_policy(struct cil_db *db)
+static void cil_pirqcons_to_policy(FILE *out, struct cil_sort *pirqcons, int mls)
 {
-	struct cil_tree_node *curr = db->ast->root;
-	struct cil_list_item *item;
-	int rc = SEPOL_ERR;
-	FILE *policy_file;
-	FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
-	char *file_path_arr[NUM_POLICY_FILES];
-	char temp[32];
-
-	struct cil_list *users = NULL;
-	struct cil_list *cats = NULL;
-	struct cil_list *sens = NULL;
-	struct cil_args_genpolicy extra_args;
-
-	cil_list_init(&users, CIL_LIST_ITEM);
-	cil_list_init(&cats, CIL_LIST_ITEM);
-	cil_list_init(&sens, CIL_LIST_ITEM);
-
-	strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
-	file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_isids-XXXXXX");
-	file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[ISIDS] = cil_strpool_add(temp);
-
-	strcpy(temp,"/tmp/cil_common-XXXXXX");
-	file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[COMMONS] = cil_strpool_add(temp);
-	
-	strcpy(temp, "/tmp/cil_class-XXXXXX");
-	file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[CLASSES] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_interf-XXXXXX");
-	file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[INTERFACES] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_sens-XXXXXX");
-	file_arr[SENS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[SENS] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_cats-XXXXXX");
-	file_arr[CATS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[CATS] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_levels-XXXXXX");
-	file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[LEVELS] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
-	file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
-	file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
-	
-	strcpy(temp, "/tmp/cil_aliases-XXXXXX");
-	file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[ALIASES] = cil_strpool_add(temp);
-	
-	strcpy(temp, "/tmp/cil_allows-XXXXXX");
-	file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[ALLOWS] = cil_strpool_add(temp);
-	
-	strcpy(temp, "/tmp/cil_conds-XXXXXX");
-	file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[CONDS] = cil_strpool_add(temp);
-	
-	strcpy(temp, "/tmp/cil_userroles-XXXXXX");
-	file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[USERROLES] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_sids-XXXXXX");
-	file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[SIDS] = cil_strpool_add(temp);
-
-	strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
-	file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
-	file_path_arr[NETIFCONS] = cil_strpool_add(temp);
-
-	policy_file = fopen("policy.conf", "w+");
-
-	cil_list_for_each(item, db->sidorder) {
-		fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
-	}
-
-	cil_list_for_each(item, db->classorder) {
-		struct cil_class *class = item->data;
-		struct cil_tree_node *node = class->datum.nodes->head->data;
-
-		fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
-
-		fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
-		if (class->common != NULL) {
-			fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
-		}
-		if (node->cl_head != NULL) {
-			struct cil_tree_node *curr_perm = node->cl_head;
-			fprintf(file_arr[CLASSES], "{ ");
-			while (curr_perm != NULL) {
-				fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
-				curr_perm = curr_perm->next;
-			}
-			fprintf(file_arr[CLASSES], "}");
-		}
-		fprintf(file_arr[CLASSES], "\n");
-	}
+	unsigned i;
+	struct cil_pirqcon *pirqcon;
 
-	if (db->catorder->head != NULL) {
-		cil_list_for_each(item, db->catorder) {
-			cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
-		}
+	for (i = 0; i<pirqcons->count; i++) {
+		pirqcon = pirqcons->array[i];
+		fprintf(out, "pirqcon %d ", pirqcon->pirq);
+		cil_context_to_policy(out, pirqcon->context, mls);
+		fprintf(out, ";\n");
 	}
+}
 
-	if (db->sensitivityorder->head != NULL) {
-		fprintf(file_arr[SENS], "sensitivityorder { ");
-		cil_list_for_each(item, db->sensitivityorder) {
-			fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
-		}
-		fprintf(file_arr[SENS], "};\n");
+static void cil_iomemcons_to_policy(FILE *out, struct cil_sort *iomemcons, int mls)
+{
+	unsigned i;
+	struct cil_iomemcon *iomemcon;
+
+	for (i = 0; i<iomemcons->count; i++) {
+		iomemcon = iomemcons->array[i];
+		fprintf(out, "iomemcon %" PRIu64 "-%" PRIu64 " ", iomemcon->iomem_low, iomemcon->iomem_high);
+		cil_context_to_policy(out, iomemcon->context, mls);
+		fprintf(out, ";\n");
 	}
+}
 
-	extra_args.users = users;
-	extra_args.sens = sens;
-	extra_args.cats = cats;
-	extra_args.file_arr= file_arr;
+static void cil_ioportcons_to_policy(FILE *out, struct cil_sort *ioportcons, int mls)
+{
+	unsigned i;
+	struct cil_ioportcon *ioportcon;
 
-	rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error walking tree\n");
-		return rc;
+	for (i = 0; i < ioportcons->count; i++) {
+		ioportcon = ioportcons->array[i];
+		fprintf(out, "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
+		cil_context_to_policy(out, ioportcon->context, mls);
+		fprintf(out, ";\n");
 	}
+}
 
-	rc = cil_netifcon_to_policy(file_arr, db->netifcon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
-	
-	rc = cil_genfscon_to_policy(file_arr, db->genfscon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
+static void cil_pcidevicecons_to_policy(FILE *out, struct cil_sort *pcidevicecons, int mls)
+{
+	unsigned i;
+	struct cil_pcidevicecon *pcidevicecon;
 
-	rc = cil_portcon_to_policy(file_arr, db->portcon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
+	for (i = 0; i < pcidevicecons->count; i++) {
+		pcidevicecon = pcidevicecons->array[i];
+		fprintf(out, "pcidevicecon %d ", pcidevicecon->dev);
+		cil_context_to_policy(out, pcidevicecon->context, mls);
+		fprintf(out, ";\n");
 	}
+}
 
-	rc = cil_nodecon_to_policy(file_arr, db->nodecon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
+static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreecons, int mls)
+{
+	unsigned i;
+	struct cil_devicetreecon *devicetreecon;
 
-	rc = cil_fsuse_to_policy(file_arr, db->fsuse);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
+	for (i = 0; i < devicetreecons->count; i++) {
+		devicetreecon = devicetreecons->array[i];
+		fprintf(out, "devicetreecon %s ", devicetreecon->path);
+		cil_context_to_policy(out, devicetreecon->context, mls);
+		fprintf(out, ";\n");
 	}
+}
 
-	rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
+void cil_gen_policy(FILE *out, struct cil_db *db)
+{
+	unsigned i;
+	struct cil_tree_node *head = db->ast->root;
+	struct cil_list *lists[CIL_LIST_NUM_LISTS];
 
-	rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
+	for (i=0; i<CIL_LIST_NUM_LISTS; i++) {
+		cil_list_init(&lists[i], CIL_LIST);
 	}
 
-	rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
+	cil_gather_statements(head, lists);
 
-	rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return rc;
-	}
+	cil_class_decls_to_policy(out, db->classorder);
 
-	rc = cil_userrole_to_policy(file_arr, users);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return SEPOL_ERR;
-	}
+	cil_sid_decls_to_policy(out, db->sidorder);
 
-	rc = cil_sens_to_policy(file_arr, sens);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return SEPOL_ERR;
-	}
+	cil_commons_to_policy(out, lists[CIL_LIST_COMMON]);
+	cil_classes_to_policy(out, db->classorder);
 
-	rc = cil_cat_to_policy(file_arr, cats);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return SEPOL_ERR;
-	}
+	cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_USER], CIL_KEY_DEFAULTUSER);
+	cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_ROLE], CIL_KEY_DEFAULTROLE);
+	cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_TYPE], CIL_KEY_DEFAULTTYPE);
 
-	rc = cil_combine_policy(file_arr, policy_file);
-	if (rc != SEPOL_OK) {
-		cil_log(CIL_ERR, "Error creating policy.conf\n");
-		return SEPOL_ERR;
+	if (db->mls == CIL_TRUE) {
+		cil_default_ranges_to_policy(out, lists[CIL_LIST_DEFAULT_RANGE]);
+		cil_sensitivities_to_policy(out, db->sensitivityorder, lists[CIL_LIST_SENSALIAS]);
+		cil_dominance_to_policy(out, db->sensitivityorder);
+		cil_categories_to_policy(out, db->catorder, lists[CIL_LIST_CATALIAS]);
+		cil_levels_to_policy(out, db->sensitivityorder);
+		cil_mlsconstrains_to_policy(out, db, lists[CIL_LIST_MLSCONSTRAIN]);
+		cil_validatetrans_to_policy(out, db, lists[CIL_LIST_MLSVALIDATETRANS], CIL_KEY_MLSVALIDATETRANS);
 	}
 
-	// Remove temp files
-	int i;
-	for (i=0; i<NUM_POLICY_FILES; i++) {
-		rc = fclose(file_arr[i]);
-		if (rc != 0) {
-			cil_log(CIL_ERR, "Error closing temporary file\n");
-			return SEPOL_ERR;
-		}
-		rc = unlink(file_path_arr[i]);
-		if (rc != 0) {
-			cil_log(CIL_ERR, "Error unlinking temporary files\n");
-			return SEPOL_ERR;
-		}
-	}
+	cil_simple_rules_to_policy(out, lists[CIL_LIST_POLICYCAP], CIL_KEY_POLICYCAP);
+
+	cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPEATTRIBUTE], "attribute");
+	cil_simple_rules_to_policy(out, lists[CIL_LIST_ROLEATTRIBUTE], "attribute_role");
 
-	rc = fclose(policy_file);
-	if (rc != 0) {
-		cil_log(CIL_ERR, "Error closing policy.conf\n");
-		return SEPOL_ERR;
+	cil_bools_to_policy(out, lists[CIL_LIST_BOOL]);
+
+	cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPE], "type");
+	cil_typealiases_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEALIAS]);
+	cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]);
+	cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]);
+	cil_te_rules_to_policy(out, head, db->mls);
+
+	cil_roles_to_policy(out, lists[CIL_LIST_ROLE]);
+	cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]);
+	cil_roleattributes_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_ROLEATTRIBUTE]);
+	cil_roleallows_to_policy(out, lists[CIL_LIST_ROLEALLOW]);
+	cil_roletransitions_to_policy(out, lists[CIL_LIST_ROLETRANSITION]);
+
+	cil_users_to_policy(out, db->mls, lists[CIL_LIST_USER], lists[CIL_LIST_ROLE]);
+
+	cil_constrains_to_policy(out, db, lists[CIL_LIST_CONSTRAINT]);
+	cil_validatetrans_to_policy(out, db, lists[CIL_LIST_VALIDATETRANS], CIL_KEY_VALIDATETRANS);
+
+	cil_sid_contexts_to_policy(out, db->sidorder, db->mls);
+	cil_fsuses_to_policy(out, db->fsuse, db->mls);
+	cil_genfscons_to_policy(out, db->genfscon, db->mls);
+	cil_portcons_to_policy(out, db->portcon, db->mls);
+	cil_netifcons_to_policy(out, db->netifcon, db->mls);
+	cil_nodecons_to_policy(out, db->nodecon, db->mls);
+	cil_pirqcons_to_policy(out, db->pirqcon, db->mls);
+	cil_iomemcons_to_policy(out, db->iomemcon, db->mls);
+	cil_ioportcons_to_policy(out, db->ioportcon, db->mls);
+	cil_pcidevicecons_to_policy(out, db->pcidevicecon, db->mls);
+	cil_devicetreecons_to_policy(out, db->devicetreecon, db->mls);
+
+	for (i=0; i<CIL_LIST_NUM_LISTS; i++) {
+		cil_list_destroy(&lists[i], CIL_FALSE);
 	}
-	free(file_arr);
-	
-	cil_list_destroy(&users, CIL_FALSE);
-	cil_list_destroy(&cats, CIL_FALSE);
-	cil_list_destroy(&sens, CIL_FALSE);
-	
-	return SEPOL_OK;
+
 }
diff --git a/libsepol/cil/src/cil_policy.h b/libsepol/cil/src/cil_policy.h
index 72cf162..d9c0a4b 100644
--- a/libsepol/cil/src/cil_policy.h
+++ b/libsepol/cil/src/cil_policy.h
@@ -30,18 +30,8 @@ 
 #ifndef CIL_POLICY_H_
 #define CIL_POLICY_H_
 
-#include "cil_tree.h"
-#include "cil_list.h"
 #include "cil_internal.h"
 
-struct cil_multimap_item {
-	struct cil_symtab_datum *key;
-	struct cil_list *values;
-};
-
-int cil_combine_policy(FILE **file_arr, FILE *policy_file);
-void cil_context_to_policy(FILE **, uint32_t, struct cil_context *);
-int cil_name_to_policy(FILE **, struct cil_tree_node *);
-int cil_gen_policy(struct cil_db *);
+void cil_gen_policy(FILE *out, struct cil_db *db);
 
 #endif
diff --git a/libsepol/src/libsepol.map.in b/libsepol/src/libsepol.map.in
index 9683caf..47a4440 100644
--- a/libsepol/src/libsepol.map.in
+++ b/libsepol/src/libsepol.map.in
@@ -45,6 +45,7 @@  LIBSEPOL_1.1 {
 	cil_set_target_platform;
 	cil_set_policy_version;
 	cil_set_mls;
+	cil_write_policy_conf;
 	sepol_ppfile_to_module_package;
 	sepol_module_package_to_cil;
 	sepol_module_policydb_to_cil;