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