• 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 
549 /* ANDROID: not used.
550 static void cil_write_src_info_node(FILE *out, struct cil_tree_node *node)
551 {
552 	struct cil_src_info *info = node->data;
553 	if (info->kind == CIL_KEY_SRC_CIL || info->kind == CIL_KEY_SRC_HLL_LMS) {
554 		fprintf(out, ";;* lms %u %s\n", info->hll_line, info->path);
555 	} else if (info->kind == CIL_KEY_SRC_HLL_LMX) {
556 		fprintf(out, ";;* lmx %u %s\n", info->hll_line, info->path);
557 	} else {
558 		fprintf(out, ";;* <?SRC_INFO_KIND> %u %s\n", info->hll_line, info->path);
559 	}
560 }
561 */
562 
cil_write_ast_node(FILE * out,struct cil_tree_node * node)563 void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
564 {
565 	if (!node->data) {
566 		return;
567 	}
568 
569 	switch(node->flavor) {
570 	case CIL_NODE: {
571 		fprintf(out, "%s\n", (char *)node->data);
572 		break;
573 	}
574 	case CIL_BLOCK: {
575 		struct cil_block *block = node->data;
576 		fprintf(out, "(block %s", datum_to_str(DATUM(block)));
577 		if (!node->cl_head)
578 			fprintf(out, ")");
579 		fprintf(out, "\n");
580 		break;
581 	}
582 	case CIL_BLOCKINHERIT: {
583 		struct cil_blockinherit *inherit = node->data;
584 		fprintf(out, "(blockinherit %s)\n", datum_or_str(DATUM(inherit->block), inherit->block_str));
585 		break;
586 	}
587 	case CIL_IN: {
588 		struct cil_in *in = node->data;
589 		fprintf(out, "(in %s", in->block_str);
590 		if (!node->cl_head)
591 			fprintf(out, ")");
592 		fprintf(out, "\n");
593 		break;
594 	}
595 	case CIL_OPTIONAL: {
596 		struct cil_optional *optional = node->data;
597 		fprintf(out, "(optional %s", datum_to_str(DATUM(optional)));
598 		if (!node->cl_head)
599 			fprintf(out, ")");
600 		fprintf(out, "\n");
601 		break;
602 	}
603 	case CIL_BOOLEANIF: {
604 		struct cil_booleanif *bif = node->data;
605 		fprintf(out, "(booleanif ");
606 		if (bif->datum_expr)
607 			write_expr(out, bif->datum_expr);
608 		else
609 			write_expr(out, bif->str_expr);
610 		if (!node->cl_head)
611 			fprintf(out, ")");
612 		fprintf(out, "\n");
613 		break;
614 	}
615 	case CIL_TUNABLEIF: {
616 		struct cil_tunableif *tif = node->data;
617 		fprintf(out, "(tunableif ");
618 		if (tif->datum_expr)
619 			write_expr(out, tif->datum_expr);
620 		else
621 			write_expr(out, tif->str_expr);
622 		if (!node->cl_head)
623 			fprintf(out, ")");
624 		fprintf(out, "\n");
625 		break;
626 	}
627 	case CIL_CONDBLOCK: {
628 		struct cil_condblock *cb = node->data;
629 		fprintf(out, "(%s", cb->flavor == CIL_CONDTRUE ? "true" : "false");
630 		if (!node->cl_head)
631 			fprintf(out, ")");
632 		fprintf(out, "\n");
633 		break;
634 	}
635 	case CIL_MACRO: {
636 		struct cil_macro *macro = node->data;
637 		struct cil_list_item *curr;
638 		fprintf(out, "(macro %s (", datum_to_str(DATUM(macro)));
639 		if (macro->params) {
640 			cil_list_for_each(curr, macro->params) {
641 				struct cil_param *param = curr->data;
642 				fprintf(out, "(%s %s)", macro_param_flavor_to_string(param->flavor), param->str);
643 			}
644 		}
645 		fprintf(out, ")");
646 		if (!node->cl_head)
647 			fprintf(out, ")");
648 		fprintf(out, "\n");
649 		break;
650 	}
651 	case CIL_CALL: {
652 		struct cil_call *call = node->data;
653 		fprintf(out, "(call %s", datum_or_str(DATUM(call->macro), call->macro_str));
654 		if (call->args) {
655 			fprintf(out, " ");
656 			write_call_args(out, call->args);
657 		} else if (call->args_tree) {
658 			fprintf(out, " ");
659 			write_call_args_tree(out, call->args_tree->root);
660 		}
661 		if (!node->cl_head)
662 			fprintf(out, ")");
663 		fprintf(out, "\n");
664 		break;
665 	}
666 	case CIL_BLOCKABSTRACT: {
667 		struct cil_blockabstract *abstract = node->data;
668 		fprintf(out, "(blockabstract %s)\n", abstract->block_str);
669 		break;
670 	}
671 	case CIL_MLS: {
672 		struct cil_mls *mls = node->data;
673 		fprintf(out, "(mls %s)\n", mls->value ? "true" : "false");
674 		break;
675 	}
676 	case CIL_HANDLEUNKNOWN: {
677 		struct cil_handleunknown *unknown = node->data;
678 		fprintf(out, "(handleunknown ");
679 		if (unknown->handle_unknown == SEPOL_ALLOW_UNKNOWN)
680 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_ALLOW);
681 		else if (unknown->handle_unknown == SEPOL_DENY_UNKNOWN)
682 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_DENY);
683 		else if (unknown->handle_unknown == SEPOL_REJECT_UNKNOWN)
684 			fprintf(out, "%s", CIL_KEY_HANDLEUNKNOWN_REJECT);
685 		else
686 			fprintf(out, "<?UNKNOWN>");
687 		fprintf(out, ")\n");
688 		break;
689 	}
690 	case CIL_DEFAULTUSER: {
691 		struct cil_default *def = node->data;
692 		fprintf(out, "(defaultuser ");
693 		if (def->class_datums)
694 			write_datum_list(out, def->class_datums);
695 		else
696 			write_string_list(out, def->class_strs);
697 		if (def->object == CIL_DEFAULT_SOURCE)
698 			fprintf(out, " source");
699 		else if (def->object == CIL_DEFAULT_TARGET)
700 			fprintf(out, " target");
701 		else
702 			fprintf(out, " <?DEFAULT>");
703 		fprintf(out, ")\n");
704 		break;
705 	}
706 	case CIL_DEFAULTROLE: {
707 		struct cil_default *def = node->data;
708 		fprintf(out, "(defaultrole ");
709 		if (def->class_datums)
710 			write_datum_list(out, def->class_datums);
711 		else
712 			write_string_list(out, def->class_strs);
713 		if (def->object == CIL_DEFAULT_SOURCE)
714 			fprintf(out, " source");
715 		else if (def->object == CIL_DEFAULT_TARGET)
716 			fprintf(out, " target");
717 		else
718 			fprintf(out, " <?DEFAULT>");
719 		fprintf(out, ")\n");
720 		break;
721 	}
722 	case CIL_DEFAULTTYPE: {
723 		struct cil_default *def = node->data;
724 		fprintf(out, "(defaulttype ");
725 		if (def->class_datums)
726 			write_datum_list(out, def->class_datums);
727 		else
728 			write_string_list(out, def->class_strs);
729 		if (def->object == CIL_DEFAULT_SOURCE)
730 			fprintf(out, " source");
731 		else if (def->object == CIL_DEFAULT_TARGET)
732 			fprintf(out, " target");
733 		else
734 			fprintf(out, " <?DEFAULT>");
735 		fprintf(out, ")\n");
736 		break;
737 	}
738 	case CIL_DEFAULTRANGE: {
739 		struct cil_defaultrange *def = node->data;
740 		fprintf(out, "(defaultrange ");
741 		if (def->class_datums)
742 			write_datum_list(out, def->class_datums);
743 		else
744 			write_string_list(out, def->class_strs);
745 		if (def->object_range == CIL_DEFAULT_SOURCE_LOW)
746 			fprintf(out, " source low");
747 		else if (def->object_range == CIL_DEFAULT_SOURCE_HIGH)
748 			fprintf(out, " source high");
749 		else if (def->object_range == CIL_DEFAULT_SOURCE_LOW_HIGH)
750 			fprintf(out, " source low-high");
751 		else if (def->object_range == CIL_DEFAULT_TARGET_LOW)
752 			fprintf(out, " target low");
753 		else if (def->object_range == CIL_DEFAULT_TARGET_HIGH)
754 			fprintf(out, " target high");
755 		else if (def->object_range == CIL_DEFAULT_TARGET_LOW_HIGH)
756 			fprintf(out, " target low-high");
757 		else
758 			fprintf(out, " <?DEFAULT>");
759 		fprintf(out, ")\n");
760 		break;
761 	}
762 	case CIL_CLASS: {
763 		struct cil_class *class = node->data;
764 		fprintf(out, "(class %s ", datum_to_str(DATUM(class)));
765 		write_node_list(out, node->cl_head);
766 		fprintf(out, ")\n");
767 		break;
768 	}
769 	case CIL_CLASSORDER: {
770 		struct cil_classorder *classorder = node->data;
771 		fprintf(out, "(classorder ");
772 		write_string_list(out, classorder->class_list_str);
773 		fprintf(out, ")\n");
774 		break;
775 	}
776 	case CIL_COMMON: {
777 		struct cil_class *common = node->data;
778 		fprintf(out, "(common %s ", datum_to_str(DATUM(common)));
779 		write_node_list(out, node->cl_head);
780 		fprintf(out, ")\n");
781 		break;
782 	}
783 	case CIL_CLASSCOMMON: {
784 		struct cil_classcommon *cc = node->data;
785 		fprintf(out, "(classcommon %s %s)\n", cc->class_str, cc->common_str);
786 		break;
787 	}
788 	case CIL_CLASSPERMISSION: {
789 		struct cil_classpermission *cp = node->data;
790 		fprintf(out, "(classpermission %s)\n", datum_to_str(DATUM(cp)));
791 		break;
792 	}
793 	case CIL_CLASSPERMISSIONSET: {
794 		struct cil_classpermissionset *cps = node->data;
795 		fprintf(out, "(classpermissionset %s ", cps->set_str);
796 		write_classperms_list(out, cps->classperms);
797 		fprintf(out, ")\n");
798 		break;
799 	}
800 	case CIL_MAP_CLASS: {
801 		struct cil_class *map = node->data;
802 		fprintf(out, "(classmap %s ", datum_to_str(DATUM(map)));
803 		write_node_list(out, node->cl_head);
804 		fprintf(out, ")\n");
805 		break;
806 	}
807 	case CIL_CLASSMAPPING: {
808 		struct cil_classmapping *mapping = node->data;
809 		fprintf(out, "(classmapping %s %s ", mapping->map_class_str, mapping->map_perm_str);
810 		write_classperms_list(out, mapping->classperms);
811 		fprintf(out, ")\n");
812 		break;
813 	}
814 	case CIL_PERMISSIONX: {
815 		struct cil_permissionx *permx = node->data;
816 		fprintf(out, "(permissionx %s (", datum_to_str(DATUM(permx)));
817 		fprintf(out, "%s ", permx->kind == CIL_PERMX_KIND_IOCTL ? "ioctl" : "<?KIND>");
818 		fprintf(out, "%s ", datum_or_str(DATUM(permx->obj), permx->obj_str));
819 		write_expr(out, permx->expr_str);
820 		fprintf(out, "))\n");
821 		break;
822 	}
823 	case CIL_SID: {
824 		struct cil_sid *sid = node->data;
825 		fprintf(out, "(sid %s)\n", datum_to_str(DATUM(sid)));
826 		break;
827 	}
828 	case CIL_SIDCONTEXT: {
829 		struct cil_sidcontext *sidcon = node->data;
830 		fprintf(out, "(sidcontext %s ", sidcon->sid_str);
831 		if (sidcon->context)
832 			write_context(out, sidcon->context, CIL_TRUE);
833 		else
834 			fprintf(out, "%s", sidcon->context_str);
835 		fprintf(out, ")\n");
836 		break;
837 	}
838 	case CIL_SIDORDER: {
839 		struct cil_sidorder *sidorder = node->data;
840 		fprintf(out, "(sidorder ");
841 		write_string_list(out, sidorder->sid_list_str);
842 		fprintf(out, ")\n");
843 		break;
844 	}
845 	case CIL_BOOL: {
846 		struct cil_bool *boolean = node->data;
847 		fprintf(out, "(boolean %s %s)\n", datum_to_str(DATUM(boolean)), boolean->value ? "true" : "false");
848 		break;
849 	}
850 	case CIL_TUNABLE: {
851 		struct cil_tunable *tunable = node->data;
852 		fprintf(out, "(tunable %s %s)\n", datum_to_str(DATUM(tunable)), tunable->value ? "true" : "false");
853 		break;
854 	}
855 	case CIL_SENS: {
856 		struct cil_sens *sens = node->data;
857 		fprintf(out, "(sensitivity %s)\n", datum_to_str(DATUM(sens)));
858 		break;
859 	}
860 	case CIL_SENSALIAS: {
861 		struct cil_alias *alias = node->data;
862 		fprintf(out, "(sensitivityalias %s)\n", datum_to_str(DATUM(alias)));
863 		break;
864 	}
865 	case CIL_SENSALIASACTUAL: {
866 		struct cil_aliasactual *aliasactual = node->data;
867 		fprintf(out, "(sensitivityaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
868 		break;
869 	}
870 	case CIL_CAT: {
871 		struct cil_cat *cat = node->data;
872 		fprintf(out, "(category %s)\n", datum_to_str(DATUM(cat)));
873 		break;
874 	}
875 	case CIL_CATALIAS: {
876 		struct cil_alias *alias = node->data;
877 		fprintf(out, "(categoryalias %s)\n", datum_to_str(DATUM(alias)));
878 		break;
879 	}
880 	case CIL_CATALIASACTUAL: {
881 		struct cil_aliasactual *aliasactual = node->data;
882 		fprintf(out, "(categoryaliasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
883 		break;
884 	}
885 	case CIL_CATSET: {
886 		struct cil_catset *catset = node->data;
887 		fprintf(out, "(categoryset %s ", datum_to_str(DATUM(catset)));
888 		write_cats(out, catset->cats);
889 		fprintf(out, ")\n");
890 		break;
891 	}
892 	case CIL_CATORDER: {
893 		struct cil_catorder *catorder = node->data;
894 		fprintf(out, "(categoryorder ");
895 		write_string_list(out, catorder->cat_list_str);
896 		fprintf(out, ")\n");
897 		break;
898 	}
899 	case CIL_SENSCAT: {
900 		struct cil_senscat *senscat = node->data;
901 		fprintf(out, "(sensitivitycategory ");
902 		fprintf(out, "%s ", senscat->sens_str);
903 		write_cats(out, senscat->cats);
904 		fprintf(out, ")\n");
905 		break;
906 	}
907 	case CIL_SENSITIVITYORDER: {
908 		struct cil_sensorder *sensorder = node->data;
909 		fprintf(out, "(sensitivityorder ");
910 		write_string_list(out, sensorder->sens_list_str);
911 		fprintf(out, ")\n");
912 		break;
913 	}
914 	case CIL_LEVEL: {
915 		struct cil_level *level = node->data;
916 		fprintf(out, "(level %s ", datum_to_str(&level->datum));
917 		write_level(out, level, CIL_FALSE);
918 		fprintf(out, ")\n");
919 		break;
920 	}
921 	case CIL_LEVELRANGE: {
922 		struct cil_levelrange *lvlrange = node->data;
923 		fprintf(out, "(levelrange %s ", datum_to_str(DATUM(lvlrange)));
924 		write_range(out, lvlrange, CIL_FALSE);
925 		fprintf(out, ")\n");
926 		break;
927 	}
928 	case CIL_USER: {
929 		struct cil_user *user = node->data;
930 		fprintf(out, "(user %s)\n", datum_to_str(DATUM(user)));
931 		break;
932 	}
933 	case CIL_USERATTRIBUTE: {
934 		struct cil_userattribute *attr = node->data;
935 		fprintf(out, "(userattribute %s)\n", datum_to_str(DATUM(attr)));
936 		break;
937 	}
938 	case CIL_USERATTRIBUTESET: {
939 		struct cil_userattributeset *attr = node->data;
940 		fprintf(out, "(userattributeset %s ", attr->attr_str);
941 		if (attr->datum_expr)
942 			write_expr(out, attr->datum_expr);
943 		else
944 			write_expr(out, attr->str_expr);
945 		fprintf(out, ")\n");
946 		break;
947 	}
948 	case CIL_USERROLE: {
949 		struct cil_userrole *userrole = node->data;
950 		fprintf(out, "(userrole ");
951 		fprintf(out, "%s ", datum_or_str(userrole->user, userrole->user_str));
952 		fprintf(out, "%s", datum_or_str(userrole->role, userrole->role_str));
953 		fprintf(out, ")\n");
954 		break;
955 	}
956 	case CIL_USERLEVEL: {
957 		struct cil_userlevel *userlevel = node->data;
958 		fprintf(out, "(userlevel %s ", userlevel->user_str);
959 		if (userlevel->level)
960 			write_level(out, userlevel->level, CIL_TRUE);
961 		else
962 			fprintf(out, "%s", userlevel->level_str);
963 		fprintf(out, ")\n");
964 		break;
965 	}
966 	case CIL_USERRANGE: {
967 		struct cil_userrange *userrange = node->data;
968 		fprintf(out, "(userrange %s ", userrange->user_str);
969 		if (userrange->range)
970 			write_range(out, userrange->range, CIL_TRUE);
971 		else
972 			fprintf(out, "%s", userrange->range_str);
973 		fprintf(out, ")\n");
974 		break;
975 	}
976 	case CIL_USERBOUNDS: {
977 		struct cil_bounds *bounds = node->data;
978 		fprintf(out, "(userbounds %s %s)\n", bounds->parent_str, bounds->child_str);
979 		break;
980 	}
981 	case CIL_USERPREFIX: {
982 		struct cil_userprefix *prefix = node->data;
983 		fprintf(out, "(userprefix ");
984 		fprintf(out, "%s ", datum_or_str(DATUM(prefix->user), prefix->user_str));
985 		fprintf(out, "%s)\n", prefix->prefix_str);
986 		break;
987 	}
988 	case CIL_SELINUXUSER: {
989 		struct cil_selinuxuser *selinuxuser = node->data;
990 		fprintf(out, "(selinuxuser %s ", selinuxuser->name_str);
991 		fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str));
992 		if (selinuxuser->range)
993 			write_range(out, selinuxuser->range, CIL_TRUE);
994 		else
995 			fprintf(out, "%s", selinuxuser->range_str);
996 		fprintf(out, ")\n");
997 		break;
998 	}
999 	case CIL_SELINUXUSERDEFAULT: {
1000 		struct cil_selinuxuser *selinuxuser = node->data;
1001 		fprintf(out, "(selinuxuserdefault ");
1002 		fprintf(out, "%s ", datum_or_str(DATUM(selinuxuser->user), selinuxuser->user_str));
1003 		if (selinuxuser->range)
1004 			write_range(out, selinuxuser->range, CIL_TRUE);
1005 		else
1006 			fprintf(out, "%s", selinuxuser->range_str);
1007 		fprintf(out, ")\n");
1008 		break;
1009 	}
1010 	case CIL_ROLE: {
1011 		fprintf(out, "(role %s)\n", datum_to_str(node->data));
1012 		break;
1013 	}
1014 	case CIL_ROLEATTRIBUTE: {
1015 		fprintf(out, "(roleattribute %s)\n", datum_to_str(node->data));
1016 		break;
1017 	}
1018 	case CIL_ROLEATTRIBUTESET: {
1019 		struct cil_roleattributeset *attr = node->data;
1020 		fprintf(out, "(roleattributeset %s ", attr->attr_str);
1021 		if (attr->datum_expr)
1022 			write_expr(out, attr->datum_expr);
1023 		else
1024 			write_expr(out, attr->str_expr);
1025 		fprintf(out, ")\n");
1026 		break;
1027 	}
1028 	case CIL_ROLETYPE: {
1029 		struct cil_roletype *roletype = node->data;
1030 		fprintf(out, "(roletype ");
1031 		fprintf(out, "%s ", datum_or_str(DATUM(roletype->role), roletype->role_str));
1032 		fprintf(out, "%s", datum_or_str(DATUM(roletype->type), roletype->type_str));
1033 		fprintf(out, ")\n");
1034 		break;
1035 	}
1036 	case CIL_ROLEBOUNDS: {
1037 		struct cil_bounds *bnds = node->data;
1038 		fprintf(out, "(rolebounds %s %s)\n", bnds->parent_str, bnds->child_str);
1039 		break;
1040 	}
1041 	case CIL_TYPE: {
1042 		fprintf(out, "(type %s)\n", datum_to_str(node->data));
1043 		break;
1044 	}
1045 	case CIL_TYPEALIAS: {
1046 		fprintf(out, "(typealias %s)\n", datum_to_str(node->data));
1047 		break;
1048 	}
1049 	case CIL_TYPEALIASACTUAL: {
1050 		struct cil_aliasactual *aliasactual = node->data;
1051 		fprintf(out, "(typealiasactual %s %s)\n", aliasactual->alias_str, aliasactual->actual_str);
1052 		break;
1053 	}
1054 	case CIL_TYPEATTRIBUTE: {
1055 		fprintf(out, "(typeattribute %s)\n", datum_to_str(node->data));
1056 		break;
1057 	}
1058 	case CIL_TYPEATTRIBUTESET: {
1059 		struct cil_typeattributeset *attr = node->data;
1060 		fprintf(out, "(typeattributeset %s ", attr->attr_str);
1061 		if (attr->datum_expr)
1062 			write_expr(out, attr->datum_expr);
1063 		else
1064 			write_expr(out, attr->str_expr);
1065 		fprintf(out, ")\n");
1066 		break;
1067 	}
1068 	case CIL_EXPANDTYPEATTRIBUTE: {
1069 		struct cil_expandtypeattribute *attr = node->data;
1070 		fprintf(out, "(expandtypeattribute ");
1071 		if (attr->attr_datums)
1072 			write_expr(out, attr->attr_datums);
1073 		else
1074 			write_expr(out, attr->attr_strs);
1075 		fprintf(out, " %s)\n", attr->expand ? "true" : "false");
1076 		break;
1077 	}
1078 	case CIL_TYPEPERMISSIVE: {
1079 		struct cil_typepermissive *tp = node->data;
1080 		fprintf(out, "(typepermissive ");
1081 		fprintf(out, "%s", datum_or_str(DATUM(tp->type), tp->type_str));
1082 		fprintf(out, ")\n");
1083 		break;
1084 	}
1085 	case CIL_TYPEBOUNDS: {
1086 		struct cil_bounds *bounds = node->data;
1087 		fprintf(out, "(typebounds %s %s)\n", bounds->parent_str, bounds->child_str);
1088 		break;
1089 	}
1090 	case CIL_ROLEALLOW: {
1091 		struct cil_roleallow *roleallow = node->data;
1092 		fprintf(out, "(roleallow ");
1093 		fprintf(out, "%s ", datum_or_str(DATUM(roleallow->src), roleallow->src_str));
1094 		fprintf(out, "%s", datum_or_str(DATUM(roleallow->tgt), roleallow->tgt_str));
1095 		fprintf(out, ")\n");
1096 		break;
1097 	}
1098 	case CIL_ROLETRANSITION: {
1099 		struct cil_roletransition *roletrans = node->data;
1100 		fprintf(out, "(roletransition ");
1101 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->src), roletrans->src_str));
1102 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->tgt), roletrans->tgt_str));
1103 		fprintf(out, "%s ", datum_or_str(DATUM(roletrans->obj), roletrans->obj_str));
1104 		fprintf(out, "%s", datum_or_str(DATUM(roletrans->result), roletrans->result_str));
1105 		fprintf(out, ")\n");
1106 		break;
1107 	}
1108 	case CIL_AVRULE: {
1109 		struct cil_avrule *rule = node->data;
1110 		if (rule->rule_kind == AVRULE_ALLOWED)
1111 			fprintf(out, "(allow ");
1112 		else if (rule->rule_kind == AVRULE_AUDITALLOW)
1113 			fprintf(out, "(auditallow ");
1114 		else if (rule->rule_kind == AVRULE_DONTAUDIT)
1115 			fprintf(out, "(dontaudit ");
1116 		else if (rule->rule_kind == AVRULE_NEVERALLOW)
1117 			fprintf(out, "(neverallow ");
1118 		else
1119 			fprintf(out, "(<?AVRULE> ");
1120 
1121 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1122 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1123 		write_classperms_list(out, rule->perms.classperms);
1124 		fprintf(out, ")\n");
1125 		break;
1126 	}
1127 	case CIL_AVRULEX: {
1128 		struct cil_avrule *rule = node->data;
1129 		if (rule->rule_kind == AVRULE_ALLOWED)
1130 			fprintf(out, "(allowx ");
1131 		else if (rule->rule_kind == AVRULE_AUDITALLOW)
1132 			fprintf(out, "(auditallowx ");
1133 		else if (rule->rule_kind == AVRULE_DONTAUDIT)
1134 			fprintf(out, "(dontauditx ");
1135 		else if (rule->rule_kind == AVRULE_NEVERALLOW)
1136 			fprintf(out, "(neverallowx ");
1137 		else
1138 			fprintf(out, "(<?AVRULEX> ");
1139 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1140 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1141 		if (rule->perms.x.permx_str) {
1142 			fprintf(out, "%s",rule->perms.x.permx_str);
1143 		} else {
1144 			write_permx(out, rule->perms.x.permx);
1145 		}
1146 		fprintf(out, ")\n");
1147 		break;
1148 	}
1149 	case CIL_TYPE_RULE: {
1150 		struct cil_type_rule *rule = node->data;
1151 		if (rule->rule_kind == AVRULE_TRANSITION)
1152 			fprintf(out, "(typetransition ");
1153 		else if (rule->rule_kind == AVRULE_MEMBER)
1154 			fprintf(out, "(typemember ");
1155 		else if (rule->rule_kind == AVRULE_CHANGE)
1156 			fprintf(out, "(typechange ");
1157 		else
1158 			fprintf(out, "(<?TYPERULE> ");
1159 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1160 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1161 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1162 		fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
1163 		fprintf(out, ")\n");
1164 		break;
1165 	}
1166 	case CIL_NAMETYPETRANSITION: {
1167 		struct cil_nametypetransition *rule = node->data;
1168 		fprintf(out, "(typetransition ");
1169 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1170 		fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str));
1171 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1172 		fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str));
1173 		fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str));
1174 		fprintf(out, ")\n");
1175 		break;
1176 	}
1177 	case CIL_RANGETRANSITION: {
1178 		struct cil_rangetransition *rule = node->data;
1179 		fprintf(out, "(rangetransition ");
1180 		fprintf(out, "%s ", datum_or_str(DATUM(rule->src), rule->src_str));
1181 		fprintf(out, "%s ", datum_or_str(DATUM(rule->exec), rule->exec_str));
1182 		fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str));
1183 		if (rule->range)
1184 			write_range(out, rule->range, CIL_TRUE);
1185 		else
1186 			fprintf(out, "%s", rule->range_str);
1187 		fprintf(out, ")\n");
1188 		break;
1189 	}
1190 	case CIL_CONSTRAIN: {
1191 		struct cil_constrain *cons = node->data;
1192 		fprintf(out, "(constrain ");
1193 		write_constrain(out, cons);
1194 		fprintf(out, ")\n");
1195 		break;
1196 	}
1197 	case CIL_MLSCONSTRAIN: {
1198 		struct cil_constrain *cons = node->data;
1199 		fprintf(out, "(mlsconstrain ");
1200 		write_constrain(out, cons);
1201 		fprintf(out, ")\n");
1202 		break;
1203 	}
1204 	case CIL_VALIDATETRANS: {
1205 		struct cil_validatetrans *vt = node->data;
1206 		fprintf(out, "(validatetrans ");
1207 		fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str));
1208 		if (vt->datum_expr)
1209 			write_expr(out, vt->datum_expr);
1210 		else
1211 			write_expr(out, vt->str_expr);
1212 		fprintf(out, ")\n");
1213 		break;
1214 	}
1215 	case CIL_MLSVALIDATETRANS: {
1216 		struct cil_validatetrans *vt = node->data;
1217 		fprintf(out, "(mlsvalidatetrans ");
1218 		fprintf(out, "%s ", datum_or_str(DATUM(vt->class), vt->class_str));
1219 		if (vt->datum_expr)
1220 			write_expr(out, vt->datum_expr);
1221 		else
1222 			write_expr(out, vt->str_expr);
1223 		fprintf(out, ")\n");
1224 		break;
1225 	}
1226 	case CIL_CONTEXT: {
1227 		struct cil_context *context = node->data;
1228 		fprintf(out, "(context %s ", datum_to_str(DATUM(context)));
1229 		write_context(out, context, CIL_FALSE);
1230 		fprintf(out, ")\n");
1231 		break;
1232 	}
1233 	case CIL_FILECON: {
1234 		struct cil_filecon *filecon = node->data;
1235 		fprintf(out, "(filecon ");
1236 		fprintf(out, "\"%s\" ", filecon->path_str);
1237 		switch (filecon->type) {
1238 		case CIL_FILECON_ANY:
1239 			fprintf(out, "%s ", CIL_KEY_ANY);
1240 			break;
1241 		case CIL_FILECON_FILE:
1242 			fprintf(out, "%s ", CIL_KEY_FILE);
1243 			break;
1244 		case CIL_FILECON_DIR:
1245 			fprintf(out, "%s ", CIL_KEY_DIR);
1246 			break;
1247 		case CIL_FILECON_CHAR:
1248 			fprintf(out, "%s ", CIL_KEY_CHAR);
1249 			break;
1250 		case CIL_FILECON_BLOCK:
1251 			fprintf(out, "%s ", CIL_KEY_BLOCK);
1252 			break;
1253 		case CIL_FILECON_SOCKET:
1254 			fprintf(out, "%s ", CIL_KEY_SOCKET);
1255 			break;
1256 		case CIL_FILECON_PIPE:
1257 			fprintf(out, "%s ", CIL_KEY_PIPE);
1258 			break;
1259 		case CIL_FILECON_SYMLINK:
1260 			fprintf(out, "%s ", CIL_KEY_SYMLINK);
1261 			break;
1262 		default:
1263 			fprintf(out, "<?FILETYPE> ");
1264 		}
1265 		if (filecon->context)
1266 			write_context(out, filecon->context, CIL_TRUE);
1267 		else if (filecon->context_str)
1268 			fprintf(out, "%s", filecon->context_str);
1269 		else
1270 			fprintf(out, "()");
1271 		fprintf(out, ")\n");
1272 		break;
1273 	}
1274 	case CIL_IBPKEYCON: {
1275 		struct cil_ibpkeycon *ibpkeycon = node->data;
1276 		fprintf(out, "(ibpkeycon %s ", ibpkeycon->subnet_prefix_str);
1277 		fprintf(out, "(%d %d) ", ibpkeycon->pkey_low, ibpkeycon->pkey_high);
1278 		if (ibpkeycon->context)
1279 			write_context(out, ibpkeycon->context, CIL_TRUE);
1280 		else if (ibpkeycon->context_str)
1281 			fprintf(out, "%s", ibpkeycon->context_str);
1282 		fprintf(out, ")\n");
1283 		break;
1284 	}
1285 	case CIL_PORTCON: {
1286 		struct cil_portcon *portcon = node->data;
1287 		fprintf(out, "(portcon ");
1288 		if (portcon->proto == CIL_PROTOCOL_UDP)
1289 			fprintf(out, " udp ");
1290 		else if (portcon->proto == CIL_PROTOCOL_TCP)
1291 			fprintf(out, " tcp ");
1292 		else if (portcon->proto == CIL_PROTOCOL_DCCP)
1293 			fprintf(out, "dccp ");
1294 		else if (portcon->proto == CIL_PROTOCOL_SCTP)
1295 			fprintf(out, "sctp ");
1296 		else
1297 			fprintf(out, "<?PROTOCOL> ");
1298 		if (portcon->port_low == portcon->port_high)
1299 			fprintf(out, "%d ", portcon->port_low);
1300 		else
1301 			fprintf(out, "(%d %d) ", portcon->port_low, portcon->port_high);
1302 		if (portcon->context)
1303 			write_context(out, portcon->context, CIL_TRUE);
1304 		else
1305 			fprintf(out, "%s", portcon->context_str);
1306 		fprintf(out, ")\n");
1307 		break;
1308 	}
1309 	case CIL_NODECON: {
1310 		struct cil_nodecon *nodecon = node->data;
1311 		fprintf(out, "(nodecon ");
1312 		if (nodecon->addr)
1313 			write_ipaddr(out, nodecon->addr);
1314 		else
1315 			fprintf(out, "%s ", nodecon->addr_str);
1316 		fprintf(out, " ");
1317 		if (nodecon->mask)
1318 			write_ipaddr(out, nodecon->mask);
1319 		else
1320 			fprintf(out, "%s ", nodecon->mask_str);
1321 		fprintf(out, " ");
1322 		if (nodecon->context)
1323 			write_context(out, nodecon->context, CIL_TRUE);
1324 		else
1325 			fprintf(out, "%s", nodecon->context_str);
1326 		fprintf(out, ")\n");
1327 		break;
1328 	}
1329 	case CIL_GENFSCON: {
1330 		struct cil_genfscon *genfscon = node->data;
1331 		fprintf(out, "(genfscon ");
1332 		fprintf(out, "%s \"%s\" ", genfscon->fs_str, genfscon->path_str);
1333 		if (genfscon->file_type != CIL_FILECON_ANY) {
1334 			switch (genfscon->file_type) {
1335 			case CIL_FILECON_FILE:
1336 				fprintf(out, "%s ", CIL_KEY_FILE);
1337 				break;
1338 			case CIL_FILECON_DIR:
1339 				fprintf(out, "%s ", CIL_KEY_DIR);
1340 				break;
1341 			case CIL_FILECON_CHAR:
1342 				fprintf(out, "%s ", CIL_KEY_CHAR);
1343 				break;
1344 			case CIL_FILECON_BLOCK:
1345 				fprintf(out, "%s ", CIL_KEY_BLOCK);
1346 				break;
1347 			case CIL_FILECON_SOCKET:
1348 				fprintf(out, "%s ", CIL_KEY_SOCKET);
1349 				break;
1350 			case CIL_FILECON_PIPE:
1351 				fprintf(out, "%s ", CIL_KEY_PIPE);
1352 				break;
1353 			case CIL_FILECON_SYMLINK:
1354 				fprintf(out, "%s ", CIL_KEY_SYMLINK);
1355 				break;
1356 			default:
1357 				fprintf(out, "<?FILETYPE> ");
1358 			}
1359 		}
1360 		if (genfscon->context)
1361 			write_context(out, genfscon->context, CIL_TRUE);
1362 		else
1363 			fprintf(out, "%s", genfscon->context_str);
1364 		fprintf(out, ")\n");
1365 		break;
1366 	}
1367 	case CIL_NETIFCON: {
1368 		struct cil_netifcon *netifcon = node->data;
1369 		fprintf(out, "(netifcon %s ", netifcon->interface_str);
1370 		if (netifcon->if_context)
1371 			write_context(out, netifcon->if_context, CIL_TRUE);
1372 		else
1373 			fprintf(out, "%s", netifcon->if_context_str);
1374 		fprintf(out, " ");
1375 		if (netifcon->packet_context)
1376 			write_context(out, netifcon->packet_context, CIL_TRUE);
1377 		else
1378 			fprintf(out, "%s", netifcon->packet_context_str);
1379 		fprintf(out, ")\n");
1380 		break;
1381 	}
1382 	case CIL_IBENDPORTCON: {
1383 		struct cil_ibendportcon *ibendportcon = node->data;
1384 		fprintf(out, "(ibendportcon %s %u ", ibendportcon->dev_name_str, ibendportcon->port);
1385 		if (ibendportcon->context)
1386 			write_context(out, ibendportcon->context, CIL_TRUE);
1387 		else
1388 			fprintf(out, "%s", ibendportcon->context_str);
1389 		fprintf(out, ")\n");
1390 		break;
1391 	}
1392 	case CIL_PIRQCON: {
1393 		struct cil_pirqcon *pirqcon = node->data;
1394 		fprintf(out, "(pirqcon %d ", pirqcon->pirq);
1395 		if (pirqcon->context)
1396 			write_context(out, pirqcon->context, CIL_TRUE);
1397 		else
1398 			fprintf(out, "%s", pirqcon->context_str);
1399 		fprintf(out, ")\n");
1400 		break;
1401 	}
1402 	case CIL_IOMEMCON: {
1403 		struct cil_iomemcon *iomemcon = node->data;
1404 		fprintf(out, "(iomemcon (%"PRId64" %"PRId64") ", iomemcon->iomem_low, iomemcon->iomem_high);
1405 		if (iomemcon->context)
1406 			write_context(out, iomemcon->context, CIL_TRUE);
1407 		else
1408 			fprintf(out, "%s", iomemcon->context_str);
1409 		fprintf(out, ")\n");
1410 		break;
1411 	}
1412 	case CIL_IOPORTCON: {
1413 		struct cil_ioportcon *ioportcon = node->data;
1414 		fprintf(out, "(ioportcon ");
1415 		if (ioportcon->ioport_low == ioportcon->ioport_high)
1416 			fprintf(out, "%d ", ioportcon->ioport_low);
1417 		else
1418 			fprintf(out, "(%d %d) ", ioportcon->ioport_low, ioportcon->ioport_high);
1419 
1420 		if (ioportcon->context)
1421 			write_context(out, ioportcon->context, CIL_TRUE);
1422 		else
1423 			fprintf(out, "%s", ioportcon->context_str);
1424 		fprintf(out, ")\n");
1425 		break;
1426 	}
1427 	case CIL_PCIDEVICECON: {
1428 		struct cil_pcidevicecon *pcidevicecon = node->data;
1429 		fprintf(out, "(pcidevicecon %d ", pcidevicecon->dev);
1430 		if (pcidevicecon->context)
1431 			write_context(out, pcidevicecon->context, CIL_TRUE);
1432 		else
1433 			fprintf(out, "%s", pcidevicecon->context_str);
1434 		fprintf(out, ")\n");
1435 		break;
1436 	}
1437 	case CIL_DEVICETREECON: {
1438 		struct cil_devicetreecon *devicetreecon = node->data;
1439 		fprintf(out, "(devicetreecon \"%s\" ", devicetreecon->path);
1440 		if (devicetreecon->context)
1441 			write_context(out, devicetreecon->context, CIL_TRUE);
1442 		else
1443 			fprintf(out, "%s", devicetreecon->context_str);
1444 		fprintf(out, ")\n");
1445 		break;
1446 	}
1447 	case CIL_FSUSE: {
1448 		struct cil_fsuse *fsuse = node->data;
1449 		fprintf(out, "(fsuse ");
1450 		if (fsuse->type == CIL_FSUSE_XATTR)
1451 			fprintf(out, "xattr ");
1452 		else if (fsuse->type == CIL_FSUSE_TASK)
1453 			fprintf(out, "task ");
1454 		else if (fsuse->type == CIL_FSUSE_TRANS)
1455 			fprintf(out, "trans ");
1456 		else
1457 			fprintf(out, "<?TYPE> ");
1458 		fprintf(out, "%s ", fsuse->fs_str);
1459 		if (fsuse->context)
1460 			write_context(out, fsuse->context, CIL_TRUE);
1461 		else
1462 			fprintf(out, "%s", fsuse->context_str);
1463 		fprintf(out, ")\n");
1464 		break;
1465 	}
1466 	case CIL_POLICYCAP: {
1467 		struct cil_policycap *polcap = node->data;
1468 		fprintf(out, "(policycap %s)\n", polcap->datum.name);
1469 		break;
1470 	}
1471 	case CIL_IPADDR: {
1472 		struct cil_ipaddr *ipaddr = node->data;
1473 		char buf[256];
1474 		if (inet_ntop(ipaddr->family, &ipaddr->ip, buf, 256) == NULL)
1475 			strcpy(buf, "<?IPADDR>");
1476 		fprintf(out, "(ipaddr %s %s)\n", datum_to_str(&ipaddr->datum), buf);
1477 		break;
1478 	}
1479 	default :
1480 		fprintf(out, "(<?RULE:%s>)\n", cil_node_to_string(node));
1481 		break;
1482 	}
1483 }
1484 
1485 /*
1486  * Tree walk data and helper functions for writing the AST of the various phases
1487  */
1488 
1489 struct cil_write_ast_args {
1490 	FILE *out;
1491 	int depth;
1492 };
1493 
1494 /*
1495  * Helper functions for writing the parse AST
1496  */
1497 
__write_parse_ast_node_helper(struct cil_tree_node * node,uint32_t * finished,void * extra_args)1498 static int __write_parse_ast_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
1499 {
1500 	struct cil_write_ast_args *args = extra_args;
1501 
1502 	fprintf(args->out, "%*s", args->depth*4, "");
1503 	if (!node->data) {
1504 		if (node->cl_head)
1505 			fprintf(args->out, "(\n");
1506 		else
1507 			fprintf(args->out, "()\n");
1508 	} else {
1509 		char *str = (char *)node->data;
1510 		size_t len = strlen(str);
1511 		size_t i;
1512 
1513 		for (i = 0; i < len; i++) {
1514 			if (isspace(str[i])) {
1515 				fprintf(args->out, "\"%s\"\n", str);
1516 				return SEPOL_OK;
1517 			}
1518 		}
1519 
1520 		fprintf(args->out, "%s\n", (char *)node->data);
1521 	}
1522 
1523 	return SEPOL_OK;
1524 }
1525 
__write_parse_ast_first_child_helper(struct cil_tree_node * node,void * extra_args)1526 static int __write_parse_ast_first_child_helper(struct cil_tree_node *node, void *extra_args)
1527 {
1528 	struct cil_write_ast_args *args = extra_args;
1529 	struct cil_tree_node *parent = node->parent;
1530 
1531 	if (parent->flavor != CIL_ROOT) {
1532 		args->depth++;
1533 	}
1534 
1535 	return SEPOL_OK;
1536 }
1537 
__write_parse_ast_last_child_helper(struct cil_tree_node * node,void * extra_args)1538 static int __write_parse_ast_last_child_helper(struct cil_tree_node *node, void *extra_args)
1539 {
1540 	struct cil_write_ast_args *args = extra_args;
1541 	struct cil_tree_node *parent = node->parent;
1542 
1543 	if (parent->flavor == CIL_ROOT) {
1544 		return SEPOL_OK;
1545 	}
1546 
1547 	args->depth--;
1548 	fprintf(args->out, "%*s", args->depth*4, "");
1549 	fprintf(args->out, ")\n");
1550 
1551 	return SEPOL_OK;
1552 }
1553 
1554 /*
1555  * Helper functions for writing the CIL AST for the build and resolve phases
1556  */
1557 
__write_cil_ast_node_helper(struct cil_tree_node * node,uint32_t * finished,void * extra_args)1558 static int __write_cil_ast_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
1559 {
1560 	struct cil_write_ast_args *args = extra_args;
1561 
1562 	if (node->flavor == CIL_SRC_INFO) {
1563 		// ANDROID: The generated cil may be split/merged later on. Do not output
1564 		// source information to avoid issues when loading the resulting policy with
1565 		// libsepol.
1566 		// cil_write_src_info_node(args->out, node);
1567 		return SEPOL_OK;
1568 	}
1569 
1570 	fprintf(args->out, "%*s", args->depth*4, "");
1571 
1572 	cil_write_ast_node(args->out, node);
1573 
1574 	if (node->flavor == CIL_CLASS || node->flavor == CIL_COMMON || node->flavor == CIL_MAP_CLASS) {
1575 		*finished = CIL_TREE_SKIP_HEAD;
1576 	}
1577 
1578 	return SEPOL_OK;
1579 }
1580 
__write_cil_ast_first_child_helper(struct cil_tree_node * node,void * extra_args)1581 static int __write_cil_ast_first_child_helper(struct cil_tree_node *node, void *extra_args)
1582 {
1583 	struct cil_write_ast_args *args = extra_args;
1584 	struct cil_tree_node *parent = node->parent;
1585 
1586 	if (parent->flavor != CIL_SRC_INFO && parent->flavor != CIL_ROOT) {
1587 		args->depth++;
1588 	}
1589 
1590 	return SEPOL_OK;
1591 }
1592 
__write_cil_ast_last_child_helper(struct cil_tree_node * node,void * extra_args)1593 static int __write_cil_ast_last_child_helper(struct cil_tree_node *node, void *extra_args)
1594 {
1595 	struct cil_write_ast_args *args = extra_args;
1596 	struct cil_tree_node *parent = node->parent;
1597 
1598 	if (parent->flavor == CIL_ROOT) {
1599 		return SEPOL_OK;
1600 	} else if (parent->flavor == CIL_SRC_INFO) {
1601 		// ANDROID: The generated cil may be split/merged later on. Do not output
1602 		// source information to avoid issues when loading the resulting policy with
1603 		// libsepol.
1604 		// fprintf(args->out, ";;* lme\n");
1605 		return SEPOL_OK;
1606 	}
1607 
1608 	args->depth--;
1609 	fprintf(args->out, "%*s", args->depth*4, "");
1610 	fprintf(args->out, ")\n");
1611 
1612 	return SEPOL_OK;
1613 }
1614 
cil_write_ast(FILE * out,enum cil_write_ast_phase phase,struct cil_tree_node * node)1615 int cil_write_ast(FILE *out, enum cil_write_ast_phase phase, struct cil_tree_node *node)
1616 {
1617 	struct cil_write_ast_args extra_args;
1618 	int rc;
1619 
1620 	extra_args.out = out;
1621 	extra_args.depth = 0;
1622 
1623 	if (phase == CIL_WRITE_AST_PHASE_PARSE) {
1624 		rc = cil_tree_walk(node, __write_parse_ast_node_helper, __write_parse_ast_first_child_helper, __write_parse_ast_last_child_helper, &extra_args);
1625 	} else {
1626 		rc = cil_tree_walk(node, __write_cil_ast_node_helper, __write_cil_ast_first_child_helper, __write_cil_ast_last_child_helper, &extra_args);
1627 	}
1628 
1629 	if (rc != SEPOL_OK) {
1630 		cil_log(CIL_ERR, "Failed to write AST\n");
1631 		return SEPOL_ERR;
1632 	}
1633 
1634 	return SEPOL_OK;
1635 }
1636