diff mbox

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

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

Commit Message

James Carter Nov. 22, 2016, 7:18 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(-)

Comments

Nicolas Iooss Nov. 22, 2016, 8:55 p.m. UTC | #1
On Tue, Nov 22, 2016 at 8:18 PM, James Carter <jwcart2@tycho.nsa.gov> wrote:

> 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.


Hello,
When building with clang and some warning flags, this commit introduces
some warnings (treated as errors because of -Werror). These warnings are
not reported by gcc, which compiles everything fine.

First, there are many:
../cil/src/cil_policy.c:867:21: error: variable 'aliases' may be
uninitialized when used here [-Werror,-Wconditional-uninitialized]
                                cil_list_append(aliases, CIL_SENSALIAS,
alias);
                                                ^~~~~~~

This is because the compiler is not smart enough to find the link between
num_aliases and aliases and that cil_list_init() never returns if it failed
to allocate "aliases". Could you please initialize aliases to NULL on
lines 867, 907 and 1025 and roles on line 1588, as well as first and last
to zero in cil_xperms_to_policy()?

Secondly:
../cil/src/cil_policy.c:1132:28: error: format specifies type 'unsigned
short' but the argument has type 'unsigned int' [-Werror,-Wformat]
                                fprintf(out, " 0x%hx", first);
                                                 ~~~   ^~~~~
                                                 %x

Why is "h" prefix used to format variables of type "int"?

The full compiler output is available in
https://travis-ci.org/fishilico/selinux/jobs/178096652 .

Nicolas
James Carter Nov. 28, 2016, 7:15 p.m. UTC | #2
On 11/22/2016 03:55 PM, Nicolas Iooss wrote:
> On Tue, Nov 22, 2016 at 8:18 PM, James Carter <jwcart2@tycho.nsa.gov
> <mailto:jwcart2@tycho.nsa.gov>> wrote:
>
>     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.
>
>
> Hello,
> When building with clang and some warning flags, this commit introduces some
> warnings (treated as errors because of -Werror). These warnings are not reported
> by gcc, which compiles everything fine.
>
> First, there are many:
> ../cil/src/cil_policy.c:867:21: error: variable 'aliases' may be uninitialized
> when used here [-Werror,-Wconditional-uninitialized]
>                                 cil_list_append(aliases, CIL_SENSALIAS, alias);
>                                                 ^~~~~~~
>
> This is because the compiler is not smart enough to find the link between
> num_aliases and aliases and that cil_list_init() never returns if it failed to
> allocate "aliases". Could you please initialize aliases to NULL on lines 867,
> 907 and 1025 and roles on line 1588, as well as first and last to zero
> in cil_xperms_to_policy()?
>

I will add initializations for these.

> Secondly:
> ../cil/src/cil_policy.c:1132:28: error: format specifies type 'unsigned short'
> but the argument has type 'unsigned int' [-Werror,-Wformat]
>                                 fprintf(out, " 0x%hx", first);
>                                                  ~~~   ^~~~~
>                                                  %x
>
> Why is "h" prefix used to format variables of type "int"?
>

It shouldn't. I copied code from module_to_cil.c which was printing uint16_t 
variables.

Jim

> The full compiler output is available
> in https://travis-ci.org/fishilico/selinux/jobs/178096652 .
>
> Nicolas
>
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..26c0d14 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;
+	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;
+	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;
+	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, last;
+	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%hx", 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%hx-0x%hx", first, last);
+			} else {
+				fprintf(out, " 0x%hx 0x%hx", first, last);
 			}
+			first = i;
+			need_last = CIL_TRUE;
 		}
 	}
+	if (need_first == CIL_FALSE) {
+		if (need_last == CIL_FALSE) {
+			fprintf(out, " 0x%hx-0x%hx", first, last);
+		} else {
+			fprintf(out, " 0x%hx", 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;
+	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;