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
72struct cil_args_genpolicy {
73	struct cil_list *users;
74	struct cil_list *sens;
75	struct cil_list *cats;
76	FILE **file_arr;
77};
78
79struct cil_args_booleanif {
80	FILE **file_arr;
81	uint32_t *file_index;
82};
83
84
85int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
86
87int 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
115int 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
136int 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
151int 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
167int 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
216exit:
217	return rc;
218}
219
220
221int 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}
234int 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
248int 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
262int 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
276int 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
299int 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
337int 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
365int 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
391int 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
417void 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
422void 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
433void 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
443void 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
454void 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
505void 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
533void 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
546void 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
575int 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->perms.classperms);
602
603	return SEPOL_OK;
604}
605
606int 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
631int 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
642static 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
805exit:
806	for (i = 0; i < pos; i++) {
807		free(stack[i]);
808	}
809	return rc;
810}
811
812int 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
826out:
827	return rc;
828}
829
830int __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
868int __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
885int 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
947int 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
1104int __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_CATALIAS: {
1159			struct cil_alias *alias = node->data;
1160			struct cil_symtab_datum *datum = alias->actual;
1161			cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
1162		}
1163			break;
1164		case CIL_SENSALIAS: {
1165			struct cil_alias *alias = node->data;
1166			struct cil_symtab_datum *datum = alias->actual;
1167			cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
1168		}
1169			break;
1170		default:
1171			rc = cil_name_to_policy(file_arr, node);
1172			if (rc != SEPOL_OK && rc != SEPOL_DONE) {
1173				cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
1174				return SEPOL_ERR;
1175			}
1176			break;
1177		}
1178	}
1179
1180	return SEPOL_OK;
1181}
1182
1183int cil_gen_policy(struct cil_db *db)
1184{
1185	struct cil_tree_node *curr = db->ast->root;
1186	struct cil_list_item *item;
1187	int rc = SEPOL_ERR;
1188	FILE *policy_file;
1189	FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
1190	char *file_path_arr[NUM_POLICY_FILES];
1191	char temp[32];
1192
1193	struct cil_list *users = NULL;
1194	struct cil_list *cats = NULL;
1195	struct cil_list *sens = NULL;
1196	struct cil_args_genpolicy extra_args;
1197
1198	cil_list_init(&users, CIL_LIST_ITEM);
1199	cil_list_init(&cats, CIL_LIST_ITEM);
1200	cil_list_init(&sens, CIL_LIST_ITEM);
1201
1202	strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
1203	file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
1204	file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
1205
1206	strcpy(temp, "/tmp/cil_isids-XXXXXX");
1207	file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
1208	file_path_arr[ISIDS] = cil_strpool_add(temp);
1209
1210	strcpy(temp,"/tmp/cil_common-XXXXXX");
1211	file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
1212	file_path_arr[COMMONS] = cil_strpool_add(temp);
1213
1214	strcpy(temp, "/tmp/cil_class-XXXXXX");
1215	file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
1216	file_path_arr[CLASSES] = cil_strpool_add(temp);
1217
1218	strcpy(temp, "/tmp/cil_interf-XXXXXX");
1219	file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
1220	file_path_arr[INTERFACES] = cil_strpool_add(temp);
1221
1222	strcpy(temp, "/tmp/cil_sens-XXXXXX");
1223	file_arr[SENS] = fdopen(mkstemp(temp), "w+");
1224	file_path_arr[SENS] = cil_strpool_add(temp);
1225
1226	strcpy(temp, "/tmp/cil_cats-XXXXXX");
1227	file_arr[CATS] = fdopen(mkstemp(temp), "w+");
1228	file_path_arr[CATS] = cil_strpool_add(temp);
1229
1230	strcpy(temp, "/tmp/cil_levels-XXXXXX");
1231	file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
1232	file_path_arr[LEVELS] = cil_strpool_add(temp);
1233
1234	strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
1235	file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
1236	file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
1237
1238	strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
1239	file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
1240	file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
1241
1242	strcpy(temp, "/tmp/cil_aliases-XXXXXX");
1243	file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
1244	file_path_arr[ALIASES] = cil_strpool_add(temp);
1245
1246	strcpy(temp, "/tmp/cil_allows-XXXXXX");
1247	file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
1248	file_path_arr[ALLOWS] = cil_strpool_add(temp);
1249
1250	strcpy(temp, "/tmp/cil_conds-XXXXXX");
1251	file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
1252	file_path_arr[CONDS] = cil_strpool_add(temp);
1253
1254	strcpy(temp, "/tmp/cil_userroles-XXXXXX");
1255	file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
1256	file_path_arr[USERROLES] = cil_strpool_add(temp);
1257
1258	strcpy(temp, "/tmp/cil_sids-XXXXXX");
1259	file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
1260	file_path_arr[SIDS] = cil_strpool_add(temp);
1261
1262	strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
1263	file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
1264	file_path_arr[NETIFCONS] = cil_strpool_add(temp);
1265
1266	policy_file = fopen("policy.conf", "w+");
1267
1268	cil_list_for_each(item, db->sidorder) {
1269		fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
1270	}
1271
1272	cil_list_for_each(item, db->classorder) {
1273		struct cil_class *class = item->data;
1274		struct cil_tree_node *node = class->datum.nodes->head->data;
1275
1276		fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
1277
1278		fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
1279		if (class->common != NULL) {
1280			fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
1281		}
1282		if (node->cl_head != NULL) {
1283			struct cil_tree_node *curr_perm = node->cl_head;
1284			fprintf(file_arr[CLASSES], "{ ");
1285			while (curr_perm != NULL) {
1286				fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
1287				curr_perm = curr_perm->next;
1288			}
1289			fprintf(file_arr[CLASSES], "}");
1290		}
1291		fprintf(file_arr[CLASSES], "\n");
1292	}
1293
1294	if (db->catorder->head != NULL) {
1295		cil_list_for_each(item, db->catorder) {
1296			cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
1297		}
1298	}
1299
1300	if (db->sensitivityorder->head != NULL) {
1301		fprintf(file_arr[SENS], "sensitivityorder { ");
1302		cil_list_for_each(item, db->sensitivityorder) {
1303			fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
1304		}
1305		fprintf(file_arr[SENS], "};\n");
1306	}
1307
1308	extra_args.users = users;
1309	extra_args.sens = sens;
1310	extra_args.cats = cats;
1311	extra_args.file_arr= file_arr;
1312
1313	rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
1314	if (rc != SEPOL_OK) {
1315		cil_log(CIL_ERR, "Error walking tree\n");
1316		return rc;
1317	}
1318
1319	rc = cil_netifcon_to_policy(file_arr, db->netifcon);
1320	if (rc != SEPOL_OK) {
1321		cil_log(CIL_ERR, "Error creating policy.conf\n");
1322		return rc;
1323	}
1324
1325	rc = cil_genfscon_to_policy(file_arr, db->genfscon);
1326	if (rc != SEPOL_OK) {
1327		cil_log(CIL_ERR, "Error creating policy.conf\n");
1328		return rc;
1329	}
1330
1331	rc = cil_portcon_to_policy(file_arr, db->portcon);
1332	if (rc != SEPOL_OK) {
1333		cil_log(CIL_ERR, "Error creating policy.conf\n");
1334		return rc;
1335	}
1336
1337	rc = cil_nodecon_to_policy(file_arr, db->nodecon);
1338	if (rc != SEPOL_OK) {
1339		cil_log(CIL_ERR, "Error creating policy.conf\n");
1340		return rc;
1341	}
1342
1343	rc = cil_fsuse_to_policy(file_arr, db->fsuse);
1344	if (rc != SEPOL_OK) {
1345		cil_log(CIL_ERR, "Error creating policy.conf\n");
1346		return rc;
1347	}
1348
1349	rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
1350	if (rc != SEPOL_OK) {
1351		cil_log(CIL_ERR, "Error creating policy.conf\n");
1352		return rc;
1353	}
1354
1355	rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
1356	if (rc != SEPOL_OK) {
1357		cil_log(CIL_ERR, "Error creating policy.conf\n");
1358		return rc;
1359	}
1360
1361	rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
1362	if (rc != SEPOL_OK) {
1363		cil_log(CIL_ERR, "Error creating policy.conf\n");
1364		return rc;
1365	}
1366
1367	rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
1368	if (rc != SEPOL_OK) {
1369		cil_log(CIL_ERR, "Error creating policy.conf\n");
1370		return rc;
1371	}
1372
1373	rc = cil_userrole_to_policy(file_arr, users);
1374	if (rc != SEPOL_OK) {
1375		cil_log(CIL_ERR, "Error creating policy.conf\n");
1376		return SEPOL_ERR;
1377	}
1378
1379	rc = cil_sens_to_policy(file_arr, sens);
1380	if (rc != SEPOL_OK) {
1381		cil_log(CIL_ERR, "Error creating policy.conf\n");
1382		return SEPOL_ERR;
1383	}
1384
1385	rc = cil_cat_to_policy(file_arr, cats);
1386	if (rc != SEPOL_OK) {
1387		cil_log(CIL_ERR, "Error creating policy.conf\n");
1388		return SEPOL_ERR;
1389	}
1390
1391	rc = cil_combine_policy(file_arr, policy_file);
1392	if (rc != SEPOL_OK) {
1393		cil_log(CIL_ERR, "Error creating policy.conf\n");
1394		return SEPOL_ERR;
1395	}
1396
1397	// Remove temp files
1398	int i;
1399	for (i=0; i<NUM_POLICY_FILES; i++) {
1400		rc = fclose(file_arr[i]);
1401		if (rc != 0) {
1402			cil_log(CIL_ERR, "Error closing temporary file\n");
1403			return SEPOL_ERR;
1404		}
1405		rc = unlink(file_path_arr[i]);
1406		if (rc != 0) {
1407			cil_log(CIL_ERR, "Error unlinking temporary files\n");
1408			return SEPOL_ERR;
1409		}
1410	}
1411
1412	rc = fclose(policy_file);
1413	if (rc != 0) {
1414		cil_log(CIL_ERR, "Error closing policy.conf\n");
1415		return SEPOL_ERR;
1416	}
1417	free(file_arr);
1418
1419	cil_list_destroy(&users, CIL_FALSE);
1420	cil_list_destroy(&cats, CIL_FALSE);
1421	cil_list_destroy(&sens, CIL_FALSE);
1422
1423	return SEPOL_OK;
1424}
1425