• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 
3 #include "cil_flavor.h"
4 #include "cil_internal.h"
5 #include "cil_log.h"
6 #include "cil_tree.h"
7 
8 struct cil_args_write {
9 	FILE *cil_out;
10 	struct cil_db *db;
11 };
12 
13 static int cil_unfill_expr(struct cil_list *expr_str, char **out_str, int paren);
14 static int cil_unfill_classperms_list(struct cil_list *classperms, char **out_str, int paren);
15 static int __cil_write_first_child_helper(struct cil_tree_node *node, void *extra_args);
16 static int __cil_write_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args);
17 static int __cil_write_last_child_helper(struct cil_tree_node *node, void *extra_args);
18 
__cil_strlist_concat(struct cil_list * str_list,char ** out_str,int paren)19 static int __cil_strlist_concat(struct cil_list *str_list, char **out_str, int paren) {
20 	size_t len = paren ? 3 : 1;
21 	size_t num_elems = 0;
22 	char *p = NULL;
23 	struct cil_list_item *curr;
24 
25 	/* get buffer size */
26 	cil_list_for_each(curr, str_list) {
27 		len += strlen((char *)curr->data);
28 		num_elems++;
29 	}
30 	if (num_elems != 0) {
31 		/* add spaces between elements */
32 		len += num_elems - 1;
33 	}
34 	*out_str = cil_malloc(len);
35 	p = *out_str;
36 	if (paren)
37 		*p++ = '(';
38 	cil_list_for_each(curr, str_list) {
39 		size_t src_len = strlen((char *)curr->data);
40 		memcpy(p, curr->data, src_len);
41 		p += src_len;
42 		if (curr->next != NULL)
43 			*p++ = ' ';
44 	}
45 	if (paren)
46 		*p++ = ')';
47 	*p++ = '\0';
48 	return SEPOL_OK;
49 }
50 
__cil_unfill_expr_helper(struct cil_list_item * curr,struct cil_list_item ** next,char ** out_str,int paren)51 static int __cil_unfill_expr_helper(struct cil_list_item *curr,
52 			     struct cil_list_item **next, char **out_str, int paren) {
53 	int rc = SEPOL_ERR;
54 	char *str = NULL;
55 	char *operand1 = NULL;
56 	char *operand2 = NULL;
57 
58 	switch(curr->flavor) {
59 	case CIL_LIST:
60 		rc = cil_unfill_expr((struct cil_list *)curr->data, &str, paren);
61 		if (rc != SEPOL_OK)
62 			goto exit;
63 		*out_str = str;
64 		*next = curr->next;
65 		break;
66 	case CIL_STRING:
67 		str = strdup((char *)curr->data);
68 		if (!str) {
69 			cil_log(CIL_ERR, "OOM. Unable to copy string.\n");
70             rc = SEPOL_ERR;
71 			goto exit;
72 		}
73 		*out_str = str;
74 		*next = curr->next;
75 		break;
76 	case CIL_DATUM:
77 		str = strdup(((struct cil_symtab_datum *)curr->data)->name);
78 		if (!str) {
79 			cil_log(CIL_ERR, "OOM. Unable to copy string.\n");
80             rc = SEPOL_ERR;
81 			goto exit;
82 		}
83 		*out_str = str;
84 		*next = curr->next;
85 		break;
86 	case CIL_OP: {
87 		char *op_str = NULL;
88 		size_t len = 0;
89 		enum cil_flavor op_flavor = (enum cil_flavor)curr->data;
90 		switch (op_flavor) {
91 		case CIL_AND:
92 			op_str = CIL_KEY_AND;
93 			break;
94 		case CIL_OR:
95 			op_str = CIL_KEY_OR;
96 			break;
97 		case CIL_NOT:
98 			op_str = CIL_KEY_NOT;
99 			break;
100 		case CIL_ALL:
101 			op_str = CIL_KEY_ALL;
102 			break;
103 		case CIL_EQ:
104 			op_str = CIL_KEY_EQ;
105 			break;
106 		case CIL_NEQ:
107 			op_str = CIL_KEY_NEQ;
108 			break;
109 		case CIL_RANGE:
110 			op_str = CIL_KEY_RANGE;
111 			break;
112 		case CIL_XOR:
113 			op_str = CIL_KEY_XOR;
114 			break;
115 		case CIL_CONS_DOM:
116 			op_str = CIL_KEY_CONS_DOM;
117 			break;
118 		case CIL_CONS_DOMBY:
119 			op_str = CIL_KEY_CONS_DOMBY;
120 			break;
121 		case CIL_CONS_INCOMP:
122 			op_str = CIL_KEY_CONS_INCOMP;
123 			break;
124 		default:
125 			cil_log(CIL_ERR, "Unknown operator in expression: %d\n", op_flavor);
126 			goto exit;
127 			break;
128 		}
129 		/* all operands take two args except for 'all' and 'not', which take
130 		 * one and two, respectively */
131 		len = strlen(op_str) + 3;
132 		if (op_flavor == CIL_ALL) {
133 			*out_str = cil_malloc(len);
134 			sprintf(*out_str, "(%s)", op_str);
135 			*next = curr->next;
136 		} else if (op_flavor == CIL_NOT) {
137 			rc = __cil_unfill_expr_helper(curr->next, next, &operand1, paren);
138 			if (rc != SEPOL_OK)
139 				goto exit;
140 			len += strlen(operand1) + 1;
141 			*out_str = cil_malloc(len);
142 			sprintf(*out_str, "(%s %s)", op_str, operand1);
143 			// *next already set by recursive call
144 		} else {
145 			rc = __cil_unfill_expr_helper(curr->next, next, &operand1, paren);
146 			if (rc != SEPOL_OK)
147 				goto exit;
148 			len += strlen(operand1) + 1;
149 			// *next contains operand2, but keep track of next after that
150 			rc = __cil_unfill_expr_helper(*next, next, &operand2, paren);
151 			if (rc != SEPOL_OK)
152 				goto exit;
153 			len += strlen(operand2) + 1;
154 			*out_str = cil_malloc(len);
155 			sprintf(*out_str, "(%s %s %s)", op_str, operand1, operand2);
156 			// *next already set by recursive call
157 		}
158 	}
159 		break;
160 	case CIL_CONS_OPERAND: {
161 		enum cil_flavor operand_flavor = (enum cil_flavor)curr->data;
162 		char *operand_str = NULL;
163 		switch (operand_flavor) {
164 		case CIL_CONS_U1:
165 			operand_str = CIL_KEY_CONS_U1;
166 			break;
167 		case CIL_CONS_U2:
168 			operand_str = CIL_KEY_CONS_U2;
169 			break;
170 		case CIL_CONS_U3:
171 			operand_str = CIL_KEY_CONS_U3;
172 			break;
173 		case CIL_CONS_T1:
174 			operand_str = CIL_KEY_CONS_T1;
175 			break;
176 		case CIL_CONS_T2:
177 			operand_str = CIL_KEY_CONS_T2;
178 			break;
179 		case CIL_CONS_T3:
180 			operand_str = CIL_KEY_CONS_T3;
181 			break;
182 		case CIL_CONS_R1:
183 			operand_str = CIL_KEY_CONS_R1;
184 			break;
185 		case CIL_CONS_R2:
186 			operand_str = CIL_KEY_CONS_R2;
187 			break;
188 		case CIL_CONS_R3:
189 			operand_str = CIL_KEY_CONS_R3;
190 			break;
191 		case CIL_CONS_L1:
192 			operand_str = CIL_KEY_CONS_L1;
193 			break;
194 		case CIL_CONS_L2:
195 			operand_str = CIL_KEY_CONS_L2;
196 			break;
197 		case CIL_CONS_H1:
198 			operand_str = CIL_KEY_CONS_H1;
199 			break;
200 		case CIL_CONS_H2:
201 			operand_str = CIL_KEY_CONS_H2;
202 			break;
203 		default:
204 			cil_log(CIL_ERR, "Unknown operand in expression\n");
205 			goto exit;
206 			break;
207 		}
208 		str = strdup(operand_str);
209 		if (!str) {
210 			cil_log(CIL_ERR, "OOM. Unable to copy string.\n");
211             rc = SEPOL_ERR;
212 			goto exit;
213 		}
214 		*out_str = str;
215 		*next = curr->next;
216 	}
217 		break;
218 	default:
219 		cil_log(CIL_ERR, "Unknown flavor in expression\n");
220 		goto exit;
221 		break;
222 	}
223 	rc = SEPOL_OK;
224 exit:
225 	free(operand1);
226 	free(operand2);
227 	return rc;
228 }
229 
cil_unfill_expr(struct cil_list * expr_str,char ** out_str,int paren)230 static int cil_unfill_expr(struct cil_list *expr_str, char **out_str, int paren) {
231 	int rc = SEPOL_ERR;
232 
233 	/* reuse cil_list to keep track of strings */
234 	struct cil_list *str_list = NULL;
235 	struct cil_list_item *curr = NULL;
236 
237 	cil_list_init(&str_list, CIL_NONE);
238 
239 	/* iterate through cil_list, grabbing elements as needed */
240 	curr = expr_str->head;
241 	while(curr != NULL) {
242 		char *str = NULL;
243 		struct cil_list_item *next = NULL;
244 
245 		rc = __cil_unfill_expr_helper(curr, &next, &str, paren);
246         if (rc != SEPOL_OK)
247             goto exit;
248 		cil_list_append(str_list, CIL_STRING, (void *) str);
249 		str = NULL;
250 		curr = next;
251 	}
252 	rc = __cil_strlist_concat(str_list, out_str, paren);
253 	if (rc != SEPOL_OK)
254 		goto exit;
255 	rc = SEPOL_OK;
256 exit:
257 	cil_list_for_each(curr, str_list) {
258 		free(curr->data);
259 	}
260 	cil_list_destroy(&str_list, 0);
261 	return rc;
262 }
263 
cil_unfill_cats(struct cil_cats * cats,char ** out_str)264 static int cil_unfill_cats(struct cil_cats *cats, char **out_str) {
265 	return cil_unfill_expr(cats->str_expr, out_str, 0);
266 }
267 
cil_unfill_level(struct cil_level * lvl,char ** out_str)268 static int cil_unfill_level(struct cil_level *lvl, char **out_str) {
269 	int rc = SEPOL_ERR;
270 	size_t len = 0;
271 	char *sens, *cats = NULL;
272 	sens = lvl->sens_str;
273 	len = strlen(sens) + 3; // '()\0'
274 	if (lvl->cats != NULL) {
275 		rc = cil_unfill_cats(lvl->cats, &cats);
276 		if (rc != SEPOL_OK)
277 			goto exit;
278 		len += strlen(cats) + 1;
279 	}
280 	*out_str = cil_malloc(len);
281 	if (cats == NULL) {
282 		if (sprintf(*out_str, "(%s)", sens) < 0) {
283 			cil_log(CIL_ERR, "Error unpacking and writing level\n");
284 			rc = SEPOL_ERR;
285 			goto exit;
286 		}
287 	} else {
288 		if (sprintf(*out_str, "(%s %s)", sens, cats) < 0) {
289 			cil_log(CIL_ERR, "Error unpacking and writing level\n");
290 			rc = SEPOL_ERR;
291 			goto exit;
292 		}
293 	}
294 	rc = SEPOL_OK;
295 exit:
296 	free(cats);
297 	return rc;
298 }
299 
cil_unfill_levelrange(struct cil_levelrange * lvlrnge,char ** out_str)300 static int cil_unfill_levelrange(struct cil_levelrange *lvlrnge, char **out_str) {
301 	int rc = SEPOL_ERR;
302 	size_t len = 0;
303 	char *low = NULL, *high = NULL;
304 	if (lvlrnge->low_str != NULL) {
305 		low = strdup(lvlrnge->low_str);
306 		if (low == NULL) {
307 			cil_log(CIL_ERR, "OOM. Unable to copy level string.\n");
308             rc = SEPOL_ERR;
309 			goto exit;
310 		}
311 	} else {
312 		rc = cil_unfill_level(lvlrnge->low, &low);
313 		if (rc != SEPOL_OK)
314 			goto exit;
315 	}
316 	if (lvlrnge->high_str != NULL) {
317 		high = strdup(lvlrnge->high_str);
318 		if (high == NULL) {
319 			cil_log(CIL_ERR, "OOM. Unable to copy level string.\n");
320             rc = SEPOL_ERR;
321 			goto exit;
322 		}
323 	} else {
324 		rc = cil_unfill_level(lvlrnge->high, &high);
325 		if (rc != SEPOL_OK)
326 			goto exit;
327 	}
328 	len = strlen(low) + strlen(high) + 4;
329 	*out_str = cil_malloc(len);
330 	if (sprintf(*out_str, "(%s %s)", low, high) < 0) {
331 		cil_log(CIL_ERR, "Error unpacking and writing levelrange\n");
332 		rc = SEPOL_ERR;
333 		goto exit;
334 	}
335 	rc = SEPOL_OK;
336 exit:
337 	free(low);
338 	free(high);
339 	return rc;
340 }
341 
cil_unfill_context(struct cil_context * context,char ** out_str)342 static int cil_unfill_context(struct cil_context *context, char **out_str) {
343 	int rc = SEPOL_ERR;
344 	size_t len = 0;
345 	char *user_str, *role_str, *type_str;
346 	char *range_str = NULL;
347 
348 	user_str = context->user_str;
349 	role_str = context->role_str;
350 	type_str = context->type_str;
351 	if (context->range_str != NULL) {
352 		range_str = strdup(context->range_str);
353 		if (range_str == NULL) {
354 			cil_log(CIL_ERR, "OOM. Unable to copy range string.\n");
355             rc = SEPOL_ERR;
356 			goto exit;
357 		}
358 	} else {
359 		rc = cil_unfill_levelrange(context->range, &range_str);
360 		if (rc != SEPOL_OK)
361 			goto exit;
362 	}
363 	len = strlen(user_str) + strlen(role_str) + strlen(type_str)
364 		+ strlen(range_str) + 6;
365 	*out_str = cil_malloc(len);
366 	if (sprintf(*out_str, "(%s %s %s %s)", user_str, role_str, type_str, range_str) < 0) {
367 		cil_log(CIL_ERR, "Error unpacking and writing context\n");
368 		rc = SEPOL_ERR;
369 		goto exit;
370 	}
371 	rc = SEPOL_OK;
372 exit:
373 	free(range_str);
374 	return rc;
375 }
376 
cil_unfill_permx(struct cil_permissionx * permx,char ** out_str)377 static int cil_unfill_permx(struct cil_permissionx *permx, char **out_str) {
378 	size_t len = 3;
379 	int rc = SEPOL_ERR;
380 	char *kind, *obj;
381 	char *expr = NULL;
382 
383 	switch (permx->kind) {
384 	case CIL_PERMX_KIND_IOCTL:
385 		kind = CIL_KEY_IOCTL;
386 		break;
387 	default:
388 		cil_log(CIL_ERR, "Unknown permissionx kind: %d\n", permx->kind);
389 		rc = SEPOL_ERR;
390 		goto exit;
391 		break;
392 	}
393 	obj = permx->obj_str;
394 	rc = cil_unfill_expr(permx->expr_str, &expr, 1);
395 	if (rc != SEPOL_OK)
396 		goto exit;
397 	len += strlen(kind) + strlen(obj) + strlen(expr) + 2;
398 	*out_str = cil_malloc(len);
399 	if (sprintf(*out_str, "(%s %s %s)", kind, obj, expr) < 0) {
400 		cil_log(CIL_ERR, "Error writing xperm\n");
401 		rc = SEPOL_ERR;
402 		goto exit;
403 	}
404 	rc = SEPOL_OK;
405 exit:
406 	free(expr);
407 	return rc;
408 }
409 
410 #define cil_write_unsupported(flavor) _cil_write_unsupported(flavor, __LINE__)
_cil_write_unsupported(const char * flavor,int line)411 static int _cil_write_unsupported(const char *flavor, int line) {
412 	cil_log(CIL_ERR,
413 			"flavor \"%s\" is not supported, look in file \"%s\""
414 			" on line %d to add support.\n", flavor, __FILE__, line);
415 	return SEPOL_ENOTSUP;
416 }
417 
cil_write_policycap(struct cil_tree_node * node,FILE * cil_out)418 static int cil_write_policycap(struct cil_tree_node *node, FILE *cil_out) {
419 	struct cil_policycap *polcap = (struct cil_policycap *)node->data;
420 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_POLICYCAP, polcap->datum.name);
421 	return SEPOL_OK;
422 }
423 
cil_write_perm(struct cil_tree_node * node,FILE * cil_out)424 static int cil_write_perm(struct cil_tree_node *node, FILE *cil_out) {
425 	struct cil_perm *perm = (struct cil_perm *)node->data;
426 	fprintf(cil_out, "%s", perm->datum.name);
427 	if (node->next != NULL)
428 		fprintf(cil_out, " ");
429 	return SEPOL_OK;
430 }
431 
432 
cil_write_class(struct cil_tree_node * node,uint32_t * finished,struct cil_args_write * extra_args)433 static int cil_write_class(struct cil_tree_node *node, uint32_t *finished,
434 		     struct cil_args_write *extra_args) {
435 	int rc = SEPOL_ERR;
436 	FILE *cil_out = extra_args->cil_out;
437 	struct cil_symtab_datum *datum = (struct cil_symtab_datum *)node->data;
438 	char *class_type = (node->flavor == CIL_CLASS) ? CIL_KEY_CLASS : CIL_KEY_COMMON;
439 
440 	/* print preamble */
441 	fprintf(cil_out, "(%s %s ", class_type, datum->name);
442 
443 	if (node->cl_head == NULL) {
444 		/* no associated perms in this part of tree */
445 		fprintf(cil_out, "()");
446 	} else {
447 
448 		/* visit subtree (perms) */
449 		rc = cil_tree_walk(node, __cil_write_node_helper,
450 				   __cil_write_first_child_helper,
451 				   __cil_write_last_child_helper,
452 				   extra_args);
453 		if (rc != SEPOL_OK)
454 			goto exit;
455 	}
456 
457 	/* postamble (trailing paren) */
458 	fprintf(cil_out, ")\n");
459 	*finished = CIL_TREE_SKIP_HEAD;
460 	rc = SEPOL_OK;
461 exit:
462 	return rc;
463 }
464 
cil_write_classorder(struct cil_tree_node * node,FILE * cil_out)465 static int cil_write_classorder(struct cil_tree_node *node, FILE *cil_out) {
466 	int rc = SEPOL_ERR;
467 	char *ord_str = NULL;
468 	struct cil_classorder *classord = (struct cil_classorder *)node->data;
469 
470 	/* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */
471 	rc = cil_unfill_expr(classord->class_list_str, &ord_str, 1);
472 	if (rc != SEPOL_OK)
473 		goto exit;
474 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_CLASSORDER, ord_str);
475 	rc = SEPOL_OK;
476 exit:
477 	free(ord_str);
478 	return rc;
479 }
480 
cil_write_classcommon(struct cil_tree_node * node,FILE * cil_out)481 static int cil_write_classcommon(struct cil_tree_node *node, FILE *cil_out) {
482 	struct cil_classcommon *classcommon = (struct cil_classcommon *)node->data;
483 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_CLASSCOMMON, classcommon->class_str,
484 		classcommon->common_str);
485 	return SEPOL_OK;
486 }
487 
cil_write_sid(struct cil_tree_node * node,FILE * cil_out)488 static int cil_write_sid(struct cil_tree_node *node, FILE *cil_out) {
489 	struct cil_sid *sid = (struct cil_sid *)node->data;
490 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_SID, sid->datum.name);
491 	return SEPOL_OK;
492 }
493 
cil_write_sidcontext(struct cil_tree_node * node,FILE * cil_out)494 static int cil_write_sidcontext(struct cil_tree_node *node, FILE *cil_out) {
495 	int rc = SEPOL_ERR;
496 	char *sid;
497 	char *ctx_str = NULL;
498 	struct cil_sidcontext *sidcon = (struct cil_sidcontext *)node->data;
499 
500 	sid = sidcon->sid_str;
501 	if (sidcon->context_str != NULL) {
502 		ctx_str = strdup(sidcon->context_str);
503 		if (ctx_str == NULL) {
504 			cil_log(CIL_ERR, "OOM. Unable to copy context string.\n");
505             rc = SEPOL_ERR;
506 			goto exit;
507 		}
508 	} else {
509 		rc = cil_unfill_context(sidcon->context, &ctx_str);
510 		if (rc != SEPOL_OK)
511 			goto exit;
512 	}
513 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_SIDCONTEXT, sid, ctx_str);
514 	rc = SEPOL_OK;
515 exit:
516 	free(ctx_str);
517 	return rc;
518 }
519 
cil_write_sidorder(struct cil_tree_node * node,FILE * cil_out)520 static int cil_write_sidorder(struct cil_tree_node *node, FILE *cil_out) {
521 	int rc = SEPOL_ERR;
522 	char *ord_str = NULL;
523 	struct cil_sidorder *sidord = (struct cil_sidorder *)node->data;
524 
525 	/* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */
526 	rc = cil_unfill_expr(sidord->sid_list_str, &ord_str, 1);
527 	if (rc != SEPOL_OK)
528 		goto exit;
529 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_SIDORDER, ord_str);
530 	rc = SEPOL_OK;
531 exit:
532 	free(ord_str);
533 	return rc;
534 }
535 
cil_write_user(struct cil_tree_node * node,FILE * cil_out)536 static int cil_write_user(struct cil_tree_node *node, FILE *cil_out) {
537 	struct cil_user *user = (struct cil_user *)node->data;
538 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_USER, user->datum.name);
539 	return SEPOL_OK;
540 }
541 
cil_write_userrole(struct cil_tree_node * node,FILE * cil_out)542 static int cil_write_userrole(struct cil_tree_node *node, FILE *cil_out) {
543 	struct cil_userrole *userrole = (struct cil_userrole *)node->data;
544 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERROLE, userrole->user_str,
545 		userrole->role_str);
546 	return SEPOL_OK;
547 }
548 
cil_write_userlevel(struct cil_tree_node * node,FILE * cil_out)549 static int cil_write_userlevel(struct cil_tree_node *node, FILE *cil_out) {
550 	struct cil_userlevel *usrlvl = (struct cil_userlevel *)node->data;
551 	int rc = SEPOL_ERR;
552 	char *usr;
553 	char *lvl = NULL;
554 
555 	usr = usrlvl->user_str;
556 	if (usrlvl->level_str != NULL) {
557 		lvl = strdup(usrlvl->level_str);
558 		if (lvl == NULL) {
559 			cil_log(CIL_ERR, "OOM. Unable to copy level string.\n");
560             rc = SEPOL_ERR;
561 			goto exit;
562 		}
563 	} else {
564 		rc = cil_unfill_level(usrlvl->level, &lvl);
565 		if (rc != SEPOL_OK)
566 			goto exit;
567 	}
568 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERLEVEL, usr, lvl);
569 	rc = SEPOL_OK;
570 exit:
571 	free(lvl);
572 	return rc;
573 }
574 
cil_write_userrange(struct cil_tree_node * node,FILE * cil_out)575 static int cil_write_userrange(struct cil_tree_node *node, FILE *cil_out) {
576 	struct cil_userrange *usrrng = (struct cil_userrange *)node->data;
577 	int rc = SEPOL_ERR;
578 	char *usr;
579 	char *range = NULL;
580 
581 	usr = usrrng->user_str;
582 	if (usrrng->range_str != NULL) {
583 		range = strdup(usrrng->range_str);
584 		if (range == NULL) {
585 			cil_log(CIL_ERR, "OOM. Unable to copy levelrange string.\n");
586             rc = SEPOL_ERR;
587 			goto exit;
588 		}
589 	} else {
590 		rc = cil_unfill_levelrange(usrrng->range, &range);
591 		if (rc != SEPOL_OK)
592 			goto exit;
593 	}
594 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERRANGE, usr, range);
595 	rc = SEPOL_OK;
596 exit:
597 	free(range);
598 	return rc;
599 }
600 
cil_write_role(struct cil_tree_node * node,FILE * cil_out)601 static int cil_write_role(struct cil_tree_node *node, FILE *cil_out) {
602 	struct cil_role *role = (struct cil_role *)node->data;
603 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_ROLE, role->datum.name);
604 	return SEPOL_OK;
605 }
606 
cil_write_roletype(struct cil_tree_node * node,FILE * cil_out)607 static int cil_write_roletype(struct cil_tree_node *node, FILE *cil_out) {
608 	struct cil_roletype *roletype = (struct cil_roletype *)node->data;
609 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_ROLETYPE, roletype->role_str, roletype->type_str);
610 	return SEPOL_OK;
611 }
612 
cil_write_roleattribute(struct cil_tree_node * node,FILE * cil_out)613 static int cil_write_roleattribute(struct cil_tree_node *node, FILE *cil_out) {
614 	struct cil_roleattribute *roleattr = (struct cil_roleattribute *)node->data;
615 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_ROLEATTRIBUTE, roleattr->datum.name);
616 	return SEPOL_OK;
617 }
618 
cil_write_type(struct cil_tree_node * node,FILE * cil_out)619 static int cil_write_type(struct cil_tree_node *node, FILE *cil_out) {
620 	struct cil_type *type = (struct cil_type *)node->data;
621 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPE, type->datum.name);
622 	return SEPOL_OK;
623 }
624 
cil_write_typepermissive(struct cil_tree_node * node,FILE * cil_out)625 static int cil_write_typepermissive(struct cil_tree_node *node, FILE *cil_out) {
626 	struct cil_typepermissive *type = (struct cil_typepermissive *)node->data;
627 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPEPERMISSIVE, type->type_str);
628 	return SEPOL_OK;
629 }
630 
cil_write_typeattribute(struct cil_tree_node * node,FILE * cil_out)631 static int cil_write_typeattribute(struct cil_tree_node *node, FILE *cil_out) {
632 	struct cil_typeattribute *typeattr = (struct cil_typeattribute *)node->data;
633 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPEATTRIBUTE, typeattr->datum.name);
634 	return SEPOL_OK;
635 }
636 
cil_write_typeattributeset(struct cil_tree_node * node,FILE * cil_out)637 static int cil_write_typeattributeset(struct cil_tree_node *node, FILE *cil_out) {
638 	int rc = SEPOL_ERR;
639 	char *typeattr;
640 	char *set_str = NULL;
641 	struct cil_typeattributeset *typeattrset = (struct cil_typeattributeset *)node->data;
642 
643 	typeattr = typeattrset->attr_str;
644 	rc = cil_unfill_expr(typeattrset->str_expr, &set_str, 1);
645 	if (rc != SEPOL_OK)
646 		goto exit;
647 
648 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_TYPEATTRIBUTESET, typeattr, set_str);
649 	rc = SEPOL_OK;
650 exit:
651 	free(set_str);
652 	return rc;
653 }
654 
cil_write_expandtypeattribute(struct cil_tree_node * node,FILE * cil_out)655 static int cil_write_expandtypeattribute(struct cil_tree_node *node, FILE *cil_out)
656 {
657 	int rc = SEPOL_ERR;
658 	char *attr_strs = NULL;
659 	struct cil_expandtypeattribute *expandattr = (struct cil_expandtypeattribute *)node->data;
660 
661 	rc = cil_unfill_expr(expandattr->attr_strs, &attr_strs, 1);
662 	if (rc != SEPOL_OK)
663 		goto exit;
664 
665 	fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_EXPANDTYPEATTRIBUTE, attr_strs,
666 		expandattr->expand ? CIL_KEY_CONDTRUE : CIL_KEY_CONDFALSE);
667 	rc = SEPOL_OK;
668 exit:
669 	free(attr_strs);
670 	return rc;
671 }
672 
cil_write_alias(struct cil_tree_node * node,FILE * cil_out)673 static int cil_write_alias(struct cil_tree_node *node, FILE *cil_out) {
674 	int rc = SEPOL_ERR;
675 	char *type;
676 	struct cil_alias *alias = (struct cil_alias *)node->data;
677 
678 	switch (node->flavor) {
679 	case CIL_TYPEALIAS:
680 		type = CIL_KEY_TYPEALIAS;
681 		break;
682 	case CIL_SENSALIAS:
683 		type = CIL_KEY_SENSALIAS;
684 		break;
685 	case CIL_CATALIAS:
686 		type = CIL_KEY_CATALIAS;
687 		break;
688 	default:
689 		cil_log(CIL_ERR, "Unknown alias type: %d\n", node->flavor);
690 		rc = SEPOL_ERR;
691 		goto exit;
692 		break;
693 	}
694 	fprintf(cil_out, "(%s %s)\n", type, alias->datum.name);
695 	rc = SEPOL_OK;
696 exit:
697 	return rc;
698 }
699 
cil_write_aliasactual(struct cil_tree_node * node,FILE * cil_out)700 static int cil_write_aliasactual(struct cil_tree_node *node, FILE *cil_out) {
701 	int rc = SEPOL_ERR;
702 	char *type, *alias, *actual;
703 	struct cil_aliasactual *aliasact = (struct cil_aliasactual *)node->data;
704 
705 	switch (node->flavor) {
706 	case CIL_TYPEALIASACTUAL:
707 		type = CIL_KEY_TYPEALIASACTUAL;
708 		break;
709 	case CIL_SENSALIASACTUAL:
710 		type = CIL_KEY_SENSALIASACTUAL;
711 		break;
712 	case CIL_CATALIASACTUAL:
713 		type = CIL_KEY_CATALIASACTUAL;
714 		break;
715 	default:
716 		cil_log(CIL_ERR, "Unknown alias type: %d\n", node->flavor);
717 		rc = SEPOL_ERR;
718 		goto exit;
719 		break;
720 	}
721 	alias = aliasact->alias_str;
722 	actual = aliasact->actual_str;
723 	fprintf(cil_out, "(%s %s %s)\n", type, alias, actual);
724 	rc = SEPOL_OK;
725 exit:
726 	return rc;
727 }
728 
cil_write_nametypetransition(struct cil_tree_node * node,FILE * cil_out)729 static int cil_write_nametypetransition(struct cil_tree_node *node, FILE *cil_out) {
730 	char *src, *tgt, *obj, *res, *name;
731 	struct cil_nametypetransition *ntrans = (struct cil_nametypetransition *)node->data;
732 
733 	src = ntrans->src_str;
734 	tgt = ntrans->tgt_str;
735 	obj = ntrans->obj_str;
736 	res = ntrans->result_str;
737 	name = ntrans->name_str;
738 	fprintf(cil_out, "(%s %s %s %s \"%s\" %s)\n", CIL_KEY_TYPETRANSITION,
739 		src, tgt, obj, name, res);
740 	return SEPOL_OK;
741 }
742 
cil_write_avrule_x(struct cil_avrule * avrule,FILE * cil_out)743 static int cil_write_avrule_x(struct cil_avrule *avrule, FILE *cil_out) {
744 	int rc = SEPOL_ERR;
745 	char *rulekind, *src, *tgt;
746 	char *xperms = NULL;
747 
748 	switch (avrule->rule_kind) {
749 	case CIL_AVRULE_ALLOWED:
750 		rulekind = CIL_KEY_ALLOWX;
751 		break;
752 	case CIL_AVRULE_AUDITALLOW:
753 		rulekind = CIL_KEY_AUDITALLOWX;
754 		break;
755 	case CIL_AVRULE_DONTAUDIT:
756 		rulekind = CIL_KEY_DONTAUDITX;
757 		break;
758 	case CIL_AVRULE_NEVERALLOW:
759 		rulekind = CIL_KEY_NEVERALLOWX;
760 		break;
761 	default:
762 		cil_log(CIL_ERR, "Unknown AVRULE type: %d\n", avrule->rule_kind);
763 		rc = SEPOL_ERR;
764 		goto exit;
765 		break;
766 	}
767 	src = avrule->src_str;
768 	tgt = avrule->tgt_str;
769 
770 	if (avrule->perms.x.permx_str != NULL) {
771 		xperms = strdup(avrule->perms.x.permx_str);
772 		if (xperms == NULL) {
773 			cil_log(CIL_ERR, "OOM. Unable to copy xperms string.\n");
774 			rc = SEPOL_ERR;
775 			goto exit;
776 		}
777 	} else {
778 		rc = cil_unfill_permx(avrule->perms.x.permx, &xperms);
779 		if (rc != SEPOL_OK)
780 			goto exit;
781 	}
782 	fprintf(cil_out, "(%s %s %s %s)\n", rulekind, src, tgt, xperms);
783 	rc = SEPOL_OK;
784 exit:
785 	free(xperms);
786 	return rc;
787 }
788 
cil_write_avrule_orig(struct cil_avrule * avrule,FILE * cil_out)789 static int cil_write_avrule_orig(struct cil_avrule *avrule, FILE *cil_out) {
790 	int rc = SEPOL_ERR;
791 	char *rulekind, *src, *tgt;
792 	char *classperms = NULL;
793 
794 	switch (avrule->rule_kind) {
795 	case CIL_AVRULE_ALLOWED:
796 		rulekind = CIL_KEY_ALLOW;
797 		break;
798 	case CIL_AVRULE_AUDITALLOW:
799 		rulekind = CIL_KEY_AUDITALLOW;
800 		break;
801 	case CIL_AVRULE_DONTAUDIT:
802 		rulekind = CIL_KEY_DONTAUDIT;
803 		break;
804 	case CIL_AVRULE_NEVERALLOW:
805 		rulekind = CIL_KEY_NEVERALLOW;
806 		break;
807 	default:
808 		cil_log(CIL_ERR, "Unknown AVRULE type: %d\n", avrule->rule_kind);
809 		rc = SEPOL_ERR;
810 		goto exit;
811 		break;
812 	}
813 	src = avrule->src_str;
814 	tgt = avrule->tgt_str;
815 
816 	rc = cil_unfill_classperms_list(avrule->perms.classperms, &classperms, 0);
817 	if (rc != SEPOL_OK)
818 		goto exit;
819 	fprintf(cil_out, "(%s %s %s %s)\n", rulekind, src, tgt, classperms);
820 	rc = SEPOL_OK;
821 exit:
822 	free(classperms);
823 	return rc;
824 }
825 
cil_write_avrule(struct cil_tree_node * node,FILE * cil_out)826 static int cil_write_avrule(struct cil_tree_node *node, FILE *cil_out) {
827 	int rc = SEPOL_ERR;
828 	struct cil_avrule *avrule = (struct cil_avrule *)node->data;
829 
830 	if (avrule->is_extended)
831 		rc = cil_write_avrule_x(avrule, cil_out);
832 	else
833 		rc = cil_write_avrule_orig(avrule, cil_out);
834 	return rc;
835 }
836 
cil_write_type_rule(struct cil_tree_node * node,FILE * cil_out)837 static int cil_write_type_rule(struct cil_tree_node *node, FILE *cil_out) {
838 	int rc = SEPOL_ERR;
839 	char *type, *src, *tgt, *obj, *res;
840 	struct cil_type_rule *typerule = (struct cil_type_rule *)node->data;
841 
842 	switch (typerule->rule_kind) {
843 	case CIL_TYPE_TRANSITION:
844 		type = CIL_KEY_TYPETRANSITION;
845 		break;
846 	case CIL_TYPE_MEMBER:
847 		type = CIL_KEY_TYPEMEMBER;
848 		break;
849 	case CIL_TYPE_CHANGE:
850 		type = CIL_KEY_TYPECHANGE;
851 		break;
852 	default:
853 		cil_log(CIL_ERR, "Unknown TYPERULE type: %d\n", typerule->rule_kind);
854 		rc = SEPOL_ERR;
855 		goto exit;
856 		break;
857 	}
858 	src = typerule->src_str;
859 	tgt = typerule->tgt_str;
860 	obj = typerule->obj_str;
861 	res = typerule->result_str;
862 	fprintf(cil_out, "(%s %s %s %s %s)\n", type, src, tgt, obj, res);
863 	rc = SEPOL_OK;
864 exit:
865 	return rc;
866 }
867 
cil_write_sens(struct cil_tree_node * node,FILE * cil_out)868 static int cil_write_sens(struct cil_tree_node *node, FILE *cil_out) {
869 	struct cil_sens *sens = (struct cil_sens *)node->data;
870 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_SENSITIVITY, sens->datum.name);
871 	return SEPOL_OK;
872 }
873 
cil_write_cat(struct cil_tree_node * node,FILE * cil_out)874 static int cil_write_cat(struct cil_tree_node *node, FILE *cil_out) {
875 	struct cil_cat *cat = (struct cil_cat *)node->data;
876 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_CATEGORY, cat->datum.name);
877 	return SEPOL_OK;
878 }
879 
cil_write_senscat(struct cil_tree_node * node,FILE * cil_out)880 static int cil_write_senscat(struct cil_tree_node *node, FILE *cil_out) {
881 	int rc = SEPOL_ERR;
882 	char *sens;
883 	char *cats = NULL;
884 	struct cil_senscat *senscat = (struct cil_senscat *)node->data;
885 
886 	sens = senscat->sens_str;
887 	rc = cil_unfill_cats(senscat->cats, &cats);
888 	if (rc != SEPOL_OK)
889 		goto exit;
890 	/* TODO: deal with extra/missing parens */
891 	fprintf(cil_out, "(%s %s (%s))\n", CIL_KEY_SENSCAT, sens, cats);
892 	rc = SEPOL_OK;
893 exit:
894 	free(cats);
895 	return rc;
896 }
897 
cil_write_catorder(struct cil_tree_node * node,FILE * cil_out)898 static int cil_write_catorder(struct cil_tree_node *node, FILE *cil_out) {
899 	int rc = SEPOL_ERR;
900 	char *ord_str = NULL;
901 	struct cil_catorder *catord = (struct cil_catorder *)node->data;
902 
903 	/* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */
904 	rc = cil_unfill_expr(catord->cat_list_str, &ord_str, 1);
905 	if (rc != SEPOL_OK)
906 		goto exit;
907 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_CATORDER, ord_str);
908 	rc = SEPOL_OK;
909 exit:
910 	free(ord_str);
911 	return rc;
912 }
913 
cil_write_sensorder(struct cil_tree_node * node,FILE * cil_out)914 static int cil_write_sensorder(struct cil_tree_node *node, FILE *cil_out) {
915 	int rc = SEPOL_ERR;
916 	char *ord_str = NULL;
917 	struct cil_sensorder *sensord = (struct cil_sensorder *)node->data;
918 
919 	/* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */
920 	rc = cil_unfill_expr(sensord->sens_list_str, &ord_str, 1);
921 	if (rc != SEPOL_OK)
922 		goto exit;
923 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_SENSITIVITYORDER, ord_str);
924 	rc = SEPOL_OK;
925 exit:
926 	free(ord_str);
927 	return rc;
928 }
929 
cil_write_genfscon(struct cil_tree_node * node,FILE * cil_out)930 static int cil_write_genfscon(struct cil_tree_node *node, FILE *cil_out) {
931 	int rc = SEPOL_ERR;
932 	char *ctx_str = NULL;
933 
934 	struct cil_genfscon *genfscon = (struct cil_genfscon *)node->data;
935 	if (genfscon->context_str != NULL) {
936 		ctx_str = strdup(genfscon->context_str);
937 		if (ctx_str == NULL) {
938 			cil_log(CIL_ERR, "OOM. Unable to copy context string.\n");
939             rc = SEPOL_ERR;
940 			goto exit;
941 		}
942 	} else {
943 		rc = cil_unfill_context(genfscon->context, &ctx_str);
944 		if (rc != SEPOL_OK)
945 			goto exit;
946 	}
947 	fprintf(cil_out, "(%s %s %s %s)\n", CIL_KEY_GENFSCON, genfscon->fs_str,
948             genfscon->path_str, ctx_str);
949 	rc = SEPOL_OK;
950 exit:
951 	free(ctx_str);
952 	return rc;
953 }
954 
cil_unfill_classperms(struct cil_list_item * curr,char ** out_str)955 static int cil_unfill_classperms(struct cil_list_item *curr, char **out_str) {
956 	int rc = SEPOL_ERR;
957 	size_t len = 3;
958 	char *class_str;
959 	char *perms_str = NULL;
960 	struct cil_classperms *cp = (struct cil_classperms *)curr->data;
961 
962 	class_str = cp->class_str;
963 	len += strlen(class_str) + 1;
964 
965 	/* fill_perms just calls gen_expr */
966 	rc = cil_unfill_expr(cp->perm_strs, &perms_str, 1);
967 	if (rc != SEPOL_OK)
968 		goto exit;
969 	len += strlen(perms_str);
970 	*out_str = cil_malloc(len);
971 	sprintf(*out_str, "(%s %s)", class_str, perms_str);
972 	rc = SEPOL_OK;
973 exit:
974 	free(perms_str);
975 	return rc;
976 }
977 
cil_unfill_classperms_list(struct cil_list * classperms,char ** out_str,int paren)978 static int cil_unfill_classperms_list(struct cil_list *classperms, char **out_str, int paren) {
979 	int rc = SEPOL_ERR;
980 	struct cil_list_item *curr;
981 	char *str = NULL;
982 
983 	/* reuse cil_list to keep track of strings */
984 	struct cil_list *str_list = NULL;
985 	cil_list_init(&str_list, CIL_NONE);
986 	cil_list_for_each(curr, classperms) {
987 		switch (curr->flavor) {
988 		case CIL_CLASSPERMS_SET:
989 			str = strdup(((struct cil_classperms_set *)curr->data)->set_str);
990 			if (str == NULL) {
991 				cil_log(CIL_ERR, "OOM. Unable to copy classpermset.\n");
992                 rc = SEPOL_ERR;
993 				goto exit;
994 			}
995 			break;
996 		case CIL_CLASSPERMS:
997 			rc = cil_unfill_classperms(curr, &str);
998 			if (rc != SEPOL_OK)
999 				goto exit;
1000 			break;
1001 		default:
1002 			cil_log(CIL_ERR, "Unrecognized classperms flavor\n.");
1003 			goto exit;
1004 		}
1005 		cil_list_append(str_list, CIL_STRING, (void *) str);
1006 		str = NULL;
1007 	}
1008 	rc = __cil_strlist_concat(str_list, out_str, paren);
1009 	if (rc != SEPOL_OK)
1010 		goto exit;
1011 	rc = SEPOL_OK;
1012 exit:
1013 	cil_list_for_each(curr, str_list) {
1014 		free(curr->data);
1015 	}
1016 	cil_list_destroy(&str_list, 0);
1017 	return rc;
1018 }
1019 
cil_write_fsuse(struct cil_tree_node * node,FILE * cil_out)1020 static int cil_write_fsuse(struct cil_tree_node *node, FILE *cil_out) {
1021 	int rc = SEPOL_ERR;
1022 	struct cil_fsuse *fsuse = (struct cil_fsuse *)node->data;
1023 	char *type, *fsname;
1024 	char *ctx_str = NULL;
1025 
1026 	switch(fsuse->type) {
1027 	case CIL_FSUSE_XATTR:
1028 		type = CIL_KEY_XATTR;
1029 		break;
1030 	case CIL_FSUSE_TASK:
1031 		type = CIL_KEY_TASK;
1032 		break;
1033 	case CIL_FSUSE_TRANS:
1034 		type = CIL_KEY_TRANS;
1035 		break;
1036 	default:
1037 		cil_log(CIL_ERR, "Unrecognized fsuse type\n");
1038 		rc = SEPOL_ERR;
1039 		goto exit;
1040 		break;
1041 	}
1042 
1043 	fsname = fsuse->fs_str;
1044 	if (fsuse->context_str != NULL) {
1045 		ctx_str = strdup(fsuse->context_str);
1046 		if (ctx_str == NULL) {
1047 			cil_log(CIL_ERR, "OOM. Unable to copy context string.\n");
1048 			rc = SEPOL_ERR;
1049 			goto exit;
1050 		}
1051 	} else {
1052 		rc = cil_unfill_context(fsuse->context, &ctx_str);
1053 		if (rc != SEPOL_OK)
1054 			goto exit;
1055 	}
1056 	fprintf(cil_out, "(%s %s %s %s)\n", CIL_KEY_FSUSE, type, fsname, ctx_str);
1057 exit:
1058 	free(ctx_str);
1059 	return rc;
1060 }
1061 
cil_write_constrain(struct cil_tree_node * node,FILE * cil_out)1062 static int cil_write_constrain(struct cil_tree_node *node, FILE *cil_out) {
1063 	int rc = SEPOL_ERR;
1064 	struct cil_constrain *cons = (struct cil_constrain *)node->data;
1065 	char *flav;
1066 	char *classperms = NULL;
1067 	char *expr = NULL;
1068 
1069 	flav = (node->flavor == CIL_CONSTRAIN) ? CIL_KEY_CONSTRAIN : CIL_KEY_MLSCONSTRAIN;
1070 
1071 	rc = cil_unfill_classperms_list(cons->classperms, &classperms, 0);
1072 	if (rc != SEPOL_OK)
1073 		goto exit;
1074 
1075 	rc = cil_unfill_expr(cons->str_expr, &expr, 0);
1076 	if (rc != SEPOL_OK)
1077 		goto exit;
1078 
1079 	fprintf(cil_out, "(%s %s %s)\n", flav, classperms, expr);
1080 exit:
1081 	free(classperms);
1082 	free(expr);
1083 	return rc;
1084 }
1085 
cil_write_handleunknown(struct cil_tree_node * node,FILE * cil_out)1086 static int cil_write_handleunknown(struct cil_tree_node *node, FILE *cil_out) {
1087 	int rc = SEPOL_OK;
1088 	struct cil_handleunknown *handunknown = (struct cil_handleunknown *)node->data;
1089 	char *val = NULL;
1090 	switch (handunknown->handle_unknown) {
1091 	case SEPOL_ALLOW_UNKNOWN:
1092 		val = CIL_KEY_HANDLEUNKNOWN_ALLOW;
1093 		break;
1094 	case SEPOL_DENY_UNKNOWN:
1095 		val = CIL_KEY_HANDLEUNKNOWN_DENY;
1096 		break;
1097 	case SEPOL_REJECT_UNKNOWN:
1098 		val = CIL_KEY_HANDLEUNKNOWN_REJECT;
1099 		break;
1100 	default:
1101 		cil_log(CIL_ERR, "Unknown handleunknown value: %d.\n",
1102 			handunknown->handle_unknown);
1103 		rc = SEPOL_ERR;
1104 		goto exit;
1105 		break;
1106 	}
1107 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_HANDLEUNKNOWN, val);
1108 exit:
1109 	return rc;
1110 }
1111 
cil_write_mls(struct cil_tree_node * node,FILE * cil_out)1112 static int cil_write_mls(struct cil_tree_node *node, FILE *cil_out) {
1113 	int rc = SEPOL_OK;
1114 	struct cil_mls *mls = (struct cil_mls *)node->data;
1115 	char *val = NULL;
1116 	switch (mls->value) {
1117 	case CIL_TRUE:
1118 		val = CIL_KEY_CONDTRUE;
1119 		break;
1120 	case CIL_FALSE:
1121 		val = CIL_KEY_CONDFALSE;
1122 		break;
1123 	default:
1124 		cil_log(CIL_ERR, "Unknown mls value: %d.\n", mls->value);
1125 		rc = SEPOL_ERR;
1126 		goto exit;
1127 		break;
1128 	}
1129 	fprintf(cil_out, "(%s %s)\n", CIL_KEY_MLS, val);
1130 exit:
1131 	return rc;
1132 }
1133 
__cil_write_first_child_helper(struct cil_tree_node * node,void * extra_args)1134 static int __cil_write_first_child_helper(struct cil_tree_node *node, void *extra_args)
1135 {
1136 	int rc = SEPOL_ERR;
1137 	struct cil_args_write *args = (struct cil_args_write *) extra_args;
1138 	FILE *cil_out = NULL;
1139 
1140 	if (node == NULL || extra_args == NULL) {
1141 		goto exit;
1142 	}
1143 
1144 	cil_out = args->cil_out;
1145 
1146 	if (node->parent && node->parent->flavor != CIL_ROOT && node->parent->flavor != CIL_SRC_INFO)
1147 		fprintf(cil_out,"(");
1148 	rc = SEPOL_OK;
1149 exit:
1150 	return rc;
1151 }
1152 
__cil_write_node_helper(struct cil_tree_node * node,uint32_t * finished,void * extra_args)1153 static int __cil_write_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
1154 {
1155 	int rc = SEPOL_OK;
1156 	struct cil_args_write *args = NULL;
1157 	FILE *cil_out = NULL;
1158 
1159 	if (node == NULL || extra_args == NULL) {
1160 		goto exit;
1161 	}
1162 
1163 	args = extra_args;
1164 	cil_out = args->cil_out;
1165 
1166 	switch (node->flavor) {
1167 	case CIL_BLOCK:
1168 		rc = cil_write_unsupported("CIL_BLOCK");
1169 		break;
1170 	case CIL_BLOCKABSTRACT:
1171 		rc = cil_write_unsupported("CIL_BLOCKABSTRACT");
1172 		break;
1173 	case CIL_BLOCKINHERIT:
1174 		rc = cil_write_unsupported("CIL_BLOCKINHERIT");
1175 		break;
1176 	case CIL_IN:
1177 		rc = cil_write_unsupported("CIL_IN");
1178 		break;
1179 	case CIL_POLICYCAP:
1180 		cil_write_policycap(node, cil_out);
1181 		break;
1182 	case CIL_PERM:
1183 		rc = cil_write_perm(node, cil_out);
1184 		break;
1185 	case CIL_MAP_PERM:
1186 		rc = cil_write_unsupported("CIL_MAP_PERM");
1187 		break;
1188 	case CIL_CLASSMAPPING:
1189 		rc = cil_write_unsupported("CIL_CLASSMAPPING");
1190 		break;
1191 	case CIL_CLASS:
1192 		rc = cil_write_class(node, finished, extra_args);
1193 		break;
1194 	case CIL_COMMON:
1195 		rc = cil_write_class(node, finished, extra_args);
1196 		break;
1197 	case CIL_MAP_CLASS:
1198 		rc = cil_write_unsupported("CIL_MAP_CLASS");
1199 		break;
1200 	case CIL_CLASSORDER:
1201 		rc = cil_write_classorder(node, cil_out);
1202 		break;
1203 	case CIL_CLASSPERMISSION:
1204 		rc = cil_write_unsupported("CIL_CLASSPERMISSION");
1205 		break;
1206 	case CIL_CLASSPERMISSIONSET:
1207 		rc = cil_write_unsupported("CIL_CLASSPERMISSIONSET");
1208 		break;
1209 	case CIL_CLASSCOMMON:
1210 		rc = cil_write_classcommon(node, cil_out);
1211 		break;
1212 	case CIL_SID:
1213 		rc = cil_write_sid(node, cil_out);
1214 		break;
1215 	case CIL_SIDCONTEXT:
1216 		rc = cil_write_sidcontext(node, cil_out);
1217 		break;
1218 	case CIL_SIDORDER:
1219 		rc = cil_write_sidorder(node, cil_out);
1220 		break;
1221 	case CIL_USER:
1222 		rc = cil_write_user(node, cil_out);
1223 		break;
1224 	case CIL_USERATTRIBUTE:
1225 		rc = cil_write_unsupported("CIL_USERATTRIBUTE");
1226 		break;
1227 	case CIL_USERATTRIBUTESET:
1228 		rc = cil_write_unsupported("CIL_USERATTRIBUTESET");
1229 		break;
1230 	case CIL_USERROLE:
1231 		rc = cil_write_userrole(node, cil_out);
1232 		break;
1233 	case CIL_USERLEVEL:
1234 		rc = cil_write_userlevel(node, cil_out);
1235 		break;
1236 	case CIL_USERRANGE:
1237 		rc = cil_write_userrange(node, cil_out);
1238 		break;
1239 	case CIL_USERBOUNDS:
1240 		rc = cil_write_unsupported("CIL_USERBOUNDS");
1241 		break;
1242 	case CIL_USERPREFIX:
1243 		rc = cil_write_unsupported("CIL_USERPREFIX");
1244 		break;
1245 	case CIL_ROLE:
1246 		rc = cil_write_role(node, cil_out);
1247 		break;
1248 	case CIL_ROLETYPE:
1249 		rc = cil_write_roletype(node, cil_out);
1250 		break;
1251 	case CIL_ROLEBOUNDS:
1252 		rc = cil_write_unsupported("CIL_ROLEBOUNDS");
1253 		break;
1254 	case CIL_ROLEATTRIBUTE:
1255 		cil_write_roleattribute(node, cil_out);
1256 		break;
1257 	case CIL_ROLEATTRIBUTESET:
1258 		rc = cil_write_unsupported("CIL_ROLEATTRIBUTESET");
1259 		break;
1260 	case CIL_ROLEALLOW:
1261 		rc = cil_write_unsupported("CIL_ROLEALLOW");
1262 		break;
1263 	case CIL_TYPE:
1264 		rc = cil_write_type(node, cil_out);
1265 		break;
1266 	case CIL_TYPEBOUNDS:
1267 		rc = cil_write_unsupported("CIL_TYPEBOUNDS");
1268 		break;
1269 	case CIL_TYPEPERMISSIVE:
1270 		rc = cil_write_typepermissive(node, cil_out);
1271 		break;
1272 	case CIL_TYPEATTRIBUTE:
1273 		rc = cil_write_typeattribute(node, cil_out);
1274 		break;
1275 	case CIL_TYPEATTRIBUTESET:
1276 		rc = cil_write_typeattributeset(node, cil_out);
1277 		break;
1278     case CIL_EXPANDTYPEATTRIBUTE:
1279         rc = cil_write_expandtypeattribute(node, cil_out);
1280         break;
1281 	case CIL_TYPEALIAS:
1282 		rc = cil_write_alias(node, cil_out);
1283 		break;
1284 	case CIL_TYPEALIASACTUAL:
1285 		rc = cil_write_aliasactual(node, cil_out);
1286 		break;
1287 	case CIL_ROLETRANSITION:
1288 		rc = cil_write_unsupported("CIL_ROLETRANSITION");
1289 		break;
1290 	case CIL_NAMETYPETRANSITION:
1291 		rc = cil_write_nametypetransition(node, cil_out);
1292 		break;
1293 	case CIL_RANGETRANSITION:
1294 		rc = cil_write_unsupported("CIL_RANGETRANSITION");
1295 		break;
1296 	case CIL_TUNABLE:
1297 		rc = cil_write_unsupported("CIL_TUNABLE");
1298 		break;
1299 	case CIL_BOOL:
1300 		rc = cil_write_unsupported("CIL_BOOL");
1301 		break;
1302 	case CIL_AVRULE:
1303 	case CIL_AVRULEX:
1304 		rc = cil_write_avrule(node, cil_out);
1305 		break;
1306 	case CIL_PERMISSIONX:
1307 		rc = cil_write_unsupported("CIL_PERMISSIONX");
1308 		break;
1309 	case CIL_TYPE_RULE:
1310 		cil_write_type_rule(node, cil_out);
1311 		break;
1312 	case CIL_SENS:
1313 		rc = cil_write_sens(node, cil_out);
1314 		break;
1315 	case CIL_SENSALIAS:
1316 		rc = cil_write_alias(node, cil_out);
1317 		break;
1318 	case CIL_SENSALIASACTUAL:
1319 		rc = cil_write_aliasactual(node, cil_out);
1320 		break;
1321 	case CIL_CAT:
1322 		rc = cil_write_cat(node, cil_out);
1323 		break;
1324 	case CIL_CATALIAS:
1325 		rc = cil_write_alias(node, cil_out);
1326 		break;
1327 	case CIL_CATALIASACTUAL:
1328 		rc = cil_write_aliasactual(node, cil_out);
1329 		break;
1330 	case CIL_CATSET:
1331 		rc = cil_write_unsupported("CIL_CATSET");
1332 		break;
1333 	case CIL_SENSCAT:
1334 		rc = cil_write_senscat(node, cil_out);
1335 		break;
1336 	case CIL_CATORDER:
1337 		rc = cil_write_catorder(node, cil_out);
1338 		break;
1339 	case CIL_SENSITIVITYORDER:
1340 		rc = cil_write_sensorder(node, cil_out);
1341 		break;
1342 	case CIL_LEVEL:
1343 		rc = cil_write_unsupported("CIL_LEVEL");
1344 		break;
1345 	case CIL_LEVELRANGE:
1346 		rc = cil_write_unsupported("CIL_LEVELRANGE");
1347 		break;
1348 	case CIL_CONTEXT:
1349 		rc = cil_write_unsupported("CIL_CONTEXT");
1350 		break;
1351 	case CIL_NETIFCON:
1352 		rc = cil_write_unsupported("CIL_NETIFCON");
1353 		break;
1354 	case CIL_GENFSCON:
1355 		 rc = cil_write_genfscon(node, cil_out);
1356 		break;
1357 	case CIL_FILECON:
1358 		rc = cil_write_unsupported("CIL_FILECON");
1359 		break;
1360 	case CIL_NODECON:
1361 		rc = cil_write_unsupported("CIL_NODECON");
1362 		break;
1363 	case CIL_PORTCON:
1364 		rc = cil_write_unsupported("CIL_PORTCON");
1365 		break;
1366 	case CIL_PIRQCON:
1367 		rc = cil_write_unsupported("CIL_PIRQCON");
1368 		break;
1369 	case CIL_IOMEMCON:
1370 		rc = cil_write_unsupported("CIL_IOMEMCON");
1371 		break;
1372 	case CIL_IOPORTCON:
1373 		rc = cil_write_unsupported("CIL_IOPORTCON");
1374 		break;
1375 	case CIL_PCIDEVICECON:
1376 		rc = cil_write_unsupported("CIL_PCIDEVICECON");
1377 		break;
1378 	case CIL_DEVICETREECON:
1379 		rc = cil_write_unsupported("CIL_DEVICETREECON");
1380 		break;
1381 	case CIL_FSUSE:
1382 		rc = cil_write_fsuse(node, cil_out);
1383 		break;
1384 	case CIL_CONSTRAIN:
1385 		rc = cil_write_unsupported("CIL_CONSTRAIN");
1386 		break;
1387 	case CIL_MLSCONSTRAIN:
1388 		rc = cil_write_constrain(node, cil_out);
1389 		break;
1390 	case CIL_VALIDATETRANS:
1391 		rc = cil_write_unsupported("CIL_VALIDATETRANS");
1392 		break;
1393 	case CIL_MLSVALIDATETRANS:
1394 		rc = cil_write_unsupported("CIL_MLSVALIDATETRANS");
1395 		break;
1396 	case CIL_CALL:
1397 		rc = cil_write_unsupported("CIL_CALL");
1398 		break;
1399 	case CIL_MACRO:
1400 		rc = cil_write_unsupported("CIL_MACRO");
1401 		break;
1402 	case CIL_NODE:
1403 		rc = cil_write_unsupported("CIL_NODE");
1404 		break;
1405 	case CIL_OPTIONAL:
1406 		rc = cil_write_unsupported("CIL_OPTIONAL");
1407 		break;
1408 	case CIL_IPADDR:
1409 		rc = cil_write_unsupported("CIL_IPADDR");
1410 		break;
1411 	case CIL_CONDBLOCK:
1412 		rc = cil_write_unsupported("CIL_CONDBLOCK");
1413 		break;
1414 	case CIL_BOOLEANIF:
1415 		rc = cil_write_unsupported("CIL_BOOLEANIF");
1416 		break;
1417 	case CIL_TUNABLEIF:
1418 		rc = cil_write_unsupported("CIL_TUNABLEIF");
1419 		break;
1420 	case CIL_DEFAULTUSER:
1421 		rc = cil_write_unsupported("CIL_DEFAULTUSER");
1422 		break;
1423 	case CIL_DEFAULTROLE:
1424 		rc = cil_write_unsupported("CIL_DEFAULTROLE");
1425 		break;
1426 	case CIL_DEFAULTTYPE:
1427 		rc = cil_write_unsupported("CIL_DEFAULTTYPE");
1428 		break;
1429 	case CIL_DEFAULTRANGE:
1430 		rc = cil_write_unsupported("CIL_DEFAULTRANGE");
1431 		break;
1432 	case CIL_SELINUXUSER:
1433 		rc = cil_write_unsupported("CIL_SELINUXUSER");
1434 		break;
1435 	case CIL_SELINUXUSERDEFAULT:
1436 		rc = cil_write_unsupported("CIL_SELINUXUSERDEFAULT");
1437 		break;
1438 	case CIL_HANDLEUNKNOWN:
1439 		rc = cil_write_handleunknown(node, cil_out);
1440 		break;
1441 	case CIL_MLS:
1442 		rc = cil_write_mls(node, cil_out);
1443 		break;
1444 	case CIL_SRC_INFO:
1445 		break;
1446 	case CIL_NONE:
1447 		// TODO: add proper removal support
1448 		*finished = CIL_TREE_SKIP_HEAD;
1449 		break;
1450 	default:
1451 		cil_log(CIL_ERR, "Unknown AST flavor: %d.\n", node->flavor);
1452 		rc = SEPOL_ERR;
1453 		goto exit;
1454 		break;
1455 	}
1456 exit:
1457 	return rc;
1458 }
1459 
__cil_write_last_child_helper(struct cil_tree_node * node,void * extra_args)1460 static int __cil_write_last_child_helper(struct cil_tree_node *node, void *extra_args)
1461 {
1462 	int rc = SEPOL_ERR;
1463 	struct cil_args_write *args = NULL;
1464 	FILE *cil_out = NULL;
1465 
1466 	if (node == NULL || extra_args == NULL) {
1467 		goto exit;
1468 	}
1469 
1470 	args = extra_args;
1471 	cil_out = args->cil_out;
1472 
1473 	if (node->parent && node->parent->flavor != CIL_ROOT && node->parent->flavor != CIL_SRC_INFO) {
1474 		fprintf(cil_out,")");
1475 	}
1476 	rc = SEPOL_OK;
1477 exit:
1478 	return rc;
1479 }
1480 
1481 /* main exported function */
cil_write_ast(struct cil_db * db,const char * path)1482 int cil_write_ast(struct cil_db *db, const char* path) {
1483 	int rc = SEPOL_ERR;
1484 	struct cil_args_write extra_args;
1485 	FILE *cil_out = NULL;
1486 
1487 	cil_out = fopen(path, "we");
1488 	if (cil_out == NULL) {
1489 		cil_log(CIL_ERR, "Failure opening output file for writing AST\n");
1490 		rc = SEPOL_ERR;
1491 		goto exit;
1492 	}
1493 
1494 	extra_args.cil_out = cil_out;
1495 	extra_args.db = db;
1496 	rc = cil_tree_walk(db->ast->root, __cil_write_node_helper,
1497 			   __cil_write_first_child_helper,
1498 			   __cil_write_last_child_helper,
1499 			   &extra_args);
1500 	if (rc != SEPOL_OK) {
1501 		cil_log(CIL_INFO, "cil_tree_walk failed, rc: %d\n", rc);
1502 		goto exit;
1503 	}
1504 
1505 exit:
1506 	fclose(cil_out);
1507 	cil_out = NULL;
1508 	return rc;
1509 }
1510