Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright 2011 Tresys Technology, LLC. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      7  *    1. Redistributions of source code must retain the above copyright notice,
      8  *       this list of conditions and the following disclaimer.
      9  *
     10  *    2. Redistributions in binary form must reproduce the above copyright notice,
     11  *       this list of conditions and the following disclaimer in the documentation
     12  *       and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
     15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     17  * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  *
     25  * The views and conclusions contained in the software and documentation are those
     26  * of the authors and should not be interpreted as representing official policies,
     27  * either expressed or implied, of Tresys Technology, LLC.
     28  */
     29 
     30 #include <stdlib.h>
     31 #include <stdio.h>
     32 #include <string.h>
     33 #include <stdint.h>
     34 #include <unistd.h>
     35 #include <inttypes.h>
     36 
     37 #include <sepol/policydb/conditional.h>
     38 #include <sepol/errcodes.h>
     39 
     40 #include "cil_internal.h"
     41 #include "cil_flavor.h"
     42 #include "cil_log.h"
     43 #include "cil_mem.h"
     44 #include "cil_tree.h"
     45 #include "cil_list.h"
     46 #include "cil_policy.h"
     47 #include "cil_symtab.h"
     48 #include "cil_strpool.h"
     49 
     50 #define SEPOL_DONE			555
     51 
     52 #define CLASS_DECL			0
     53 #define ISIDS				1
     54 #define COMMONS				2
     55 #define CLASSES				3
     56 #define INTERFACES			4
     57 #define SENS				5
     58 #define CATS				6
     59 #define LEVELS				7
     60 #define CONSTRAINS			8
     61 #define TYPEATTRTYPES			9
     62 #define ALIASES				10
     63 #define ALLOWS				11
     64 #define CONDS				12
     65 #define USERROLES			13
     66 #define SIDS				14
     67 #define NETIFCONS			15
     68 
     69 #define BUFFER				1024
     70 #define NUM_POLICY_FILES		16
     71 
     72 struct cil_args_genpolicy {
     73 	struct cil_list *users;
     74 	struct cil_list *sens;
     75 	struct cil_list *cats;
     76 	FILE **file_arr;
     77 };
     78 
     79 struct cil_args_booleanif {
     80 	FILE **file_arr;
     81 	uint32_t *file_index;
     82 };
     83 
     84 
     85 int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
     86 
     87 int cil_combine_policy(FILE **file_arr, FILE *policy_file)
     88 {
     89 	char temp[BUFFER];
     90 	int i, rc, rc_read, rc_write;
     91 
     92 	for(i=0; i<NUM_POLICY_FILES; i++) {
     93 		fseek(file_arr[i], 0, SEEK_SET);
     94 		while (!feof(file_arr[i])) {
     95 			rc_read = fread(temp, 1, BUFFER, file_arr[i]);
     96 			if (rc_read == 0 && ferror(file_arr[i])) {
     97 				cil_log(CIL_ERR, "Error reading temp policy file\n");
     98 				return SEPOL_ERR;
     99 			}
    100 			rc_write = 0;
    101 			while (rc_read > rc_write) {
    102 				rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file);
    103 				rc_write += rc;
    104 				if (rc == 0 && ferror(file_arr[i])) {
    105 					cil_log(CIL_ERR, "Error writing to policy.conf\n");
    106 					return SEPOL_ERR;
    107 				}
    108 			}
    109 		}
    110 	}
    111 
    112 	return SEPOL_OK;
    113 }
    114 
    115 int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort)
    116 {
    117 	uint32_t i = 0;
    118 
    119 	for (i=0; i<sort->count; i++) {
    120 		struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i];
    121 		fprintf(file_arr[NETIFCONS], "portcon ");
    122 		if (portcon->proto == CIL_PROTOCOL_UDP) {
    123 			fprintf(file_arr[NETIFCONS], "udp ");
    124 		} else if (portcon->proto == CIL_PROTOCOL_TCP) {
    125 			fprintf(file_arr[NETIFCONS], "tcp ");
    126 		}
    127 		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low);
    128 		fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high);
    129 		cil_context_to_policy(file_arr, NETIFCONS, portcon->context);
    130 		fprintf(file_arr[NETIFCONS], ";\n");
    131 	}
    132 
    133 	return SEPOL_OK;
    134 }
    135 
    136 int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort)
    137 {
    138 	uint32_t i = 0;
    139 
    140 	for (i=0; i<sort->count; i++) {
    141 		struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i];
    142 		fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str);
    143 		fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str);
    144 		cil_context_to_policy(file_arr, NETIFCONS, genfscon->context);
    145 		fprintf(file_arr[NETIFCONS], ";\n");
    146 	}
    147 
    148 	return SEPOL_OK;
    149 }
    150 
    151 int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort)
    152 {
    153 	uint32_t i = 0;
    154 
    155 	for (i=0; i<sort->count; i++) {
    156 		struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i];
    157 		fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str);
    158 		cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context);
    159 		fprintf(file_arr[NETIFCONS], " ");
    160 		cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context);
    161 		fprintf(file_arr[NETIFCONS], ";\n");
    162 	}
    163 
    164 	return SEPOL_OK;
    165 }
    166 
    167 int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort)
    168 {
    169 	uint32_t i = 0;
    170 	int rc = SEPOL_ERR;
    171 
    172 	for (i=0; i<sort->count; i++) {
    173 		struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i];
    174 		char *buf = NULL;
    175 		errno = 0;
    176 		if (nodecon->addr->family == AF_INET) {
    177 			buf = cil_malloc(INET_ADDRSTRLEN);
    178 			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN);
    179 		} else if (nodecon->addr->family == AF_INET6) {
    180 			buf = cil_malloc(INET6_ADDRSTRLEN);
    181 			inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN);
    182 		}
    183 
    184 		if (errno != 0) {
    185 			cil_log(CIL_INFO, "Failed to convert ip address to string\n");
    186 			rc = SEPOL_ERR;
    187 			goto exit;
    188 		}
    189 
    190 		fprintf(file_arr[NETIFCONS], "nodecon %s ", buf);
    191 		free(buf);
    192 
    193 		if (nodecon->mask->family == AF_INET) {
    194 			buf = cil_malloc(INET_ADDRSTRLEN);
    195 			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN);
    196 		} else if (nodecon->mask->family == AF_INET6) {
    197 			buf = cil_malloc(INET6_ADDRSTRLEN);
    198 			inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN);
    199 		}
    200 
    201 		if (errno != 0) {
    202 			cil_log(CIL_INFO, "Failed to convert mask to string\n");
    203 			rc = SEPOL_ERR;
    204 			goto exit;
    205 		}
    206 
    207 		fprintf(file_arr[NETIFCONS], "%s ", buf);
    208 		free(buf);
    209 
    210 		cil_context_to_policy(file_arr, NETIFCONS, nodecon->context);
    211 		fprintf(file_arr[NETIFCONS], ";\n");
    212 	}
    213 
    214 	return SEPOL_OK;
    215 
    216 exit:
    217 	return rc;
    218 }
    219 
    220 
    221 int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort)
    222 {
    223 	uint32_t i = 0;
    224 
    225 	for (i = 0; i < sort->count; i++) {
    226 		struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i];
    227 		fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq);
    228 		cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context);
    229 		fprintf(file_arr[NETIFCONS], ";\n");
    230 	}
    231 
    232 	return SEPOL_OK;
    233 }
    234 int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort)
    235 {
    236 	uint32_t i = 0;
    237 
    238 	for (i = 0; i < sort->count; i++) {
    239 		struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i];
    240 		fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high);
    241 		cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context);
    242 		fprintf(file_arr[NETIFCONS], ";\n");
    243 	}
    244 
    245 	return SEPOL_OK;
    246 }
    247 
    248 int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort)
    249 {
    250 	uint32_t i = 0;
    251 
    252 	for (i = 0; i < sort->count; i++) {
    253 		struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i];
    254 		fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
    255 		cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context);
    256 		fprintf(file_arr[NETIFCONS], ";\n");
    257 	}
    258 
    259 	return SEPOL_OK;
    260 }
    261 
    262 int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort)
    263 {
    264 	uint32_t i = 0;
    265 
    266 	for (i = 0; i < sort->count; i++) {
    267 		struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i];
    268 		fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev);
    269 		cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context);
    270 		fprintf(file_arr[NETIFCONS], ";\n");
    271 	}
    272 
    273 	return SEPOL_OK;
    274 }
    275 
    276 int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort)
    277 {
    278 	uint32_t i = 0;
    279 
    280 	for (i=0; i<sort->count; i++) {
    281 		struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i];
    282 		if (fsuse->type == CIL_FSUSE_XATTR) {
    283 			fprintf(file_arr[NETIFCONS], "fs_use_xattr ");
    284 		} else if (fsuse->type == CIL_FSUSE_TASK) {
    285 			fprintf(file_arr[NETIFCONS], "fs_use_task ");
    286 		} else if (fsuse->type == CIL_FSUSE_TRANS) {
    287 			fprintf(file_arr[NETIFCONS], "fs_use_trans ");
    288 		} else {
    289 			return SEPOL_ERR;
    290 		}
    291 		fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str);
    292 		cil_context_to_policy(file_arr, NETIFCONS, fsuse->context);
    293 		fprintf(file_arr[NETIFCONS], ";\n");
    294 	}
    295 
    296 	return SEPOL_OK;
    297 }
    298 
    299 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)
    300 {
    301 	struct cil_list_item *curr_key;
    302 	struct cil_multimap_item *new_data;
    303 
    304 	if (list == NULL || key == NULL) {
    305 		return SEPOL_ERR;
    306 	}
    307 
    308 	cil_list_for_each(curr_key, list) {
    309 		struct cil_multimap_item *curr_multimap_item = curr_key->data;
    310 		if (curr_multimap_item != NULL) {
    311 			if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) {
    312 				struct cil_list_item *curr_value;
    313 				cil_list_for_each(curr_value, curr_multimap_item->values) {
    314 					if (curr_value == (struct cil_list_item*)value) {
    315 						return SEPOL_OK;;
    316 					}
    317 				}
    318 				cil_list_append(curr_multimap_item->values, val_flavor, value);
    319 			}
    320 		} else {
    321 			cil_log(CIL_INFO, "No data in list item\n");
    322 			return SEPOL_ERR;
    323 		}
    324 	}
    325 
    326 	new_data = cil_malloc(sizeof(*new_data));
    327 	new_data->key = key;
    328 	cil_list_init(&new_data->values, CIL_LIST_ITEM);
    329 	if (value != NULL) {
    330 		cil_list_append(new_data->values, val_flavor, value);
    331 	}
    332 	cil_list_append(list, key_flavor, new_data);
    333 
    334 	return SEPOL_OK;
    335 }
    336 
    337 int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles)
    338 {
    339 	struct cil_list_item *current_user;
    340 
    341 	if (userroles == NULL) {
    342 		return SEPOL_OK;
    343 	}
    344 
    345 	cil_list_for_each(current_user, userroles) {
    346 		struct cil_multimap_item *user_multimap_item = current_user->data;
    347 		struct cil_list_item *current_role;
    348 		if (user_multimap_item->values->head == NULL) {
    349 			cil_log(CIL_INFO, "No roles associated with user %s\n",
    350 					user_multimap_item->key->name);
    351 			return SEPOL_ERR;
    352 		}
    353 
    354 		fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name);
    355 
    356 		cil_list_for_each(current_role, user_multimap_item->values) {
    357 			fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name);
    358 		}
    359 		fprintf(file_arr[USERROLES], " };\n");
    360 	}
    361 
    362 	return SEPOL_OK;
    363 }
    364 
    365 int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats)
    366 {
    367 	struct cil_list_item *curr_cat;
    368 
    369 	if (cats == NULL) {
    370 		return SEPOL_OK;
    371 	}
    372 
    373 	cil_list_for_each(curr_cat, cats) {
    374 		struct cil_multimap_item *cat_multimap_item = curr_cat->data;
    375 		fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name);
    376 		if (cat_multimap_item->values->head == NULL) {
    377 			fprintf(file_arr[CATS], ";\n");
    378 		} else {
    379 			struct cil_list_item *curr_catalias;
    380 			fprintf(file_arr[CATS], " alias");
    381 			cil_list_for_each(curr_catalias, cat_multimap_item->values) {
    382 				fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name);
    383 			}
    384 			fprintf(file_arr[CATS], ";\n");
    385 		}
    386 	}
    387 
    388 	return SEPOL_OK;
    389 }
    390 
    391 int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens)
    392 {
    393 	struct cil_list_item *curr_sens;
    394 
    395 	if (sens == NULL) {
    396 		return SEPOL_OK;
    397 	}
    398 
    399 	cil_list_for_each(curr_sens, sens) {
    400 		struct cil_multimap_item *sens_multimap_item = curr_sens->data;
    401 		fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name);
    402 		if (sens_multimap_item->values->head == NULL)
    403 			fprintf(file_arr[SENS], ";\n");
    404 		else {
    405 			struct cil_list_item *curr_sensalias;
    406 			fprintf(file_arr[SENS], " alias");
    407 			cil_list_for_each(curr_sensalias, sens_multimap_item->values) {
    408 				fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name);
    409 			}
    410 			fprintf(file_arr[SENS], ";\n");
    411 		}
    412 	}
    413 
    414 	return SEPOL_OK;
    415 }
    416 
    417 void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats)
    418 {
    419 	cil_expr_to_policy(file_arr, file_index, cats->datum_expr);
    420 }
    421 
    422 void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level)
    423 {
    424 	char *sens_str = level->sens->datum.name;
    425 
    426 	fprintf(file_arr[file_index], "%s", sens_str);
    427 	if (level->cats != NULL) {
    428 		fprintf(file_arr[file_index], ":");
    429 		cil_cats_to_policy(file_arr, file_index, level->cats);
    430 	}
    431 }
    432 
    433 void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange)
    434 {
    435 	struct cil_level *low = lvlrange->low;
    436 	struct cil_level *high = lvlrange->high;
    437 
    438 	cil_level_to_policy(file_arr, file_index, low);
    439 	fprintf(file_arr[file_index], "-");
    440 	cil_level_to_policy(file_arr, file_index, high);
    441 }
    442 
    443 void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context)
    444 {
    445 	char *user_str = ((struct cil_symtab_datum*)context->user)->name;
    446 	char *role_str = ((struct cil_symtab_datum*)context->role)->name;
    447 	char *type_str = ((struct cil_symtab_datum*)context->type)->name;
    448 	struct cil_levelrange *lvlrange = context->range;
    449 
    450 	fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str);
    451 	cil_levelrange_to_policy(file_arr, file_index, lvlrange);
    452 }
    453 
    454 void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list)
    455 {
    456 	struct cil_list_item *curr;
    457 
    458 	fprintf(file_arr[file_index], " {");
    459 	cil_list_for_each(curr, list) {
    460 		switch (curr->flavor) {
    461 		case CIL_LIST:
    462 			cil_perms_to_policy(file_arr, file_index, curr->data);
    463 			break;
    464 		case CIL_STRING:
    465 			fprintf(file_arr[file_index], " %s", (char *)curr->data);
    466 			break;
    467 		case CIL_DATUM:
    468 			fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name);
    469 			break;
    470 		case CIL_OP: {
    471 			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
    472 			char *op_str = NULL;
    473 
    474 			switch (op_flavor) {
    475 			case CIL_AND:
    476 				op_str = CIL_KEY_AND;
    477 				break;
    478 			case CIL_OR:
    479 				op_str = CIL_KEY_OR;
    480 				break;
    481 			case CIL_NOT:
    482 				op_str = CIL_KEY_NOT;
    483 				break;
    484 			case CIL_ALL:
    485 				op_str = CIL_KEY_ALL;
    486 				break;
    487 			case CIL_XOR:
    488 				op_str = CIL_KEY_XOR;
    489 				break;
    490 			default:
    491 				cil_log(CIL_ERR, "Unknown operator in expression\n");
    492 				break;
    493 			}
    494 			fprintf(file_arr[file_index], " %s", op_str);
    495 			break;
    496 		}
    497 		default:
    498 			cil_log(CIL_ERR, "Unknown flavor in expression\n");
    499 			break;
    500 		}
    501 	}
    502 	fprintf(file_arr[file_index], " }");
    503 }
    504 
    505 void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr)
    506 {
    507 	struct cil_list_item *curr;
    508 
    509 	cil_list_for_each(curr, classperms) {
    510 		if (curr->flavor == CIL_CLASSPERMS) {
    511 			struct cil_classperms *cp = curr->data;
    512 			if (FLAVOR(cp->class) == CIL_CLASS) {
    513 				fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name);
    514 				cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms);
    515 				fprintf(file_arr[CONSTRAINS], "\n\t");
    516 				cil_expr_to_policy(file_arr, CONSTRAINS, expr);
    517 				fprintf(file_arr[CONSTRAINS], ";\n");
    518 			} else { /* MAP */
    519 				struct cil_list_item *i = NULL;
    520 				cil_list_for_each(i, cp->perms) {
    521 					struct cil_perm *cmp = i->data;
    522 					cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr);
    523 				}
    524 			}
    525 		} else { /* SET */
    526 			struct cil_classperms_set *cp_set = curr->data;
    527 			struct cil_classpermission *cp = cp_set->set;
    528 			cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr);
    529 		}
    530 	}
    531 }
    532 
    533 void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor)
    534 {
    535 	char *kind = NULL;
    536 
    537 	if (flavor == CIL_CONSTRAIN) {
    538 		kind = CIL_KEY_CONSTRAIN;
    539 	} else if (flavor == CIL_MLSCONSTRAIN) {
    540 		kind = CIL_KEY_MLSCONSTRAIN;
    541 	}
    542 
    543 	cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr);
    544 }
    545 
    546 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)
    547 {
    548 	struct cil_list_item *i;
    549 
    550 	cil_list_for_each(i, classperms) {
    551 		if (i->flavor == CIL_CLASSPERMS) {
    552 			struct cil_classperms *cp = i->data;
    553 			if (FLAVOR(cp->class) == CIL_CLASS) {
    554 				fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name);
    555 				cil_perms_to_policy(file_arr, file_index, cp->perms);
    556 				fprintf(file_arr[file_index], ";\n");
    557 			} else { /* MAP */
    558 				struct cil_list_item *j = NULL;
    559 				cil_list_for_each(j, cp->perms) {
    560 					struct cil_perm *cmp = j->data;
    561 					cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms);
    562 				}
    563 			}
    564 		} else { /* SET */
    565 			struct cil_list_item *j;
    566 			struct cil_classperms_set *cp_set = i->data;
    567 			struct cil_classpermission *cp = cp_set->set;
    568 			cil_list_for_each(j, cp->classperms) {
    569 				cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data);
    570 			}
    571 		}
    572 	}
    573 }
    574 
    575 int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule)
    576 {
    577 	const char *kind_str = NULL;
    578 	const char *src_str = DATUM(rule->src)->name;
    579 	const char *tgt_str = DATUM(rule->tgt)->name;
    580 
    581 
    582 	switch (rule->rule_kind) {
    583 	case CIL_AVRULE_ALLOWED:
    584 		kind_str = "allow";
    585 		break;
    586 	case CIL_AVRULE_AUDITALLOW:
    587 		kind_str = "auditallow";
    588 		break;
    589 	case CIL_AVRULE_DONTAUDIT:
    590 		kind_str = "dontaudit";
    591 		break;
    592 	case CIL_AVRULE_NEVERALLOW:
    593 		kind_str = "neverallow";
    594 		break;
    595 	default :
    596 		cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n",
    597 				rule->rule_kind, src_str, tgt_str);
    598 		return SEPOL_ERR;
    599 	}
    600 
    601 	cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->classperms);
    602 
    603 	return SEPOL_OK;
    604 }
    605 
    606 int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule)
    607 {
    608 	char *src_str = ((struct cil_symtab_datum*)rule->src)->name;
    609 	char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name;
    610 	char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name;
    611 	char *result_str = ((struct cil_symtab_datum*)rule->result)->name;
    612 
    613 	switch (rule->rule_kind) {
    614 	case CIL_TYPE_TRANSITION:
    615 		fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
    616 		break;
    617 	case CIL_TYPE_CHANGE:
    618 		fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str);
    619 		break;
    620 	case CIL_TYPE_MEMBER:
    621 		fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
    622 		break;
    623 	default:
    624 		cil_log(CIL_INFO, "Unknown type_rule\n");
    625 		return SEPOL_ERR;
    626 	}
    627 
    628 	return SEPOL_OK;
    629 }
    630 
    631 int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans)
    632 {
    633 	char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name;
    634 	char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name;
    635 	char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name;
    636 	char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name;
    637 
    638 	fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str);
    639 	return SEPOL_OK;
    640 }
    641 
    642 static int cil_expr_to_string(struct cil_list *expr, char **out)
    643 {
    644 	int rc = SEPOL_ERR;
    645 	struct cil_list_item *curr;
    646 	char *stack[COND_EXPR_MAXDEPTH] = {};
    647 	int pos = 0;
    648 	int i;
    649 
    650 	cil_list_for_each(curr, expr) {
    651 		if (pos > COND_EXPR_MAXDEPTH) {
    652 			rc = SEPOL_ERR;
    653 			goto exit;
    654 		}
    655 		switch (curr->flavor) {
    656 		case CIL_LIST:
    657 			rc = cil_expr_to_string(curr->data, &stack[pos]);
    658 			if (rc != SEPOL_OK) {
    659 				goto exit;
    660 			}
    661 			pos++;
    662 			break;
    663 		case CIL_STRING:
    664 			stack[pos] = curr->data;
    665 			pos++;
    666 			break;
    667 		case CIL_DATUM:
    668 			stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
    669 			pos++;
    670 			break;
    671 		case CIL_OP: {
    672 			int len;
    673 			char *expr_str;
    674 			enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
    675 			char *op_str = NULL;
    676 
    677 			if (pos == 0) {
    678 				rc = SEPOL_ERR;
    679 				goto exit;
    680 			}
    681 			switch (op_flavor) {
    682 			case CIL_AND:
    683 				op_str = CIL_KEY_AND;
    684 				break;
    685 			case CIL_OR:
    686 				op_str = CIL_KEY_OR;
    687 				break;
    688 			case CIL_NOT:
    689 				op_str = CIL_KEY_NOT;
    690 				break;
    691 			case CIL_ALL:
    692 				op_str = CIL_KEY_ALL;
    693 				break;
    694 			case CIL_EQ:
    695 				op_str = CIL_KEY_EQ;
    696 				break;
    697 			case CIL_NEQ:
    698 				op_str = CIL_KEY_NEQ;
    699 				break;
    700 			case CIL_XOR:
    701 				op_str = CIL_KEY_XOR;
    702 				break;
    703 			case CIL_CONS_DOM:
    704 				op_str = CIL_KEY_CONS_DOM;
    705 				break;
    706 			case CIL_CONS_DOMBY:
    707 				op_str = CIL_KEY_CONS_DOMBY;
    708 				break;
    709 			case CIL_CONS_INCOMP:
    710 				op_str = CIL_KEY_CONS_INCOMP;
    711 				break;
    712 			default:
    713 				cil_log(CIL_ERR, "Unknown operator in expression\n");
    714 				goto exit;
    715 				break;
    716 			}
    717 			if (op_flavor == CIL_NOT) {
    718 				len = strlen(stack[pos-1]) + strlen(op_str) + 4;
    719 				expr_str = cil_malloc(len);
    720 				snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
    721 				free(stack[pos-1]);
    722 				stack[pos-1] = NULL;
    723 				pos--;
    724 			} else {
    725 				if (pos < 2) {
    726 					rc = SEPOL_ERR;
    727 					goto exit;
    728 				}
    729 				len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
    730 				expr_str = cil_malloc(len);
    731 				snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]);
    732 				free(stack[pos-2]);
    733 				free(stack[pos-1]);
    734 				stack[pos-2] = NULL;
    735 				stack[pos-1] = NULL;
    736 				pos -= 2;
    737 			}
    738 			stack[pos] = expr_str;
    739 			pos++;
    740 			break;
    741 		}
    742 		case CIL_CONS_OPERAND: {
    743 			enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
    744 			char *operand_str = NULL;
    745 			switch (operand_flavor) {
    746 			case CIL_CONS_U1:
    747 				operand_str = CIL_KEY_CONS_U1;
    748 				break;
    749 			case CIL_CONS_U2:
    750 				operand_str = CIL_KEY_CONS_U2;
    751 				break;
    752 			case CIL_CONS_U3:
    753 				operand_str = CIL_KEY_CONS_U3;
    754 				break;
    755 			case CIL_CONS_T1:
    756 				operand_str = CIL_KEY_CONS_T1;
    757 				break;
    758 			case CIL_CONS_T2:
    759 				operand_str = CIL_KEY_CONS_T2;
    760 				break;
    761 			case CIL_CONS_T3:
    762 				operand_str = CIL_KEY_CONS_T3;
    763 				break;
    764 			case CIL_CONS_R1:
    765 				operand_str = CIL_KEY_CONS_R1;
    766 				break;
    767 			case CIL_CONS_R2:
    768 				operand_str = CIL_KEY_CONS_R2;
    769 				break;
    770 			case CIL_CONS_R3:
    771 				operand_str = CIL_KEY_CONS_R3;
    772 				break;
    773 			case CIL_CONS_L1:
    774 				operand_str = CIL_KEY_CONS_L1;
    775 				break;
    776 			case CIL_CONS_L2:
    777 				operand_str = CIL_KEY_CONS_L2;
    778 				break;
    779 			case CIL_CONS_H1:
    780 				operand_str = CIL_KEY_CONS_H1;
    781 				break;
    782 			case CIL_CONS_H2:
    783 				operand_str = CIL_KEY_CONS_H2;
    784 				break;
    785 			default:
    786 				cil_log(CIL_ERR, "Unknown operand in expression\n");
    787 				goto exit;
    788 				break;
    789 			}
    790 			stack[pos] = operand_str;
    791 			pos++;
    792 			break;
    793 		}
    794 		default:
    795 			cil_log(CIL_ERR, "Unknown flavor in expression\n");
    796 			goto exit;
    797 			break;
    798 		}
    799 	}
    800 
    801 	*out = stack[0];
    802 
    803 	return SEPOL_OK;
    804 
    805 exit:
    806 	for (i = 0; i < pos; i++) {
    807 		free(stack[i]);
    808 	}
    809 	return rc;
    810 }
    811 
    812 int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr)
    813 {
    814 	int rc = SEPOL_ERR;
    815 	char *str_out;
    816 
    817 	rc = cil_expr_to_string(expr, &str_out);
    818 	if (rc != SEPOL_OK) {
    819 		goto out;
    820 	}
    821 	fprintf(file_arr[file_index], "%s", str_out);
    822 	free(str_out);
    823 
    824 	return SEPOL_OK;
    825 
    826 out:
    827 	return rc;
    828 }
    829 
    830 int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
    831 {
    832 	int rc = SEPOL_ERR;
    833 	struct cil_args_booleanif *args;
    834 	FILE **file_arr;
    835 	uint32_t *file_index;
    836 
    837 	args = extra_args;
    838 	file_arr = args->file_arr;
    839 	file_index = args->file_index;
    840 
    841 	switch (node->flavor) {
    842 	case CIL_AVRULE:
    843 		rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data);
    844 		if (rc != SEPOL_OK) {
    845 			cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc);
    846 			return rc;
    847 		}
    848 		break;
    849 	case CIL_TYPE_RULE:
    850 		rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data);
    851 		if (rc != SEPOL_OK) {
    852 			cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc);
    853 			return rc;
    854 		}
    855 		break;
    856 	case CIL_FALSE:
    857 		fprintf(file_arr[*file_index], "else {\n");
    858 		break;
    859 	case CIL_TRUE:
    860 		break;
    861 	default:
    862 		return SEPOL_ERR;
    863 	}
    864 
    865 	return SEPOL_OK;
    866 }
    867 
    868 int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args)
    869 {
    870 	struct cil_args_booleanif *args;
    871 	FILE **file_arr;
    872 	uint32_t *file_index;
    873 
    874 	args = extra_args;
    875 	file_arr = args->file_arr;
    876 	file_index = args->file_index;
    877 
    878 	if (node->parent->flavor == CIL_FALSE) {
    879 		fprintf(file_arr[*file_index], "}\n");
    880 	}
    881 
    882 	return SEPOL_OK;
    883 }
    884 
    885 int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node)
    886 {
    887 	int rc = SEPOL_ERR;
    888 	struct cil_booleanif *bif = node->data;
    889 	struct cil_list *expr = bif->datum_expr;
    890 	struct cil_args_booleanif extra_args;
    891 	struct cil_tree_node *true_node = NULL;
    892 	struct cil_tree_node *false_node = NULL;
    893 	struct cil_condblock *cb = NULL;
    894 
    895 	extra_args.file_arr = file_arr;
    896 	extra_args.file_index = &file_index;;
    897 
    898 	fprintf(file_arr[file_index], "if ");
    899 
    900 	rc = cil_expr_to_policy(file_arr, file_index, expr);
    901 	if (rc != SEPOL_OK) {
    902 		cil_log(CIL_ERR, "Failed to write expression\n");
    903 		return rc;
    904 	}
    905 
    906 	if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) {
    907 		cb = node->cl_head->data;
    908 		if (cb->flavor == CIL_CONDTRUE) {
    909 			true_node = node->cl_head;
    910 		} else if (cb->flavor == CIL_CONDFALSE) {
    911 			false_node = node->cl_head;
    912 		}
    913 	}
    914 
    915 	if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) {
    916 		cb = node->cl_head->next->data;
    917 		if (cb->flavor == CIL_CONDTRUE) {
    918 			true_node = node->cl_head->next;
    919 		} else if (cb->flavor == CIL_CONDFALSE) {
    920 			false_node = node->cl_head->next;
    921 		}
    922 	}
    923 
    924 	fprintf(file_arr[file_index], "{\n");
    925 	if (true_node != NULL) {
    926 		rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
    927 		if (rc != SEPOL_OK) {
    928 			cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc);
    929 			return rc;
    930 		}
    931 	}
    932 	fprintf(file_arr[file_index], "}\n");
    933 
    934 	if (false_node != NULL) {
    935 		fprintf(file_arr[file_index], "else {\n");
    936 		rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
    937 		if (rc != SEPOL_OK) {
    938 			cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc);
    939 			return rc;
    940 		}
    941 		fprintf(file_arr[file_index], "}\n");
    942 	}
    943 
    944 	return SEPOL_OK;
    945 }
    946 
    947 int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current)
    948 {
    949 	uint32_t flavor = current->flavor;
    950 	int rc = SEPOL_ERR;
    951 
    952 	switch(flavor) {
    953 	case CIL_TYPEATTRIBUTE:
    954 		fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name);
    955 		break;
    956 	case CIL_TYPE:
    957 		fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name);
    958 		break;
    959 	case CIL_TYPEALIAS: {
    960 		struct cil_alias *alias = current->data;
    961 		fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name);
    962 		break;
    963 	}
    964 	case CIL_TYPEBOUNDS: {
    965 		struct cil_bounds *bnds = current->data;
    966 		fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str);
    967 		break;
    968 	}
    969 	case CIL_TYPEPERMISSIVE: {
    970 		struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data;
    971 		fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name);
    972 		break;
    973 	}
    974 	case CIL_ROLE:
    975 		fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name);
    976 		break;
    977 	case CIL_BOOL: {
    978 		const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false";
    979 		fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean);
    980 		break;
    981 	}
    982 	case CIL_COMMON:
    983 		fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name);
    984 
    985 		if (current->cl_head != NULL) {
    986 			current = current->cl_head;
    987 			fprintf(file_arr[COMMONS], " {");
    988 		} else {
    989 			cil_log(CIL_INFO, "No permissions given\n");
    990 			return SEPOL_ERR;
    991 		}
    992 
    993 		while (current != NULL) {
    994 			if (current->flavor == CIL_PERM) {
    995 				fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name);
    996 			} else {
    997 				cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor);
    998 				return SEPOL_ERR;
    999 			}
   1000 			current = current->next;
   1001 		}
   1002 		fprintf(file_arr[COMMONS], "}\n");
   1003 
   1004 		return SEPOL_DONE;
   1005 	case CIL_AVRULE: {
   1006 		struct cil_avrule *avrule = (struct cil_avrule*)current->data;
   1007 		rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule);
   1008 		if (rc != SEPOL_OK) {
   1009 			cil_log(CIL_INFO, "Failed to write avrule to policy\n");
   1010 			return rc;
   1011 		}
   1012 		break;
   1013 	}
   1014 	case CIL_TYPE_RULE: {
   1015 		struct cil_type_rule *rule = (struct cil_type_rule*)current->data;
   1016 		rc = cil_typerule_to_policy(file_arr, ALLOWS, rule);
   1017 		if (rc != SEPOL_OK) {
   1018 			cil_log(CIL_INFO, "Failed to write type rule to policy\n");
   1019 			return rc;
   1020 		}
   1021 		break;
   1022 	}
   1023 	case CIL_NAMETYPETRANSITION: {
   1024 		struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data;
   1025 		rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans);
   1026 		if (rc != SEPOL_OK) {
   1027 			cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n");
   1028 			return rc;
   1029 		}
   1030 	}
   1031 	case CIL_ROLETRANSITION: {
   1032 		struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data;
   1033 		char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name;
   1034 		char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name;
   1035 		char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name;
   1036 		char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name;
   1037 
   1038 		fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str);
   1039 		break;
   1040 	}
   1041 	case CIL_ROLEALLOW: {
   1042 		struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data;
   1043 		char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name;
   1044 		char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name;
   1045 
   1046 		fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str);
   1047 		break;
   1048 	}
   1049 	case CIL_ROLETYPE: {
   1050 		struct cil_roletype *roletype = (struct cil_roletype*)current->data;
   1051 		char *role_str = ((struct cil_symtab_datum*)roletype->role)->name;
   1052 		char *type_str = ((struct cil_symtab_datum*)roletype->type)->name;
   1053 
   1054 		fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str);
   1055 		break;
   1056 	}
   1057 	case CIL_LEVEL:
   1058 		fprintf(file_arr[LEVELS], "level ");
   1059 		cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data);
   1060 			fprintf(file_arr[LEVELS], ";\n");
   1061 			break;
   1062 	case CIL_CONSTRAIN:
   1063 		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
   1064 		break;
   1065 	case CIL_MLSCONSTRAIN:
   1066 		cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
   1067 		break;
   1068 	case CIL_VALIDATETRANS: {
   1069 		struct cil_validatetrans *vt = current->data;
   1070 		fprintf(file_arr[CONSTRAINS], "validatetrans");
   1071 		fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name);
   1072 		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
   1073 		fprintf(file_arr[CONSTRAINS], ";\n");
   1074 		break;
   1075 	}
   1076 	case CIL_MLSVALIDATETRANS: {
   1077 		struct cil_validatetrans *vt = current->data;
   1078 		fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans");
   1079 		fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name);
   1080 		cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
   1081 		fprintf(file_arr[CONSTRAINS], ";\n");
   1082 		break;
   1083 	}
   1084 	case CIL_SID:
   1085 		fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name);
   1086 		break;
   1087 	case CIL_SIDCONTEXT: {
   1088 		struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data;
   1089 		fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str);
   1090 		cil_context_to_policy(file_arr, SIDS, sidcon->context);
   1091 		fprintf(file_arr[SIDS], "\n");
   1092 		break;
   1093 	}
   1094 	case CIL_POLICYCAP:
   1095 		fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name);
   1096 		break;
   1097 	default:
   1098 		break;
   1099 	}
   1100 
   1101 	return SEPOL_OK;
   1102 }
   1103 
   1104 int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
   1105 {
   1106 	int rc = SEPOL_ERR;
   1107 	struct cil_args_genpolicy *args = NULL;
   1108 	struct cil_list *users = NULL;
   1109 	struct cil_list *sens = NULL;
   1110 	struct cil_list *cats = NULL;
   1111 	FILE **file_arr = NULL;
   1112 
   1113 	if (extra_args == NULL) {
   1114 		return SEPOL_ERR;
   1115 	}
   1116 
   1117 	*finished = CIL_TREE_SKIP_NOTHING;
   1118 
   1119 	args = extra_args;
   1120 	users = args->users;
   1121 	sens = args->sens;
   1122 	cats = args->cats;
   1123 	file_arr = args->file_arr;
   1124 
   1125 	if (node->cl_head != NULL) {
   1126 		if (node->flavor == CIL_MACRO) {
   1127 			*finished = CIL_TREE_SKIP_HEAD;
   1128 			return SEPOL_OK;
   1129 		}
   1130 
   1131 		if (node->flavor == CIL_BOOLEANIF) {
   1132 			rc = cil_booleanif_to_policy(file_arr, CONDS, node);
   1133 			if (rc != SEPOL_OK) {
   1134 				cil_log(CIL_INFO, "Failed to write booleanif contents to file\n");
   1135 				return rc;
   1136 			}
   1137 			*finished = CIL_TREE_SKIP_HEAD;
   1138 			return SEPOL_OK;
   1139 		}
   1140 
   1141 		if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) {
   1142 			*finished = CIL_TREE_SKIP_HEAD;
   1143 			return SEPOL_OK;
   1144 		}
   1145 
   1146 		if (node->flavor != CIL_ROOT) {
   1147 			rc = cil_name_to_policy(file_arr, node);
   1148 			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
   1149 				cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor);
   1150 				return SEPOL_ERR;
   1151 			}
   1152 		}
   1153 	} else {
   1154 		switch (node->flavor) {
   1155 		case CIL_USER:
   1156 			cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
   1157 			break;
   1158 		case CIL_USERROLE: {
   1159 			struct cil_userrole *userrole = node->data;
   1160 			cil_multimap_insert(users, &userrole->user->datum, (struct cil_symtab_datum *)userrole->role, CIL_USERROLE, CIL_ROLE);
   1161 		}
   1162 			break;
   1163 		case CIL_CATALIAS: {
   1164 			struct cil_alias *alias = node->data;
   1165 			struct cil_symtab_datum *datum = alias->actual;
   1166 			cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
   1167 		}
   1168 			break;
   1169 		case CIL_SENSALIAS: {
   1170 			struct cil_alias *alias = node->data;
   1171 			struct cil_symtab_datum *datum = alias->actual;
   1172 			cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
   1173 		}
   1174 			break;
   1175 		default:
   1176 			rc = cil_name_to_policy(file_arr, node);
   1177 			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
   1178 				cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
   1179 				return SEPOL_ERR;
   1180 			}
   1181 			break;
   1182 		}
   1183 	}
   1184 
   1185 	return SEPOL_OK;
   1186 }
   1187 
   1188 int cil_gen_policy(struct cil_db *db)
   1189 {
   1190 	struct cil_tree_node *curr = db->ast->root;
   1191 	struct cil_list_item *item;
   1192 	int rc = SEPOL_ERR;
   1193 	FILE *policy_file;
   1194 	FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
   1195 	char *file_path_arr[NUM_POLICY_FILES];
   1196 	char temp[32];
   1197 
   1198 	struct cil_list *users = NULL;
   1199 	struct cil_list *cats = NULL;
   1200 	struct cil_list *sens = NULL;
   1201 	struct cil_args_genpolicy extra_args;
   1202 
   1203 	cil_list_init(&users, CIL_LIST_ITEM);
   1204 	cil_list_init(&cats, CIL_LIST_ITEM);
   1205 	cil_list_init(&sens, CIL_LIST_ITEM);
   1206 
   1207 	strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
   1208 	file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
   1209 	file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
   1210 
   1211 	strcpy(temp, "/tmp/cil_isids-XXXXXX");
   1212 	file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
   1213 	file_path_arr[ISIDS] = cil_strpool_add(temp);
   1214 
   1215 	strcpy(temp,"/tmp/cil_common-XXXXXX");
   1216 	file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
   1217 	file_path_arr[COMMONS] = cil_strpool_add(temp);
   1218 
   1219 	strcpy(temp, "/tmp/cil_class-XXXXXX");
   1220 	file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
   1221 	file_path_arr[CLASSES] = cil_strpool_add(temp);
   1222 
   1223 	strcpy(temp, "/tmp/cil_interf-XXXXXX");
   1224 	file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
   1225 	file_path_arr[INTERFACES] = cil_strpool_add(temp);
   1226 
   1227 	strcpy(temp, "/tmp/cil_sens-XXXXXX");
   1228 	file_arr[SENS] = fdopen(mkstemp(temp), "w+");
   1229 	file_path_arr[SENS] = cil_strpool_add(temp);
   1230 
   1231 	strcpy(temp, "/tmp/cil_cats-XXXXXX");
   1232 	file_arr[CATS] = fdopen(mkstemp(temp), "w+");
   1233 	file_path_arr[CATS] = cil_strpool_add(temp);
   1234 
   1235 	strcpy(temp, "/tmp/cil_levels-XXXXXX");
   1236 	file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
   1237 	file_path_arr[LEVELS] = cil_strpool_add(temp);
   1238 
   1239 	strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
   1240 	file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
   1241 	file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
   1242 
   1243 	strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
   1244 	file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
   1245 	file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
   1246 
   1247 	strcpy(temp, "/tmp/cil_aliases-XXXXXX");
   1248 	file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
   1249 	file_path_arr[ALIASES] = cil_strpool_add(temp);
   1250 
   1251 	strcpy(temp, "/tmp/cil_allows-XXXXXX");
   1252 	file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
   1253 	file_path_arr[ALLOWS] = cil_strpool_add(temp);
   1254 
   1255 	strcpy(temp, "/tmp/cil_conds-XXXXXX");
   1256 	file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
   1257 	file_path_arr[CONDS] = cil_strpool_add(temp);
   1258 
   1259 	strcpy(temp, "/tmp/cil_userroles-XXXXXX");
   1260 	file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
   1261 	file_path_arr[USERROLES] = cil_strpool_add(temp);
   1262 
   1263 	strcpy(temp, "/tmp/cil_sids-XXXXXX");
   1264 	file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
   1265 	file_path_arr[SIDS] = cil_strpool_add(temp);
   1266 
   1267 	strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
   1268 	file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
   1269 	file_path_arr[NETIFCONS] = cil_strpool_add(temp);
   1270 
   1271 	policy_file = fopen("policy.conf", "w+");
   1272 
   1273 	cil_list_for_each(item, db->sidorder) {
   1274 		fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
   1275 	}
   1276 
   1277 	cil_list_for_each(item, db->classorder) {
   1278 		struct cil_class *class = item->data;
   1279 		struct cil_tree_node *node = class->datum.nodes->head->data;
   1280 
   1281 		fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
   1282 
   1283 		fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
   1284 		if (class->common != NULL) {
   1285 			fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
   1286 		}
   1287 		if (node->cl_head != NULL) {
   1288 			struct cil_tree_node *curr_perm = node->cl_head;
   1289 			fprintf(file_arr[CLASSES], "{ ");
   1290 			while (curr_perm != NULL) {
   1291 				fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
   1292 				curr_perm = curr_perm->next;
   1293 			}
   1294 			fprintf(file_arr[CLASSES], "}");
   1295 		}
   1296 		fprintf(file_arr[CLASSES], "\n");
   1297 	}
   1298 
   1299 	if (db->catorder->head != NULL) {
   1300 		cil_list_for_each(item, db->catorder) {
   1301 			cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
   1302 		}
   1303 	}
   1304 
   1305 	if (db->sensitivityorder->head != NULL) {
   1306 		fprintf(file_arr[SENS], "sensitivityorder { ");
   1307 		cil_list_for_each(item, db->sensitivityorder) {
   1308 			fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
   1309 		}
   1310 		fprintf(file_arr[SENS], "};\n");
   1311 	}
   1312 
   1313 	extra_args.users = users;
   1314 	extra_args.sens = sens;
   1315 	extra_args.cats = cats;
   1316 	extra_args.file_arr= file_arr;
   1317 
   1318 	rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
   1319 	if (rc != SEPOL_OK) {
   1320 		cil_log(CIL_ERR, "Error walking tree\n");
   1321 		return rc;
   1322 	}
   1323 
   1324 	rc = cil_netifcon_to_policy(file_arr, db->netifcon);
   1325 	if (rc != SEPOL_OK) {
   1326 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1327 		return rc;
   1328 	}
   1329 
   1330 	rc = cil_genfscon_to_policy(file_arr, db->genfscon);
   1331 	if (rc != SEPOL_OK) {
   1332 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1333 		return rc;
   1334 	}
   1335 
   1336 	rc = cil_portcon_to_policy(file_arr, db->portcon);
   1337 	if (rc != SEPOL_OK) {
   1338 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1339 		return rc;
   1340 	}
   1341 
   1342 	rc = cil_nodecon_to_policy(file_arr, db->nodecon);
   1343 	if (rc != SEPOL_OK) {
   1344 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1345 		return rc;
   1346 	}
   1347 
   1348 	rc = cil_fsuse_to_policy(file_arr, db->fsuse);
   1349 	if (rc != SEPOL_OK) {
   1350 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1351 		return rc;
   1352 	}
   1353 
   1354 	rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
   1355 	if (rc != SEPOL_OK) {
   1356 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1357 		return rc;
   1358 	}
   1359 
   1360 	rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
   1361 	if (rc != SEPOL_OK) {
   1362 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1363 		return rc;
   1364 	}
   1365 
   1366 	rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
   1367 	if (rc != SEPOL_OK) {
   1368 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1369 		return rc;
   1370 	}
   1371 
   1372 	rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
   1373 	if (rc != SEPOL_OK) {
   1374 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1375 		return rc;
   1376 	}
   1377 
   1378 	rc = cil_userrole_to_policy(file_arr, users);
   1379 	if (rc != SEPOL_OK) {
   1380 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1381 		return SEPOL_ERR;
   1382 	}
   1383 
   1384 	rc = cil_sens_to_policy(file_arr, sens);
   1385 	if (rc != SEPOL_OK) {
   1386 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1387 		return SEPOL_ERR;
   1388 	}
   1389 
   1390 	rc = cil_cat_to_policy(file_arr, cats);
   1391 	if (rc != SEPOL_OK) {
   1392 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1393 		return SEPOL_ERR;
   1394 	}
   1395 
   1396 	rc = cil_combine_policy(file_arr, policy_file);
   1397 	if (rc != SEPOL_OK) {
   1398 		cil_log(CIL_ERR, "Error creating policy.conf\n");
   1399 		return SEPOL_ERR;
   1400 	}
   1401 
   1402 	// Remove temp files
   1403 	int i;
   1404 	for (i=0; i<NUM_POLICY_FILES; i++) {
   1405 		rc = fclose(file_arr[i]);
   1406 		if (rc != 0) {
   1407 			cil_log(CIL_ERR, "Error closing temporary file\n");
   1408 			return SEPOL_ERR;
   1409 		}
   1410 		rc = unlink(file_path_arr[i]);
   1411 		if (rc != 0) {
   1412 			cil_log(CIL_ERR, "Error unlinking temporary files\n");
   1413 			return SEPOL_ERR;
   1414 		}
   1415 	}
   1416 
   1417 	rc = fclose(policy_file);
   1418 	if (rc != 0) {
   1419 		cil_log(CIL_ERR, "Error closing policy.conf\n");
   1420 		return SEPOL_ERR;
   1421 	}
   1422 	free(file_arr);
   1423 
   1424 	cil_list_destroy(&users, CIL_FALSE);
   1425 	cil_list_destroy(&cats, CIL_FALSE);
   1426 	cil_list_destroy(&sens, CIL_FALSE);
   1427 
   1428 	return SEPOL_OK;
   1429 }
   1430