• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdio.h>
31 #include <stdint.h>
32 #include <inttypes.h>
33 #include <ctype.h>
34 
35 #include "cil_internal.h"
36 #include "cil_flavor.h"
37 #include "cil_list.h"
38 #include "cil_log.h"
39 #include "cil_symtab.h"
40 #include "cil_tree.h"
41 #include "cil_write_ast.h"
42 
43 
datum_or_str(struct cil_symtab_datum * datum,const char * str)44 static inline const char *datum_or_str(struct cil_symtab_datum *datum, const char *str)
45 {
46 	return datum ? datum->fqn : str;
47 }
48 
datum_to_str(struct cil_symtab_datum * datum)49 static inline const char *datum_to_str(struct cil_symtab_datum *datum)
50 {
51 	return datum ? datum->fqn : "<?DATUM>";
52 }
53 
write_expr(FILE * out,struct cil_list * expr)54 static void write_expr(FILE *out, struct cil_list *expr)
55 {
56 	struct cil_list_item *curr;
57 	int notfirst = 0;
58 
59 	fprintf(out, "(");
60 	cil_list_for_each(curr, expr) {
61 		if (notfirst)
62 			fprintf(out, " ");
63 		else
64 			notfirst = 1;
65 		switch (curr->flavor) {
66 		case CIL_LIST:
67 			write_expr(out, curr->data);
68 			break;
69 		case CIL_STRING:
70 			fprintf(out, "%s", (char *)curr->data);
71 			break;
72 		case CIL_DATUM:
73 		case CIL_TYPE:
74 		case CIL_ROLE:
75 		case CIL_USER:
76 		case CIL_SENS:
77 		case CIL_CAT:
78 		case CIL_BOOL:
79 		case CIL_CLASS:
80 		case CIL_MAP_CLASS:
81 		case CIL_NAME:
82 			fprintf(out, "%s", datum_to_str(curr->data));
83 			break;
84 		case CIL_OP: {
85 			const char *op_str;
86 			enum cil_flavor op_flavor = (enum cil_flavor)(uintptr_t)curr->data;
87 			switch (op_flavor) {
88 			case CIL_AND:
89 				op_str = CIL_KEY_AND;
90 				break;
91 			case CIL_OR:
92 				op_str = CIL_KEY_OR;
93 				break;
94 			case CIL_NOT:
95 				op_str = CIL_KEY_NOT;
96 				break;
97 			case CIL_ALL:
98 				op_str = CIL_KEY_ALL;
99 				break;
100 			case CIL_EQ:
101 				op_str = CIL_KEY_EQ;
102 				break;
103 			case CIL_NEQ:
104 				op_str = CIL_KEY_NEQ;
105 				break;
106 			case CIL_XOR:
107 				op_str = CIL_KEY_XOR;
108 				break;
109 			case CIL_RANGE:
110 				op_str = CIL_KEY_RANGE;
111 				break;
112 			case CIL_CONS_DOM:
113 				op_str = CIL_KEY_CONS_DOM;
114 				break;
115 			case CIL_CONS_DOMBY:
116 				op_str = CIL_KEY_CONS_DOMBY;
117 				break;
118 			case CIL_CONS_INCOMP:
119 				op_str = CIL_KEY_CONS_INCOMP;
120 				break;
121 			default:
122 				op_str = "<?OP>";
123 				break;
124 			}
125 			fprintf(out, "%s", op_str);
126 			break;
127 		}
128 		case CIL_CONS_OPERAND: {
129 			const char *operand_str;
130 			enum cil_flavor operand_flavor = (enum cil_flavor)(uintptr_t)curr->data;
131 			switch (operand_flavor) {
132 			case CIL_CONS_U1:
133 				operand_str = CIL_KEY_CONS_U1;
134 				break;
135 			case CIL_CONS_U2:
136 				operand_str = CIL_KEY_CONS_U2;
137 				break;
138 			case CIL_CONS_U3:
139 				operand_str = CIL_KEY_CONS_U3;
140 				break;
141 			case CIL_CONS_T1:
142 				operand_str = CIL_KEY_CONS_T1;
143 				break;
144 			case CIL_CONS_T2:
145 				operand_str = CIL_KEY_CONS_T2;
146 				break;
147 			case CIL_CONS_T3:
148 				operand_str = CIL_KEY_CONS_T3;
149 				break;
150 			case CIL_CONS_R1:
151 				operand_str = CIL_KEY_CONS_R1;
152 				break;
153 			case CIL_CONS_R2:
154 				operand_str = CIL_KEY_CONS_R2;
155 				break;
156 			case CIL_CONS_R3:
157 				operand_str = CIL_KEY_CONS_R3;
158 				break;
159 			case CIL_CONS_L1:
160 				operand_str = CIL_KEY_CONS_L1;
161 				break;
162 			case CIL_CONS_L2:
163 				operand_str = CIL_KEY_CONS_L2;
164 				break;
165 			case CIL_CONS_H1:
166 				operand_str = CIL_KEY_CONS_H1;
167 				break;
168 			case CIL_CONS_H2:
169 				operand_str = CIL_KEY_CONS_H2;
170 				break;
171 			default:
172 				operand_str = "<?OPERAND>";
173 				break;
174 			}
175 			fprintf(out, "%s", operand_str);
176 			break;
177 		}
178 		default:
179 			fprintf(out, "<?FLAVOR>");
180 			break;
181 		}
182 	}
183 	fprintf(out, ")");
184 }
185 
write_node_list(FILE * out,struct cil_tree_node * current)186 static void write_node_list(FILE *out, struct cil_tree_node *current)
187 {
188 	int notfirst = 0;
189 
190 	fprintf(out, "(");
191 	while (current) {
192 		if (notfirst)
193 			fprintf(out, " ");
194 		else
195 			notfirst = 1;
196 
197 		fprintf(out, "%s", datum_to_str(current->data));
198 		current = current->next;
199 	}
200 	fprintf(out, ")");
201 }
202 
write_string_list(FILE * out,struct cil_list * list)203 static void write_string_list(FILE *out, struct cil_list *list)
204 {
205 	struct cil_list_item *curr;
206 	int notfirst = 0;
207 
208 	if (!list) {
209 		fprintf(out, "()");
210 		return;
211 	}
212 
213 	fprintf(out, "(");
214 	cil_list_for_each(curr, list) {
215 		if (notfirst)
216 			fprintf(out, " ");
217 		else
218 			notfirst = 1;
219 		fprintf(out, "%s", (char*)curr->data);
220 	}
221 	fprintf(out, ")");
222 }
223 
write_datum_list(FILE * out,struct cil_list * list)224 static void write_datum_list(FILE *out, struct cil_list *list)
225 {
226 	struct cil_list_item *curr;
227 	int notfirst = 0;
228 
229 	if (!list) {
230 		fprintf(out, "()");
231 		return;
232 	}
233 
234 	fprintf(out, "(");
235 	cil_list_for_each(curr, list) {
236 		if (notfirst)
237 			fprintf(out, " ");
238 		else
239 			notfirst = 1;
240 		fprintf(out, "%s", datum_to_str(curr->data));
241 	}
242 	fprintf(out, ")");
243 }
244 
write_classperms(FILE * out,struct cil_classperms * cp)245 static void write_classperms(FILE *out, struct cil_classperms *cp)
246 {
247 	if (!cp) {
248 		fprintf(out, "()");
249 		return;
250 	}
251 
252 	fprintf(out, "(%s ", datum_or_str(DATUM(cp->class), cp->class_str));
253 	if (cp->perms)
254 		write_expr(out, cp->perms);
255 	else
256 		write_expr(out, cp->perm_strs);
257 	fprintf(out, ")");
258 }
259 
write_classperms_list(FILE * out,struct cil_list * cp_list)260 static void write_classperms_list(FILE *out, struct cil_list *cp_list)
261 {
262 	struct cil_list_item *curr;
263 	int notfirst = 0;
264 	int num = 0;
265 
266 	if (!cp_list) {
267 		fprintf(out, "()");
268 		return;
269 	}
270 
271 	cil_list_for_each(curr, cp_list) {
272 		num++;
273 	}
274 	if (num > 1)
275 		fprintf(out, "(");
276 	cil_list_for_each(curr, cp_list) {
277 		if (notfirst)
278 			fprintf(out, " ");
279 		else
280 			notfirst = 1;
281 		if (curr->flavor == CIL_CLASSPERMS) {
282 			write_classperms(out, curr->data);
283 		} else {
284 			struct cil_classperms_set *cp_set = curr->data;
285 			struct cil_classpermission *cp = cp_set->set;
286 			if (cp) {
287 				if (cp->datum.name)
288 					fprintf(out, "%s", datum_to_str(DATUM(cp)));
289 				else
290 					write_classperms_list(out,cp->classperms);
291 			} else {
292 				fprintf(out, "%s", cp_set->set_str);
293 			}
294 		}
295 	}
296 	if (num > 1)
297 		fprintf(out, ")");
298 }
299 
write_permx(FILE * out,struct cil_permissionx * permx)300 static void write_permx(FILE *out, struct cil_permissionx *permx)
301 {
302 	if (permx->datum.name) {
303 		fprintf(out, "%s", datum_to_str(DATUM(permx)));
304 	} else {
305 		fprintf(out, "(");
306 		fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>");
307 		fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str));
308 		write_expr(out, permx->expr_str);
309 		fprintf(out, ")");
310 	}
311 }
312 
write_cats(FILE * out,struct cil_cats * cats)313 static void write_cats(FILE *out, struct cil_cats *cats)
314 {
315 	if (cats->datum_expr) {
316 		write_expr(out, cats->datum_expr);
317 	} else {
318 		write_expr(out, cats->str_expr);
319 	}
320 }
321 
write_level(FILE * out,struct cil_level * level,int print_name)322 static void write_level(FILE *out, struct cil_level *level, int print_name)
323 {
324 	if (print_name && level->datum.name) {
325 		fprintf(out, "%s", datum_to_str(DATUM(level)));
326 	} else {
327 		fprintf(out, "(");
328 		fprintf(out, "%s", datum_or_str(DATUM(level->sens), level->sens_str));
329 		if (level->cats) {
330 			fprintf(out, " ");
331 			write_cats(out, level->cats);
332 		}
333 		fprintf(out, ")");
334 	}
335 }
336 
write_range(FILE * out,struct cil_levelrange * range,int print_name)337 static void write_range(FILE *out, struct cil_levelrange *range, int print_name)
338 {
339 	if (print_name && range->datum.name) {
340 		fprintf(out, "%s", datum_to_str(DATUM(range)));
341 	} else {
342 		fprintf(out, "(");
343 		if (range->low)
344 			write_level(out, range->low, CIL_TRUE);
345 		else
346 			fprintf(out, "%s", range->low_str);
347 		fprintf(out, " ");
348 		if (range->high)
349 			write_level(out, range->high, CIL_TRUE);
350 		else
351 			fprintf(out, "%s", range->high_str);
352 		fprintf(out, ")");
353 	}
354 }
355 
write_context(FILE * out,struct cil_context * context,int print_name)356 static void write_context(FILE *out, struct cil_context *context, int print_name)
357 {
358 	if (print_name && context->datum.name) {
359 		fprintf(out, "%s", datum_to_str(DATUM(context)));
360 	} else {
361 		fprintf(out, "(");
362 		fprintf(out, "%s ", datum_or_str(DATUM(context->user), context->user_str));
363 		fprintf(out, "%s ", datum_or_str(DATUM(context->role), context->role_str));
364 		fprintf(out, "%s ", datum_or_str(DATUM(context->type), context->type_str));
365 		if (context->range)
366 			write_range(out, context->range, CIL_TRUE);
367 		else
368 			fprintf(out, "%s", context->range_str);
369 		fprintf(out, ")");
370 	}
371 }
372 
write_ipaddr(FILE * out,struct cil_ipaddr * ipaddr)373 static void write_ipaddr(FILE *out, struct cil_ipaddr *ipaddr)
374 {
375 	if (ipaddr->datum.name) {
376 		fprintf(out, "%s", datum_to_str(DATUM(ipaddr)));
377 	} else {
378 		char buf[256];
379 		if (inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256) == NULL)
380 			strcpy(buf, "<?IPADDR>");
381 		fprintf(out, "(%s)", buf);
382 	}
383 }
384 
write_constrain(FILE * out,struct cil_constrain * cons)385 static void write_constrain(FILE *out, struct cil_constrain *cons)
386 {
387 	write_classperms_list(out, cons->classperms);
388 	fprintf(out, " ");
389 	if (cons->datum_expr)
390 		write_expr(out, cons->datum_expr);
391 	else
392 		write_expr(out, cons->str_expr);
393 }
394 
write_call_args(FILE * out,struct cil_list * args)395 static void write_call_args(FILE *out, struct cil_list *args)
396 {
397 	struct cil_list_item *item;
398 	int notfirst = 0;
399 
400 	fprintf(out, "(");
401 	cil_list_for_each(item, args) {
402 		struct cil_args* arg = item->data;
403 		enum cil_flavor arg_flavor = arg->flavor;
404 		if (notfirst)
405 			fprintf(out, " ");
406 		else
407 			notfirst = 1;
408 		switch (arg_flavor) {
409 		case CIL_TYPE:
410 		case CIL_ROLE:
411 		case CIL_USER:
412 		case CIL_SENS:
413 		case CIL_CAT:
414 		case CIL_BOOL:
415 		case CIL_CLASS:
416 		case CIL_MAP_CLASS:
417 		case CIL_NAME: {
418 			fprintf(out, "%s", datum_or_str(arg->arg, arg->arg_str));
419 			break;
420 		}
421 		case CIL_CATSET: {
422 			if (arg->arg) {
423 				struct cil_catset *catset = (struct cil_catset *)arg->arg;
424 				write_cats(out, catset->cats);
425 			} else {
426 				fprintf(out, "%s", arg->arg_str);
427 			}
428 			break;
429 		}
430 		case CIL_LEVEL: {
431 			if (arg->arg) {
432 				struct cil_level *level = (struct cil_level *)arg->arg;
433 				write_level(out, level, CIL_TRUE);
434 			} else {
435 				fprintf(out, "%s", arg->arg_str);
436 			}
437 			break;
438 		}
439 		case CIL_LEVELRANGE: {
440 			if (arg->arg) {
441 				struct cil_levelrange *range = (struct cil_levelrange *)arg->arg;
442 				write_range(out, range, CIL_TRUE);
443 			} else {
444 				fprintf(out, "%s", arg->arg_str);
445 			}
446 			break;
447 		}
448 		case CIL_IPADDR: {
449 			if (arg->arg) {
450 				struct cil_ipaddr *addr = (struct cil_ipaddr *)arg->arg;
451 				write_ipaddr(out, addr);
452 			} else {
453 				fprintf(out, "%s", arg->arg_str);
454 			}
455 			break;
456 		}
457 		case CIL_CLASSPERMISSION: {
458 			if (arg->arg) {
459 				struct cil_classpermission *cp = (struct cil_classpermission *)arg->arg;
460 				if (cp->datum.name)
461 					fprintf(out, "%s", datum_to_str(DATUM(cp)));
462 				else
463 					write_classperms_list(out, cp->classperms);
464 			} else {
465 				fprintf(out, "%s", arg->arg_str);
466 			}
467 			break;
468 		}
469 		default:
470 			fprintf(out, "<?ARG:%s>", datum_or_str(arg->arg, arg->arg_str));
471 			break;
472 		}
473 	}
474 	fprintf(out, ")");
475 }
476 
write_call_args_tree(FILE * out,struct cil_tree_node * arg_node)477 static void write_call_args_tree(FILE *out, struct cil_tree_node *arg_node)
478 {
479 	while (arg_node) {
480 		if (arg_node->data) {
481 			fprintf(out, "%s", (char *)arg_node->data);
482 		} else if (arg_node->cl_head) {
483 			fprintf(out, "(");
484 			write_call_args_tree(out, arg_node->cl_head);
485 			fprintf(out, ")");
486 		}
487 		if (arg_node->next)
488 			fprintf(out, " ");
489 		arg_node = arg_node->next;
490 	}
491 }
492 
macro_param_flavor_to_string(enum cil_flavor flavor)493 static const char *macro_param_flavor_to_string(enum cil_flavor flavor)
494 {
495 	const char *str;
496 	switch(flavor) {
497 	case CIL_TYPE:
498 		str = CIL_KEY_TYPE;
499 		break;
500 	case CIL_ROLE:
501 		str = CIL_KEY_ROLE;
502 		break;
503 	case CIL_USER:
504 		str = CIL_KEY_USER;
505 		break;
506 	case CIL_SENS:
507 		str = CIL_KEY_SENSITIVITY;
508 		break;
509 	case CIL_CAT:
510 		str = CIL_KEY_CATEGORY;
511 		break;
512 	case CIL_CATSET:
513 		str = CIL_KEY_CATSET;
514 		break;
515 	case CIL_LEVEL:
516 		str = CIL_KEY_LEVEL;
517 		break;
518 	case CIL_LEVELRANGE:
519 		str = CIL_KEY_LEVELRANGE;
520 		break;
521 	case CIL_CLASS:
522 		str = CIL_KEY_CLASS;
523 		break;
524 	case CIL_IPADDR:
525 		str = CIL_KEY_IPADDR;
526 		break;
527 	case CIL_MAP_CLASS:
528 		str = CIL_KEY_MAP_CLASS;
529 		break;
530 	case CIL_CLASSPERMISSION:
531 		str = CIL_KEY_CLASSPERMISSION;
532 		break;
533 	case CIL_BOOL:
534 		str = CIL_KEY_BOOL;
535 		break;
536 	case CIL_STRING:
537 		str = CIL_KEY_STRING;
538 		break;
539 	case CIL_NAME:
540 		str = CIL_KEY_NAME;
541 		break;
542 	default:
543 		str = "<?FLAVOR>";
544 		break;
545 	}
546 	return str;
547 }
548 
cil_write_src_info_node(FILE * out,struct cil_tree_node * node)549 void cil_write_src_info_node(FILE *out, struct cil_tree_node *node)
550 {
551 	struct cil_src_info *info = node->data;
552 	if (info->kind == CIL_KEY_SRC_CIL || info->kind == CIL_KEY_SRC_HLL_LMS) {
553 		fprintf(out, ";;* lms %u %s\n", info->hll_line, info->path);
554 	} else if (info->kind == CIL_KEY_SRC_HLL_LMX) {
555 		fprintf(out, ";;* lmx %u %s\n", info->hll_line, info->path);
556 	} else {
557 		fprintf(out, ";;* <?SRC_INFO_KIND> %u %s\n", info->hll_line, info->path);
558 	}
559 }
560 
cil_write_ast_node(FILE * out,struct cil_tree_node * node)561 void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
562 {
563 	if (!node->data) {
564 		return;
565 	}
566 
567 	switch(node->flavor) {
568 	case CIL_NODE: {
569 		fprintf(out, "%s\n", (char *)node->data);
570 		break;
571 	}
572 	case CIL_BLOCK: {
573 		struct cil_block *block = node->data;
574 		fprintf(out, "(block %s", datum_to_str(DATUM(block)));
575 		if (!node->cl_head)
576 			fprintf(out, ")");
577 		fprintf(out, "\n");
578 		break;
579 	}
580 	case CIL_BLOCKINHERIT: {
581 		struct cil_blockinherit *inherit = node->data;
582 		fprintf(out, "(blockinherit %s)\n", datum_or_str(DATUM(inherit->block), inherit->block_str));
583 		break;
584 	}
585 	case CIL_IN: {
586 		struct cil_in *in = node->data;
587 		fprintf(out, "(in %s", in->block_str);
588 		if (!node->cl_head)
589 			fprintf(out, ")");
590 		fprintf(out, "\n");
591 		break;
592 	}
593 	case CIL_OPTIONAL: {
594 		struct cil_optional *optional = node->data;
595 		fprintf(out, "(optional %s", datum_to_str(DATUM(optional)));
596 		if (!node->cl_head)
597 			fprintf(out, ")");
598 		fprintf(out, "\n");
599 		break;
600 	}
601 	case CIL_BOOLEANIF: {
602 		struct cil_booleanif *bif = node->data;
603 		fprintf(out, "(booleanif ");
604 		if (bif->datum_expr)
605 			write_expr(out, bif->datum_expr);
606 		else
607 			write_expr(out, bif->str_expr);
608 		if (!node->cl_head)
609 			fprintf(out, ")");
610 		fprintf(out, "\n");
611 		break;
612 	}
613 	case CIL_TUNABLEIF: {
614 		struct cil_tunableif *tif = node->data;
615 		fprintf(out, "(tunableif ");
616 		if (tif->datum_expr)
617 			write_expr(out, tif->datum_expr);
618 		else
619 			write_expr(out, tif->str_expr);
620 		if (!node->cl_head)
621 			fprintf(out, ")");
622 		fprintf(out, "\n");
623 		break;
624 	}
625 	case CIL_CONDBLOCK: {
626 		struct cil_condblock *cb = node->data;
627 		fprintf(out, "(%s", cb->flavor == CIL_CONDTRUE ? "true" : "false");
628 		if (!node->cl_head)
629 			fprintf(out, ")");
630 		fprintf(out, "\n");
631 		break;
632 	}
633 	case CIL_MACRO: {
634 		struct cil_macro *macro = node->data;
635 		struct cil_list_item *curr;
636 		fprintf(out, "(macro %s (", datum_to_str(DATUM(macro)));
637 		if (macro->params) {
638 			cil_list_for_each(curr, macro->params) {
639 				struct cil_param *param = curr->data;
640 				fprintf(out, "(%s %s)", macro_param_flavor_to_string(param->flavor), param->str);
641 			}
642 		}
643 		fprintf(out, ")");
644 		if (!node->cl_head)
645 			fprintf(out, ")");
646 		fprintf(out, "\n");
647 		break;
648 	}
649 	case CIL_CALL: {
650 		struct cil_call *call = node->data;
651 		fprintf(out, "(call %s", datum_or_str(DATUM(call->macro), call->macro_str));
652 		if (call->args) {
653 			fprintf(out, " ");
654 			write_call_args(out, call->args);
655 		} else if (call->args_tree) {
656 			fprintf(out, " ");
657 			write_call_args_tree(out, call->args_tree->root);
658 		}
659 		if (!node->cl_head)
660 			fprintf(out, ")");
661 		fprintf(out, "\n");
662 		break;
663 	}
664 	case CIL_BLOCKABSTRACT: {
665 		struct cil_blockabstract *abstract = node->data;
666 		fprintf(out, "(blockabstract %s)\n", abstract->block_str);
667 		break;
668 	}
669 	case CIL_MLS: {
670 		struct cil_mls *mls = node->data;
671 		fprintf(out, "(mls %s)\n", mls->value ? "true" : "false");
672 		break;
673 	}
674 	case CIL_HANDLEUNKNOWN: {
675 		struct cil_handleunknown *unknown = node->data;
676 		fprintf(out, "(handleunknown ");
677 		if (unknown->handle_unknown == SEPOL_ALLOW_UNKNOWN)
678 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_ALLOW);
679 		else if (unknown->handle_unknown == SEPOL_DENY_UNKNOWN)
680 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_DENY);
681 		else if (unknown->handle_unknown == SEPOL_REJECT_UNKNOWN)
682 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_REJECT);
683 		else
684 			fprintf(out, "<?UNKNOWN>");
685 		fprintf(out, ")\n");
686 		break;
687 	}
688 	case CIL_DEFAULTUSER: {
689 		struct cil_default *def = node->data;
690 		fprintf(out, "(defaultuser ");
691 		if (def->class_datums)
692 			write_datum_list(out, def->class_datums);
693 		else
694 			write_string_list(out, def->class_strs);
695 		if (def->object == CIL_DEFAULT_SOURCE)
696 			fprintf(out, " source");
697 		else if (def->object == CIL_DEFAULT_TARGET)
698 			fprintf(out, " target");
699 		else
700 			fprintf(out, " <?DEFAULT>");
701 		fprintf(out, ")\n");
702 		break;
703 	}
704 	case CIL_DEFAULTROLE: {
705 		struct cil_default *def = node->data;
706 		fprintf(out, "(defaultrole ");
707 		if (def->class_datums)
708 			write_datum_list(out, def->class_datums);
709 		else
710 			write_string_list(out, def->class_strs);
711 		if (def->object == CIL_DEFAULT_SOURCE)
712 			fprintf(out, " source");
713 		else if (def->object == CIL_DEFAULT_TARGET)
714 			fprintf(out, " target");
715 		else
716 			fprintf(out, " <?DEFAULT>");
717 		fprintf(out, ")\n");
718 		break;
719 	}
720 	case CIL_DEFAULTTYPE: {
721 		struct cil_default *def = node->data;
722 		fprintf(out, "(defaulttype ");
723 		if (def->class_datums)
724 			write_datum_list(out, def->class_datums);
725 		else
726 			write_string_list(out, def->class_strs);
727 		if (def->object == CIL_DEFAULT_SOURCE)
728 			fprintf(out, " source");
729 		else if (def->object == CIL_DEFAULT_TARGET)
730 			fprintf(out, " target");
731 		else
732 			fprintf(out, " <?DEFAULT>");
733 		fprintf(out, ")\n");
734 		break;
735 	}
736 	case CIL_DEFAULTRANGE: {
737 		struct cil_defaultrange *def = node->data;
738 		fprintf(out, "(defaultrange ");
739 		if (def->class_datums)
740 			write_datum_list(out, def->class_datums);
741 		else
742 			write_string_list(out, def->class_strs);
743 		if (def->object_range == CIL_DEFAULT_SOURCE_LOW)
744 			fprintf(out, " source low");
745 		else if (def->object_range == CIL_DEFAULT_SOURCE_HIGH)
746 			fprintf(out, " source high");
747 		else if (def->object_range == CIL_DEFAULT_SOURCE_LOW_HIGH)
748 			fprintf(out, " source low-high");
749 		else if (def->object_range == CIL_DEFAULT_TARGET_LOW)
750 			fprintf(out, " target low");
751 		else if (def->object_range == CIL_DEFAULT_TARGET_HIGH)
752 			fprintf(out, " target high");
753 		else if (def->object_range == CIL_DEFAULT_TARGET_LOW_HIGH)
754 			fprintf(out, " target low-high");
755 		else
756 			fprintf(out, " <?DEFAULT>");
757 		fprintf(out, ")\n");
758 		break;
759 	}
760 	case CIL_CLASS: {
761 		struct cil_class *class = node->data;
762 		fprintf(out, "(class %s ", datum_to_str(DATUM(class)));
763 		write_node_list(out, node->cl_head);
764 		fprintf(out, ")\n");
765 		break;
766 	}
767 	case CIL_CLASSORDER: {
768 		struct cil_classorder *classorder = node->data;
769 		fprintf(out, "(classorder ");
770 		write_string_list(out, classorder->class_list_str);
771 		fprintf(out, ")\n");
772 		break;
773 	}
774 	case CIL_COMMON: {
775 		struct cil_class *common = node->data;
776 		fprintf(out, "(common %s ", datum_to_str(DATUM(common)));
777 		write_node_list(out, node->cl_head);
778 		fprintf(out, ")\n");
779 		break;
780 	}
781 	case CIL_CLASSCOMMON: {
782 		struct cil_classcommon *cc = node->data;
783 		fprintf(out, "(classcommon %s %s)\n", cc->class_str, cc->common_str);
784 		break;
785 	}
786 	case CIL_CLASSPERMISSION: {
787 		struct cil_classpermission *cp = node->data;
788 		fprintf(out, "(classpermission %s)\n", datum_to_str(DATUM(cp)));
789 		break;
790 	}
791 	case CIL_CLASSPERMISSIONSET: {
792 		struct cil_classpermissionset *cps = node->data;
793 		fprintf(out, "(classpermissionset %s ", cps->set_str);
794 		write_classperms_list(out, cps->classperms);
795 		fprintf(out, ")\n");
796 		break;
797 	}
798 	case CIL_MAP_CLASS: {
799 		struct cil_class *map = node->data;
800 		fprintf(out, "(classmap %s ", datum_to_str(DATUM(map)));
801 		write_node_list(out, node->cl_head);
802 		fprintf(out, ")\n");
803 		break;
804 	}
805 	case CIL_CLASSMAPPING: {
806 		struct cil_classmapping *mapping = node->data;
807 		fprintf(out, "(classmapping %s %s ", mapping->map_class_str, mapping->map_perm_str);
808 		write_classperms_list(out, mapping->classperms);
809 		fprintf(out, ")\n");
810 		break;
811 	}
812 	case CIL_PERMISSIONX: {
813 		struct cil_permissionx *permx = node->data;
814 		fprintf(out, "(permissionx %s (", datum_to_str(DATUM(permx)));
815 		fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>");
816 		fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str));
817 		write_expr(out, permx->expr_str);
818 		fprintf(out, "))\n");
819 		break;
820 	}
821 	case CIL_SID: {
822 		struct cil_sid *sid = node->data;
823 		fprintf(out, "(sid %s)\n", datum_to_str(DATUM(sid)));
824 		break;
825 	}
826 	case CIL_SIDCONTEXT: {
827 		struct cil_sidcontext *sidcon = node->data;
828 		fprintf(out, "(sidcontext %s ", sidcon->sid_str);
829 		if (sidcon->context)
830 			write_context(out, sidcon->context, CIL_TRUE);
831 		else
832 			fprintf(out, "%s", sidcon->context_str);
833 		fprintf(out, ")\n");
834 		break;
835 	}
836 	case CIL_SIDORDER: {
837 		struct cil_sidorder *sidorder = node->data;
838 		fprintf(out, "(sidorder ");
839 		write_string_list(out, sidorder->sid_list_str);
840 		fprintf(out, ")\n");
841 		break;
842 	}
843 	case CIL_BOOL: {
844 		struct cil_bool *boolean = node->data;
845 		fprintf(out, "(boolean %s %s)\n", datum_to_str(DATUM(boolean)), boolean->value ? "true" : "false");
846 		break;
847 	}
848 	case CIL_TUNABLE: {
849 		struct cil_tunable *tunable = node->data;
850 		fprintf(out, "(tunable %s %s)\n", datum_to_str(DATUM(tunable)), tunable->value ? "true" : "false");
851 		break;
852 	}
853 	case CIL_SENS: {
854 		struct cil_sens *sens = node->data;
855 		fprintf(out, "(sensitivity %s)\n", datum_to_str(DATUM(sens)));
856 		break;
857 	}
858 	case CIL_SENSALIAS: {
859 		struct cil_alias *alias = node->data;
860 		fprintf(out, "(sensitivityalias %s)\n", datum_to_str(DATUM(alias)));
861 		break;
862 	}
863 	case CIL_SENSALIASACTUAL: {
864 		struct cil_aliasactual *aliasactual = node->data;
865 		fprintf(out, "(sensitivityaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
866 		break;
867 	}
868 	case CIL_CAT: {
869 		struct cil_cat *cat = node->data;
870 		fprintf(out, "(category %s)\n", datum_to_str(DATUM(cat)));
871 		break;
872 	}
873 	case CIL_CATALIAS: {
874 		struct cil_alias *alias = node->data;
875 		fprintf(out, "(categoryalias %s)\n", datum_to_str(DATUM(alias)));
876 		break;
877 	}
878 	case CIL_CATALIASACTUAL: {
879 		struct cil_aliasactual *aliasactual = node->data;
880 		fprintf(out, "(categoryaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
881 		break;
882 	}
883 	case CIL_CATSET: {
884 		struct cil_catset *catset = node->data;
885 		fprintf(out, "(categoryset %s ", datum_to_str(DATUM(catset)));
886 		write_cats(out, catset->cats);
887 		fprintf(out, ")\n");
888 		break;
889 	}
890 	case CIL_CATORDER: {
891 		struct cil_catorder *catorder = node->data;
892 		fprintf(out, "(categoryorder ");
893 		write_string_list(out, catorder->cat_list_str);
894 		fprintf(out, ")\n");
895 		break;
896 	}
897 	case CIL_SENSCAT: {
898 		struct cil_senscat *senscat = node->data;
899 		fprintf(out, "(sensitivitycategory ");
900 		fprintf(out, "%s ", senscat->sens_str);
901 		write_cats(out, senscat->cats);
902 		fprintf(out, ")\n");
903 		break;
904 	}
905 	case CIL_SENSITIVITYORDER: {
906 		struct cil_sensorder *sensorder = node->data;
907 		fprintf(out, "(sensitivityorder ");
908 		write_string_list(out, sensorder->sens_list_str);
909 		fprintf(out, ")\n");
910 		break;
911 	}
912 	case CIL_LEVEL: {
913 		struct cil_level *level = node->data;
914 		fprintf(out, "(level %s ", datum_to_str(&level->datum));
915 		write_level(out, level, CIL_FALSE);
916 		fprintf(out, ")\n");
917 		break;
918 	}
919 	case CIL_LEVELRANGE: {
920 		struct cil_levelrange *lvlrange = node->data;
921 		fprintf(out, "(levelrange %s ", datum_to_str(DATUM(lvlrange)));
922 		write_range(out, lvlrange, CIL_FALSE);
923 		fprintf(out, ")\n");
924 		break;
925 	}
926 	case CIL_USER: {
927 		struct cil_user *user = node->data;
928 		fprintf(out, "(user %s)\n", datum_to_str(DATUM(user)));
929 		break;
930 	}
931 	case CIL_USERATTRIBUTE: {
932 		struct cil_userattribute *attr = node->data;
933 		fprintf(out, "(userattribute %s)\n", datum_to_str(DATUM(attr)));
934 		break;
935 	}
936 	case CIL_USERATTRIBUTESET: {
937 		struct cil_userattributeset *attr = node->data;
938 		fprintf(out, "(userattributeset %s ", attr->attr_str);
939 		if (attr->datum_expr)
940 			write_expr(out, attr->datum_expr);
941 		else
942 			write_expr(out, attr->str_expr);
943 		fprintf(out, ")\n");
944 		break;
945 	}
946 	case CIL_USERROLE: {
947 		struct cil_userrole *userrole = node->data;
948 		fprintf(out, "(userrole ");
949 		fprintf(out, "%s ", datum_or_str(userrole->user, userrole->user_str));
950 		fprintf(out, "%s", datum_or_str(userrole->role, userrole->role_str));
951 		fprintf(out, ")\n");
952 		break;
953 	}
954 	case CIL_USERLEVEL: {
955 		struct cil_userlevel *userlevel = node->data;
956 		fprintf(out, "(userlevel %s ", userlevel->user_str);
957 		if (userlevel->level)
958 			write_level(out, userlevel->level, CIL_TRUE);
959 		else
960 			fprintf(out, "%s", userlevel->level_str);
961 		fprintf(out, ")\n");
962 		break;
963 	}
964 	case CIL_USERRANGE: {
965 		struct cil_userrange *userrange = node->data;
966 		fprintf(out, "(userrange %s ", userrange->user_str);
967 		if (userrange->range)
968 			write_range(out, userrange->range, CIL_TRUE);
969 		else
970 			fprintf(out, "%s", userrange->range_str);
971 		fprintf(out, ")\n");
972 		break;
973 	}
974 	case CIL_USERBOUNDS: {
975 		struct cil_bounds *bounds = node->data;
976 		fprintf(out, "(userbounds %s %s)\n", bounds->parent_str, bounds->child_str);
977 		break;
978 	}
979 	case CIL_USERPREFIX: {
980 		struct cil_userprefix *prefix = node->data;
981 		fprintf(out, "(userprefix ");
982 		fprintf(out, "%s ", datum_or_str(DATUM(prefix->user), prefix->user_str));
983 		fprintf(out, "%s)\n", prefix->prefix_str);
984 		break;
985 	}
986 	case CIL_SELINUXUSER: {
987 		struct cil_selinuxuser *selinuxuser = node->data;
988 		fprintf(out, "(selinuxuser %s ", selinuxuser->name_str);
989 		fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str));
990 		if (selinuxuser->range)
991 			write_range(out, selinuxuser->range, CIL_TRUE);
992 		else
993 			fprintf(out, "%s", selinuxuser->range_str);
994 		fprintf(out, ")\n");
995 		break;
996 	}
997 	case CIL_SELINUXUSERDEFAULT: {
998 		struct cil_selinuxuser *selinuxuser = node->data;
999 		fprintf(out, "(selinuxuserdefault ");
1000 		fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str));
1001 		if (selinuxuser->range)
1002 			write_range(out, selinuxuser->range, CIL_TRUE);
1003 		else
1004 			fprintf(out, "%s", selinuxuser->range_str);
1005 		fprintf(out, ")\n");
1006 		break;
1007 	}
1008 	case CIL_ROLE: {
1009 		fprintf(out, "(role %s)\n", datum_to_str(node->data));
1010 		break;
1011 	}
1012 	case CIL_ROLEATTRIBUTE: {
1013 		fprintf(out, "(roleattribute %s)\n", datum_to_str(node->data));
1014 		break;
1015 	}
1016 	case CIL_ROLEATTRIBUTESET: {
1017 		struct cil_roleattributeset *attr = node->data;
1018 		fprintf(out, "(roleattributeset %s ", attr->attr_str);
1019 		if (attr->datum_expr)
1020 			write_expr(out, attr->datum_expr);
1021 		else
1022 			write_expr(out, attr->str_expr);
1023 		fprintf(out, ")\n");
1024 		break;
1025 	}
1026 	case CIL_ROLETYPE: {
1027 		struct cil_roletype *roletype = node->data;
1028 		fprintf(out, "(roletype ");
1029 		fprintf(out, "%s ", datum_or_str(DATUM(roletype->role), roletype->role_str));
1030 		fprintf(out, "%s", datum_or_str(DATUM(roletype->type), roletype->type_str));
1031 		fprintf(out, ")\n");
1032 		break;
1033 	}
1034 	case CIL_ROLEBOUNDS: {
1035 		struct cil_bounds *bnds = node->data;
1036 		fprintf(out, "(rolebounds %s %s)\n", bnds->parent_str, bnds->child_str);
1037 		break;
1038 	}
1039 	case CIL_TYPE: {
1040 		fprintf(out, "(type %s)\n", datum_to_str(node->data));
1041 		break;
1042 	}
1043 	case CIL_TYPEALIAS: {
1044 		fprintf(out, "(typealias %s)\n", datum_to_str(node->data));
1045 		break;
1046 	}
1047 	case CIL_TYPEALIASACTUAL: {
1048 		struct cil_aliasactual *aliasactual = node->data;
1049 		fprintf(out, "(typealiasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
1050 		break;
1051 	}
1052 	case CIL_TYPEATTRIBUTE: {
1053 		fprintf(out, "(typeattribute %s)\n", datum_to_str(node->data));
1054 		break;
1055 	}
1056 	case CIL_TYPEATTRIBUTESET: {
1057 		struct cil_typeattributeset *attr = node->data;
1058 		fprintf(out, "(typeattributeset %s ", attr->attr_str);
1059 		if (attr->datum_expr)
1060 			write_expr(out, attr->datum_expr);
1061 		else
1062 			write_expr(out, attr->str_expr);
1063 		fprintf(out, ")\n");
1064 		break;
1065 	}
1066 	case CIL_EXPANDTYPEATTRIBUTE: {
1067 		struct cil_expandtypeattribute *attr = node->data;
1068 		fprintf(out, "(expandtypeattribute ");
1069 		if (attr->attr_datums)
1070 			write_expr(out, attr->attr_datums);
1071 		else
1072 			write_expr(out, attr->attr_strs);
1073 		fprintf(out, " %s)\n", attr->expand ? "true" : "false");
1074 		break;
1075 	}
1076 	case CIL_TYPEPERMISSIVE: {
1077 		struct cil_typepermissive *tp = node->data;
1078 		fprintf(out, "(typepermissive ");
1079 		fprintf(out, "%s", datum_or_str(DATUM(tp->type), tp->type_str));
1080 		fprintf(out, ")\n");
1081 		break;
1082 	}
1083 	case CIL_TYPEBOUNDS: {
1084 		struct cil_bounds *bounds = node->data;
1085 		fprintf(out, "(typebounds %s %s)\n", bounds->parent_str, bounds->child_str);
1086 		break;
1087 	}
1088 	case CIL_ROLEALLOW: {
1089 		struct cil_roleallow *roleallow = node->data;
1090 		fprintf(out, "(roleallow ");
1091 		fprintf(out, "%s ", datum_or_str(DATUM(roleallow->src), roleallow->src_str));
1092 		fprintf(out, "%s", datum_or_str(DATUM(roleallow->tgt), roleallow->tgt_str));
1093 		fprintf(out, ")\n");
1094 		break;
1095 	}
1096 	case CIL_ROLETRANSITION: {
1097 		struct cil_roletransition *roletrans = node->data;
1098 		fprintf(out, "(roletransition ");
1099 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->src), roletrans->src_str));
1100 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->tgt), roletrans->tgt_str));
1101 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->obj), roletrans->obj_str));
1102 		fprintf(out, "%s", datum_or_str(DATUM(roletrans->result), roletrans->result_str));
1103 		fprintf(out, ")\n");
1104 		break;
1105 	}
1106 	case CIL_AVRULE: {
1107 		struct cil_avrule *rule = node->data;
1108 		if (rule->rule_kind == AVRULE_ALLOWED)
1109 			fprintf(out, "(allow ");
1110 		else if (rule->rule_kind == AVRULE_AUDITALLOW)
1111 			fprintf(out, "(auditallow ");
1112 		else if (rule->rule_kind == AVRULE_DONTAUDIT)
1113 			fprintf(out, "(dontaudit ");
1114 		else if (rule->rule_kind == AVRULE_NEVERALLOW)
1115 			fprintf(out, "(neverallow ");
1116 		else
1117 			fprintf(out, "(<?AVRULE> ");
1118 
1119 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1120 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1121 		write_classperms_list(out, rule->perms.classperms);
1122 		fprintf(out, ")\n");
1123 		break;
1124 	}
1125 	case CIL_AVRULEX: {
1126 		struct cil_avrule *rule = node->data;
1127 		if (rule->rule_kind == AVRULE_ALLOWED)
1128 			fprintf(out, "(allowx ");
1129 		else if (rule->rule_kind == AVRULE_AUDITALLOW)
1130 			fprintf(out, "(auditallowx ");
1131 		else if (rule->rule_kind == AVRULE_DONTAUDIT)
1132 			fprintf(out, "(dontauditx ");
1133 		else if (rule->rule_kind == AVRULE_NEVERALLOW)
1134 			fprintf(out, "(neverallowx ");
1135 		else
1136 			fprintf(out, "(<?AVRULEX> ");
1137 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1138 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1139 		if (rule->perms.x.permx_str) {
1140 			fprintf(out, "%s",rule->perms.x.permx_str);
1141 		} else {
1142 			write_permx(out, rule->perms.x.permx);
1143 		}
1144 		fprintf(out, ")\n");
1145 		break;
1146 	}
1147 	case CIL_TYPE_RULE: {
1148 		struct cil_type_rule *rule = node->data;
1149 		if (rule->rule_kind == AVRULE_TRANSITION)
1150 			fprintf(out, "(typetransition ");
1151 		else if (rule->rule_kind == AVRULE_MEMBER)
1152 			fprintf(out, "(typemember ");
1153 		else if (rule->rule_kind == AVRULE_CHANGE)
1154 			fprintf(out, "(typechange ");
1155 		else
1156 			fprintf(out, "(<?TYPERULE> ");
1157 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1158 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1159 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1160 		fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
1161 		fprintf(out, ")\n");
1162 		break;
1163 	}
1164 	case CIL_NAMETYPETRANSITION: {
1165 		struct cil_nametypetransition *rule = node->data;
1166 		fprintf(out, "(typetransition ");
1167 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1168 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1169 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1170 		fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str));
1171 		fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
1172 		fprintf(out, ")\n");
1173 		break;
1174 	}
1175 	case CIL_RANGETRANSITION: {
1176 		struct cil_rangetransition *rule = node->data;
1177 		fprintf(out, "(rangetransition ");
1178 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1179 		fprintf(out, "%s ", datum_or_str(DATUM(rule->exec), rule->exec_str));
1180 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1181 		if (rule->range)
1182 			write_range(out, rule->range, CIL_TRUE);
1183 		else
1184 			fprintf(out, "%s", rule->range_str);
1185 		fprintf(out, ")\n");
1186 		break;
1187 	}
1188 	case CIL_CONSTRAIN: {
1189 		struct cil_constrain *cons = node->data;
1190 		fprintf(out, "(constrain ");
1191 		write_constrain(out, cons);
1192 		fprintf(out, ")\n");
1193 		break;
1194 	}
1195 	case CIL_MLSCONSTRAIN: {
1196 		struct cil_constrain *cons = node->data;
1197 		fprintf(out, "(mlsconstrain ");
1198 		write_constrain(out, cons);
1199 		fprintf(out, ")\n");
1200 		break;
1201 	}
1202 	case CIL_VALIDATETRANS: {
1203 		struct cil_validatetrans *vt = node->data;
1204 		fprintf(out, "(validatetrans ");
1205 		fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str));
1206 		if (vt->datum_expr)
1207 			write_expr(out, vt->datum_expr);
1208 		else
1209 			write_expr(out, vt->str_expr);
1210 		fprintf(out, ")\n");
1211 		break;
1212 	}
1213 	case CIL_MLSVALIDATETRANS: {
1214 		struct cil_validatetrans *vt = node->data;
1215 		fprintf(out, "(mlsvalidatetrans ");
1216 		fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str));
1217 		if (vt->datum_expr)
1218 			write_expr(out, vt->datum_expr);
1219 		else
1220 			write_expr(out, vt->str_expr);
1221 		fprintf(out, ")\n");
1222 		break;
1223 	}
1224 	case CIL_CONTEXT: {
1225 		struct cil_context *context = node->data;
1226 		fprintf(out, "(context %s ", datum_to_str(DATUM(context)));
1227 		write_context(out, context, CIL_FALSE);
1228 		fprintf(out, ")\n");
1229 		break;
1230 	}
1231 	case CIL_FILECON: {
1232 		struct cil_filecon *filecon = node->data;
1233 		fprintf(out, "(filecon ");
1234 		fprintf(out, "\"%s\" ", filecon->path_str);
1235 		if (filecon->type == CIL_FILECON_FILE)
1236 			fprintf(out, "%s ", CIL_KEY_FILE);
1237 		else if (filecon->type == CIL_FILECON_DIR)
1238 			fprintf(out, "%s ", CIL_KEY_DIR);
1239 		else if (filecon->type == CIL_FILECON_CHAR)
1240 			fprintf(out, "%s ", CIL_KEY_CHAR);
1241 		else if (filecon->type == CIL_FILECON_BLOCK)
1242 			fprintf(out, "%s ", CIL_KEY_BLOCK);
1243 		else if (filecon->type == CIL_FILECON_SOCKET)
1244 			fprintf(out, "%s ", CIL_KEY_SOCKET);
1245 		else if (filecon->type == CIL_FILECON_PIPE)
1246 			fprintf(out, "%s ", CIL_KEY_PIPE);
1247 		else if (filecon->type == CIL_FILECON_SYMLINK)
1248 			fprintf(out, "%s ", CIL_KEY_SYMLINK);
1249 		else if (filecon->type == CIL_FILECON_ANY)
1250 			fprintf(out, "%s ", CIL_KEY_ANY);
1251 		else
1252 			fprintf(out, "<?FILETYPE> ");
1253 		if (filecon->context)
1254 			write_context(out, filecon->context, CIL_TRUE);
1255 		else if (filecon->context_str)
1256 			fprintf(out, "%s", filecon->context_str);
1257 		else
1258 			fprintf(out, "()");
1259 		fprintf(out, ")\n");
1260 		break;
1261 	}
1262 	case CIL_IBPKEYCON: {
1263 		struct cil_ibpkeycon *ibpkeycon = node->data;
1264 		fprintf(out, "(ibpkeycon %s ", ibpkeycon->subnet_prefix_str);
1265 		fprintf(out, "(%d %d) ", ibpkeycon->pkey_low, ibpkeycon->pkey_high);
1266 		if (ibpkeycon->context)
1267 			write_context(out, ibpkeycon->context, CIL_TRUE);
1268 		else if (ibpkeycon->context_str)
1269 			fprintf(out, "%s", ibpkeycon->context_str);
1270 		fprintf(out, ")\n");
1271 		break;
1272 	}
1273 	case CIL_PORTCON: {
1274 		struct cil_portcon *portcon = node->data;
1275 		fprintf(out, "(portcon ");
1276 		if (portcon->proto == CIL_PROTOCOL_UDP)
1277 			fprintf(out, " udp ");
1278 		else if (portcon->proto == CIL_PROTOCOL_TCP)
1279 			fprintf(out, " tcp ");
1280 		else if (portcon->proto == CIL_PROTOCOL_DCCP)
1281 			fprintf(out, "dccp ");
1282 		else if (portcon->proto == CIL_PROTOCOL_SCTP)
1283 			fprintf(out, "sctp ");
1284 		else
1285 			fprintf(out, "<?PROTOCOL> ");
1286 		if (portcon->port_low == portcon->port_high)
1287 			fprintf(out, "%d ", portcon->port_low);
1288 		else
1289 			fprintf(out, "(%d %d) ", portcon->port_low, portcon->port_high);
1290 		if (portcon->context)
1291 			write_context(out, portcon->context, CIL_TRUE);
1292 		else
1293 			fprintf(out, "%s", portcon->context_str);
1294 		fprintf(out, ")\n");
1295 		break;
1296 	}
1297 	case CIL_NODECON: {
1298 		struct cil_nodecon *nodecon = node->data;
1299 		fprintf(out, "(nodecon ");
1300 		if (nodecon->addr)
1301 			write_ipaddr(out, nodecon->addr);
1302 		else
1303 			fprintf(out, "%s ", nodecon->addr_str);
1304 		fprintf(out, " ");
1305 		if (nodecon->mask)
1306 			write_ipaddr(out, nodecon->mask);
1307 		else
1308 			fprintf(out, "%s ", nodecon->mask_str);
1309 		fprintf(out, " ");
1310 		if (nodecon->context)
1311 			write_context(out, nodecon->context, CIL_TRUE);
1312 		else
1313 			fprintf(out, "%s", nodecon->context_str);
1314 		fprintf(out, ")\n");
1315 		break;
1316 	}
1317 	case CIL_GENFSCON: {
1318 		struct cil_genfscon *genfscon = node->data;
1319 		fprintf(out, "(genfscon ");
1320 		fprintf(out, "%s \"%s\" ", genfscon->fs_str, genfscon->path_str);
1321 		if (genfscon->context)
1322 			write_context(out, genfscon->context, CIL_TRUE);
1323 		else
1324 			fprintf(out, "%s", genfscon->context_str);
1325 		fprintf(out, ")\n");
1326 		break;
1327 	}
1328 	case CIL_NETIFCON: {
1329 		struct cil_netifcon *netifcon = node->data;
1330 		fprintf(out, "(netifcon %s ", netifcon->interface_str);
1331 		if (netifcon->if_context)
1332 			write_context(out, netifcon->if_context, CIL_TRUE);
1333 		else
1334 			fprintf(out, "%s", netifcon->if_context_str);
1335 		fprintf(out, " ");
1336 		if (netifcon->packet_context)
1337 			write_context(out, netifcon->packet_context, CIL_TRUE);
1338 		else
1339 			fprintf(out, "%s", netifcon->packet_context_str);
1340 		fprintf(out, ")\n");
1341 		break;
1342 	}
1343 	case CIL_IBENDPORTCON: {
1344 		struct cil_ibendportcon *ibendportcon = node->data;
1345 		fprintf(out, "(ibendportcon %s %u ", ibendportcon->dev_name_str, ibendportcon->port);
1346 		if (ibendportcon->context)
1347 			write_context(out, ibendportcon->context, CIL_TRUE);
1348 		else
1349 			fprintf(out, "%s", ibendportcon->context_str);
1350 		fprintf(out, ")\n");
1351 		break;
1352 	}
1353 	case CIL_PIRQCON: {
1354 		struct cil_pirqcon *pirqcon = node->data;
1355 		fprintf(out, "(pirqcon %d ", pirqcon->pirq);
1356 		if (pirqcon->context)
1357 			write_context(out, pirqcon->context, CIL_TRUE);
1358 		else
1359 			fprintf(out, "%s", pirqcon->context_str);
1360 		fprintf(out, ")\n");
1361 		break;
1362 	}
1363 	case CIL_IOMEMCON: {
1364 		struct cil_iomemcon *iomemcon = node->data;
1365 		fprintf(out, "(iomemcon (%"PRId64" %"PRId64") ", iomemcon->iomem_low, iomemcon->iomem_high);
1366 		if (iomemcon->context)
1367 			write_context(out, iomemcon->context, CIL_TRUE);
1368 		else
1369 			fprintf(out, "%s", iomemcon->context_str);
1370 		fprintf(out, ")\n");
1371 		break;
1372 	}
1373 	case CIL_IOPORTCON: {
1374 		struct cil_ioportcon *ioportcon = node->data;
1375 		fprintf(out, "(ioportcon ");
1376 		if (ioportcon->ioport_low == ioportcon->ioport_high)
1377 			fprintf(out, "%d ", ioportcon->ioport_low);
1378 		else
1379 			fprintf(out, "(%d %d) ", ioportcon->ioport_low, ioportcon->ioport_high);
1380 
1381 		if (ioportcon->context)
1382 			write_context(out, ioportcon->context, CIL_TRUE);
1383 		else
1384 			fprintf(out, "%s", ioportcon->context_str);
1385 		fprintf(out, ")\n");
1386 		break;
1387 	}
1388 	case CIL_PCIDEVICECON: {
1389 		struct cil_pcidevicecon *pcidevicecon = node->data;
1390 		fprintf(out, "(pcidevicecon %d ", pcidevicecon->dev);
1391 		if (pcidevicecon->context)
1392 			write_context(out, pcidevicecon->context, CIL_TRUE);
1393 		else
1394 			fprintf(out, "%s", pcidevicecon->context_str);
1395 		fprintf(out, ")\n");
1396 		break;
1397 	}
1398 	case CIL_DEVICETREECON: {
1399 		struct cil_devicetreecon *devicetreecon = node->data;
1400 		fprintf(out, "(devicetreecon \"%s\" ", devicetreecon->path);
1401 		if (devicetreecon->context)
1402 			write_context(out, devicetreecon->context, CIL_TRUE);
1403 		else
1404 			fprintf(out, "%s", devicetreecon->context_str);
1405 		fprintf(out, ")\n");
1406 		break;
1407 	}
1408 	case CIL_FSUSE: {
1409 		struct cil_fsuse *fsuse = node->data;
1410 		fprintf(out, "(fsuse ");
1411 		if (fsuse->type == CIL_FSUSE_XATTR)
1412 			fprintf(out, "xattr ");
1413 		else if (fsuse->type == CIL_FSUSE_TASK)
1414 			fprintf(out, "task ");
1415 		else if (fsuse->type == CIL_FSUSE_TRANS)
1416 			fprintf(out, "trans ");
1417 		else
1418 			fprintf(out, "<?TYPE> ");
1419 		fprintf(out, "%s ", fsuse->fs_str);
1420 		if (fsuse->context)
1421 			write_context(out, fsuse->context, CIL_TRUE);
1422 		else
1423 			fprintf(out, "%s", fsuse->context_str);
1424 		fprintf(out, ")\n");
1425 		break;
1426 	}
1427 	case CIL_POLICYCAP: {
1428 		struct cil_policycap *polcap = node->data;
1429 		fprintf(out, "(policycap %s)\n", polcap->datum.name);
1430 		break;
1431 	}
1432 	case CIL_IPADDR: {
1433 		struct cil_ipaddr *ipaddr = node->data;
1434 		char buf[256];
1435 		if (inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256) == NULL)
1436 			strcpy(buf, "<?IPADDR>");
1437 		fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf);
1438 		break;
1439 	}
1440 	default :
1441 		fprintf(out, "(<?RULE:%s>)\n", cil_node_to_string(node));
1442 		break;
1443 	}
1444 }
1445 
1446 /*
1447  * Tree walk data and helper functions for writing the AST of the various phases
1448  */
1449 
1450 struct cil_write_ast_args {
1451 	FILE *out;
1452 	int depth;
1453 };
1454 
1455 /*
1456  * Helper functions for writing the parse AST
1457  */
1458 
__write_parse_ast_node_helper(struct cil_tree_node * node,uint32_t * finished,void * extra_args)1459 static int __write_parse_ast_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
1460 {
1461 	struct cil_write_ast_args *args = extra_args;
1462 
1463 	fprintf(args->out, "%*s", args->depth*4, "");
1464 	if (!node->data) {
1465 		if (node->cl_head)
1466 			fprintf(args->out, "(\n");
1467 		else
1468 			fprintf(args->out, "()\n");
1469 	} else {
1470 		char *str = (char *)node->data;
1471 		size_t len = strlen(str);
1472 		size_t i;
1473 
1474 		for (i = 0; i < len; i++) {
1475 			if (isspace(str[i])) {
1476 				fprintf(args->out, "\"%s\"\n", str);
1477 				return SEPOL_OK;
1478 			}
1479 		}
1480 
1481 		fprintf(args->out, "%s\n", (char *)node->data);
1482 	}
1483 
1484 	return SEPOL_OK;
1485 }
1486 
__write_parse_ast_first_child_helper(struct cil_tree_node * node,void * extra_args)1487 static int __write_parse_ast_first_child_helper(struct cil_tree_node *node, void *extra_args)
1488 {
1489 	struct cil_write_ast_args *args = extra_args;
1490 	struct cil_tree_node *parent = node->parent;
1491 
1492 	if (parent->flavor != CIL_ROOT) {
1493 		args->depth++;
1494 	}
1495 
1496 	return SEPOL_OK;
1497 }
1498 
__write_parse_ast_last_child_helper(struct cil_tree_node * node,void * extra_args)1499 static int __write_parse_ast_last_child_helper(struct cil_tree_node *node, void *extra_args)
1500 {
1501 	struct cil_write_ast_args *args = extra_args;
1502 	struct cil_tree_node *parent = node->parent;
1503 
1504 	if (parent->flavor == CIL_ROOT) {
1505 		return SEPOL_OK;
1506 	}
1507 
1508 	args->depth--;
1509 	fprintf(args->out, "%*s", args->depth*4, "");
1510 	fprintf(args->out, ")\n");
1511 
1512 	return SEPOL_OK;
1513 }
1514 
1515 /*
1516  * Helper functions for writing the CIL AST for the build and resolve phases
1517  */
1518 
__write_cil_ast_node_helper(struct cil_tree_node * node,uint32_t * finished,void * extra_args)1519 static int __write_cil_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
1520 {
1521 	struct cil_write_ast_args *args = extra_args;
1522 
1523 	if (node->flavor == CIL_SRC_INFO) {
1524 		cil_write_src_info_node(args->out, node);
1525 		return SEPOL_OK;
1526 	}
1527 
1528 	fprintf(args->out, "%*s", args->depth*4, "");
1529 
1530 	cil_write_ast_node(args->out, node);
1531 
1532 	if (node->flavor == CIL_CLASS || node->flavor == CIL_COMMON || node->flavor == CIL_MAP_CLASS) {
1533 		*finished = CIL_TREE_SKIP_HEAD;
1534 	}
1535 
1536 	return SEPOL_OK;
1537 }
1538 
__write_cil_ast_first_child_helper(struct cil_tree_node * node,void * extra_args)1539 static int __write_cil_ast_first_child_helper(struct cil_tree_node *node, void *extra_args)
1540 {
1541 	struct cil_write_ast_args *args = extra_args;
1542 	struct cil_tree_node *parent = node->parent;
1543 
1544 	if (parent->flavor != CIL_SRC_INFO && parent->flavor != CIL_ROOT) {
1545 		args->depth++;
1546 	}
1547 
1548 	return SEPOL_OK;
1549 }
1550 
__write_cil_ast_last_child_helper(struct cil_tree_node * node,void * extra_args)1551 static int __write_cil_ast_last_child_helper(struct cil_tree_node *node, void *extra_args)
1552 {
1553 	struct cil_write_ast_args *args = extra_args;
1554 	struct cil_tree_node *parent = node->parent;
1555 
1556 	if (parent->flavor == CIL_ROOT) {
1557 		return SEPOL_OK;
1558 	} else if (parent->flavor == CIL_SRC_INFO) {
1559 		fprintf(args->out, ";;* lme\n");
1560 		return SEPOL_OK;
1561 	}
1562 
1563 	args->depth--;
1564 	fprintf(args->out, "%*s", args->depth*4, "");
1565 	fprintf(args->out, ")\n");
1566 
1567 	return SEPOL_OK;
1568 }
1569 
cil_write_ast(FILE * out,enum cil_write_ast_phase phase,struct cil_tree_node * node)1570 int cil_write_ast(FILE *out, enum cil_write_ast_phase phase, struct cil_tree_node *node)
1571 {
1572 	struct cil_write_ast_args extra_args;
1573 	int rc;
1574 
1575 	extra_args.out = out;
1576 	extra_args.depth = 0;
1577 
1578 	if (phase == CIL_WRITE_AST_PHASE_PARSE) {
1579 		rc = cil_tree_walk(node, __write_parse_ast_node_helper, __write_parse_ast_first_child_helper, __write_parse_ast_last_child_helper, &extra_args);
1580 	} else {
1581 		rc = cil_tree_walk(node, __write_cil_ast_node_helper, __write_cil_ast_first_child_helper, __write_cil_ast_last_child_helper, &extra_args);
1582 	}
1583 
1584 	if (rc != SEPOL_OK) {
1585 		cil_log(CIL_ERR, "Failed to write AST\n");
1586 		return SEPOL_ERR;
1587 	}
1588 
1589 	return SEPOL_OK;
1590 }
1591