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