Home | History | Annotate | Download | only in src
      1 #include <stdarg.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <inttypes.h>
      6 #include <sys/types.h>
      7 #include <unistd.h>
      8 
      9 #include <arpa/inet.h>
     10 #include <netinet/in.h>
     11 #ifndef IPPROTO_DCCP
     12 #define IPPROTO_DCCP 33
     13 #endif
     14 
     15 #include <sepol/policydb/avtab.h>
     16 #include <sepol/policydb/conditional.h>
     17 #include <sepol/policydb/flask.h>
     18 #include <sepol/policydb/hashtab.h>
     19 #include <sepol/policydb/polcaps.h>
     20 #include <sepol/policydb/policydb.h>
     21 #include <sepol/policydb/services.h>
     22 #include <sepol/policydb/util.h>
     23 
     24 #include "kernel_to_common.h"
     25 
     26 
     27 static char *cond_expr_to_str(struct policydb *pdb, struct cond_expr *expr)
     28 {
     29 	struct cond_expr *curr;
     30 	struct strs *stack;
     31 	char *new_val;
     32 	char *str = NULL;
     33 	int rc;
     34 
     35 	rc = stack_init(&stack);
     36 	if (rc != 0) {
     37 		goto exit;
     38 	}
     39 
     40 	for (curr = expr; curr != NULL; curr = curr->next) {
     41 		if (curr->expr_type == COND_BOOL) {
     42 			char *val1 = pdb->p_bool_val_to_name[curr->bool - 1];
     43 			new_val = create_str("%s", 1, val1);
     44 		} else {
     45 			const char *op;
     46 			uint32_t num_params;
     47 			char *val1 = NULL;
     48 			char *val2 = NULL;
     49 
     50 			switch(curr->expr_type) {
     51 			case COND_NOT:	op = "!";  num_params = 1; break;
     52 			case COND_OR:	op = "||"; num_params = 2; break;
     53 			case COND_AND:	op = "&&"; num_params = 2; break;
     54 			case COND_XOR:	op = "^";  num_params = 2; break;
     55 			case COND_EQ:	op = "=="; num_params = 2; break;
     56 			case COND_NEQ:	op = "!="; num_params = 2; break;
     57 			default:
     58 				sepol_log_err("Unknown conditional operator: %i", curr->expr_type);
     59 				goto exit;
     60 			}
     61 
     62 			if (num_params == 2) {
     63 				val2 = stack_pop(stack);
     64 				if (!val2) {
     65 					sepol_log_err("Invalid conditional expression");
     66 					goto exit;
     67 				}
     68 			}
     69 			val1 = stack_pop(stack);
     70 			if (!val1) {
     71 				sepol_log_err("Invalid conditional expression");
     72 				free(val2);
     73 				goto exit;
     74 			}
     75 			if (num_params == 2) {
     76 				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
     77 				free(val2);
     78 			} else {
     79 				new_val = create_str("%s %s", 2, op, val1);
     80 			}
     81 			free(val1);
     82 		}
     83 		if (!new_val) {
     84 			sepol_log_err("Invalid conditional expression");
     85 			goto exit;
     86 		}
     87 		rc = stack_push(stack, new_val);
     88 		if (rc != 0) {
     89 			sepol_log_err("Out of memory");
     90 			goto exit;
     91 		}
     92 	}
     93 
     94 	new_val = stack_pop(stack);
     95 	if (!new_val || !stack_empty(stack)) {
     96 		sepol_log_err("Invalid conditional expression");
     97 		goto exit;
     98 	}
     99 
    100 	str = new_val;
    101 
    102 	stack_destroy(&stack);
    103 	return str;
    104 
    105 exit:
    106 	while ((new_val = stack_pop(stack)) != NULL) {
    107 		free(new_val);
    108 	}
    109 	stack_destroy(&stack);
    110 
    111 	return NULL;
    112 }
    113 
    114 static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr *expr, int *use_mls)
    115 {
    116 	struct constraint_expr *curr;
    117 	struct strs *stack = NULL;
    118 	char *new_val = NULL;
    119 	const char *op;
    120 	char *str = NULL;
    121 	int rc;
    122 
    123 	*use_mls = 0;
    124 
    125 	rc = stack_init(&stack);
    126 	if (rc != 0) {
    127 		goto exit;
    128 	}
    129 
    130 	for (curr = expr; curr; curr = curr->next) {
    131 		if (curr->expr_type == CEXPR_ATTR || curr->expr_type == CEXPR_NAMES) {
    132 			const char *attr1 = NULL;
    133 			const char *attr2 = NULL;
    134 
    135 			switch (curr->op) {
    136 			case CEXPR_EQ:      op = "==";     break;
    137 			case CEXPR_NEQ:     op = "!=";    break;
    138 			case CEXPR_DOM:     op = "dom";    break;
    139 			case CEXPR_DOMBY:   op = "domby";  break;
    140 			case CEXPR_INCOMP:  op = "incomp"; break;
    141 			default:
    142 				sepol_log_err("Unknown constraint operator: %i", curr->op);
    143 				goto exit;
    144 			}
    145 
    146 			switch (curr->attr) {
    147 			case CEXPR_USER:                 attr1 ="u1"; attr2 ="u2"; break;
    148 			case CEXPR_USER | CEXPR_TARGET:  attr1 ="u2"; attr2 ="";   break;
    149 			case CEXPR_USER | CEXPR_XTARGET: attr1 ="u3"; attr2 ="";   break;
    150 			case CEXPR_ROLE:                 attr1 ="r1"; attr2 ="r2"; break;
    151 			case CEXPR_ROLE | CEXPR_TARGET:  attr1 ="r2"; attr2 ="";   break;
    152 			case CEXPR_ROLE | CEXPR_XTARGET: attr1 ="r3"; attr2 ="";   break;
    153 			case CEXPR_TYPE:                 attr1 ="t1"; attr2 ="t2"; break;
    154 			case CEXPR_TYPE | CEXPR_TARGET:  attr1 ="t2"; attr2 ="";   break;
    155 			case CEXPR_TYPE | CEXPR_XTARGET: attr1 ="t3"; attr2 ="";   break;
    156 			case CEXPR_L1L2:                 attr1 ="l1"; attr2 ="l2"; break;
    157 			case CEXPR_L1H2:                 attr1 ="l1"; attr2 ="h2"; break;
    158 			case CEXPR_H1L2:                 attr1 ="h1"; attr2 ="l2"; break;
    159 			case CEXPR_H1H2:                 attr1 ="h1"; attr2 ="h2"; break;
    160 			case CEXPR_L1H1:                 attr1 ="l1"; attr2 ="h1"; break;
    161 			case CEXPR_L2H2:                 attr1 ="l2"; attr2 ="h2"; break;
    162 			default:
    163 				sepol_log_err("Unknown constraint attribute: %i", curr->attr);
    164 				goto exit;
    165 			}
    166 
    167 			if (curr->attr >= CEXPR_XTARGET) {
    168 				*use_mls = 1;
    169 			}
    170 
    171 			if (curr->expr_type == CEXPR_ATTR) {
    172 				new_val = create_str("%s %s %s", 3, attr1, op, attr2);
    173 			} else {
    174 				char *names = NULL;
    175 				if (curr->attr & CEXPR_TYPE) {
    176 					struct type_set *ts = curr->type_names;
    177 					names = ebitmap_to_str(&ts->types, pdb->p_type_val_to_name, 1);
    178 				} else if (curr->attr & CEXPR_USER) {
    179 					names = ebitmap_to_str(&curr->names, pdb->p_user_val_to_name, 1);
    180 				} else if (curr->attr & CEXPR_ROLE) {
    181 					names = ebitmap_to_str(&curr->names, pdb->p_role_val_to_name, 1);
    182 				}
    183 				if (!names) {
    184 					goto exit;
    185 				}
    186 				new_val = create_str("%s %s %s", 3, attr1, op, names);
    187 				free(names);
    188 			}
    189 		} else {
    190 			uint32_t num_params;
    191 			char *val1 = NULL;
    192 			char *val2 = NULL;
    193 
    194 			switch (curr->expr_type) {
    195 			case CEXPR_NOT: op = "not"; num_params = 1; break;
    196 			case CEXPR_AND: op = "and"; num_params = 2; break;
    197 			case CEXPR_OR:  op = "or";  num_params = 2; break;
    198 			default:
    199 				sepol_log_err("Unknown constraint expression type: %i", curr->expr_type);
    200 				goto exit;
    201 			}
    202 
    203 			if (num_params == 2) {
    204 				val2 = stack_pop(stack);
    205 				if (!val2) {
    206 					sepol_log_err("Invalid constraint expression");
    207 					goto exit;
    208 				}
    209 			}
    210 			val1 = stack_pop(stack);
    211 			if (!val1) {
    212 				sepol_log_err("Invalid constraint expression");
    213 				goto exit;
    214 			}
    215 
    216 			if (num_params == 2) {
    217 				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
    218 				free(val2);
    219 			} else {
    220 				new_val = create_str("%s (%s)", 2, op, val1);
    221 			}
    222 			free(val1);
    223 		}
    224 		if (!new_val) {
    225 			goto exit;
    226 		}
    227 		rc = stack_push(stack, new_val);
    228 		if (rc != 0) {
    229 			sepol_log_err("Out of memory");
    230 			goto exit;
    231 		}
    232 	}
    233 
    234 	new_val = stack_pop(stack);
    235 	if (!new_val || !stack_empty(stack)) {
    236 		sepol_log_err("Invalid constraint expression");
    237 		goto exit;
    238 	}
    239 
    240 	str = new_val;
    241 
    242 	stack_destroy(&stack);
    243 
    244 	return str;
    245 
    246 exit:
    247 	while ((new_val = stack_pop(stack)) != NULL) {
    248 		free(new_val);
    249 	}
    250 	stack_destroy(&stack);
    251 
    252 	return NULL;
    253 }
    254 
    255 static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
    256 					  class_datum_t *class,
    257 					  struct constraint_node *constraint_rules,
    258 					  struct strs *mls_list,
    259 					  struct strs *non_mls_list)
    260 {
    261 	struct constraint_node *curr;
    262 	struct strs *strs;
    263 	const char *format_str, *flavor;
    264 	char *perms, *expr;
    265 	int is_mls;
    266 	int rc = 0;
    267 
    268 	for (curr = constraint_rules; curr != NULL; curr = curr->next) {
    269 		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
    270 		if (!expr) {
    271 			rc = -1;
    272 			goto exit;
    273 		}
    274 
    275 		perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
    276 		if (strchr(perms, ' ')) {
    277 			format_str = "%s %s { %s } %s;";
    278 		} else {
    279 			format_str = "%s %s %s %s";
    280 		}
    281 		if (is_mls) {
    282 			flavor = "mlsconstrain";
    283 			strs = mls_list;
    284 		} else {
    285 			flavor = "constrain";
    286 			strs = non_mls_list;
    287 		}
    288 
    289 		rc = strs_create_and_add(strs, format_str, 4,
    290 					 flavor, classkey, perms+1, expr);
    291 		free(expr);
    292 		if (rc != 0) {
    293 			goto exit;
    294 		}
    295 	}
    296 
    297 	return 0;
    298 exit:
    299 	sepol_log_err("Error gathering constraint rules\n");
    300 	return rc;
    301 }
    302 
    303 static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classkey,
    304 					     struct constraint_node *validatetrans_rules,
    305 					     struct strs *mls_list,
    306 					     struct strs *non_mls_list)
    307 {
    308 	struct constraint_node *curr;
    309 	struct strs *strs;
    310 	const char *flavor;
    311 	char *expr;
    312 	int is_mls;
    313 	int rc = 0;
    314 
    315 	for (curr = validatetrans_rules; curr != NULL; curr = curr->next) {
    316 		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
    317 		if (!expr) {
    318 			rc = -1;
    319 			goto exit;
    320 		}
    321 
    322 		if (is_mls) {
    323 			flavor = "mlsvalidatetrans";
    324 			strs = mls_list;
    325 		} else {
    326 			flavor = "validatetrans";
    327 			strs = non_mls_list;
    328 		}
    329 
    330 		rc = strs_create_and_add(strs, "%s %s %s;", 3, flavor, classkey, expr);
    331 		free(expr);
    332 		if (rc != 0) {
    333 			goto exit;
    334 		}
    335 	}
    336 
    337 exit:
    338 	return rc;
    339 }
    340 
    341 static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
    342 {
    343 	class_datum_t *class;
    344 	char *name;
    345 	unsigned i;
    346 	int rc = 0;
    347 
    348 	for (i=0; i < pdb->p_classes.nprim; i++) {
    349 		class = pdb->class_val_to_struct[i];
    350 		if (class->constraints) {
    351 			name = pdb->p_class_val_to_name[i];
    352 			rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
    353 			if (rc != 0) {
    354 				goto exit;
    355 			}
    356 		}
    357 	}
    358 
    359 	strs_sort(mls_strs);
    360 	strs_sort(non_mls_strs);
    361 
    362 exit:
    363 	return rc;
    364 }
    365 
    366 static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
    367 {
    368 	class_datum_t *class;
    369 	char *name;
    370 	unsigned i;
    371 	int rc = 0;
    372 
    373 	for (i=0; i < pdb->p_classes.nprim; i++) {
    374 		class = pdb->class_val_to_struct[i];
    375 		if (class->validatetrans) {
    376 			name = pdb->p_class_val_to_name[i];
    377 			rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
    378 			if (rc != 0) {
    379 				goto exit;
    380 			}
    381 		}
    382 	}
    383 
    384 	strs_sort(mls_strs);
    385 	strs_sort(non_mls_strs);
    386 
    387 exit:
    388 	return rc;
    389 }
    390 
    391 static int write_handle_unknown_to_conf(FILE *out, struct policydb *pdb)
    392 {
    393 	const char *action;
    394 
    395 	switch (pdb->handle_unknown) {
    396 	case SEPOL_DENY_UNKNOWN:
    397 		action = "deny";
    398 		break;
    399 	case SEPOL_REJECT_UNKNOWN:
    400 		action = "reject";
    401 		break;
    402 	case SEPOL_ALLOW_UNKNOWN:
    403 		action = "allow";
    404 		break;
    405 	default:
    406 		sepol_log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
    407 		return -1;
    408 	}
    409 
    410 	sepol_printf(out, "# handle_unknown %s\n", action);
    411 
    412 	return 0;
    413 }
    414 
    415 static int write_class_decl_rules_to_conf(FILE *out, struct policydb *pdb)
    416 {
    417 	char *name;
    418 	unsigned i;
    419 
    420 	for (i=0; i < pdb->p_classes.nprim; i++) {
    421 		name = pdb->p_class_val_to_name[i];
    422 		sepol_printf(out, "class %s\n", name);
    423 	}
    424 
    425 	return 0;
    426 }
    427 
    428 static int write_sids_to_conf(FILE *out, const char *const *sid_to_str, struct ocontext *isids)
    429 {
    430 	struct ocontext *isid;
    431 	struct strs *strs;
    432 	char *sid;
    433 	unsigned i;
    434 	int rc;
    435 
    436 	rc = strs_init(&strs, SECINITSID_NUM+1);
    437 	if (rc != 0) {
    438 		goto exit;
    439 	}
    440 
    441 	for (isid = isids; isid != NULL; isid = isid->next) {
    442 		i = isid->sid[0];
    443 		rc = strs_add_at_index(strs, (char *)sid_to_str[i], i);
    444 		if (rc != 0) {
    445 			goto exit;
    446 		}
    447 	}
    448 
    449 	for (i=0; i<strs_num_items(strs); i++) {
    450 		sid = strs_read_at_index(strs, i);
    451 		if (!sid) {
    452 			continue;
    453 		}
    454 		sepol_printf(out, "sid %s\n", sid);
    455 	}
    456 
    457 exit:
    458 	strs_destroy(&strs);
    459 	if (rc != 0) {
    460 		sepol_log_err("Error writing sid rules to policy.conf\n");
    461 	}
    462 
    463 	return rc;
    464 }
    465 
    466 static int write_sid_decl_rules_to_conf(FILE *out, struct policydb *pdb)
    467 {
    468 	int rc = 0;
    469 
    470 	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
    471 		rc = write_sids_to_conf(out, selinux_sid_to_str, pdb->ocontexts[0]);
    472 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
    473 		rc = write_sids_to_conf(out, xen_sid_to_str, pdb->ocontexts[0]);
    474 	} else {
    475 		sepol_log_err("Unknown target platform: %i", pdb->target_platform);
    476 		rc = -1;
    477 	}
    478 
    479 	return rc;
    480 }
    481 static char *class_or_common_perms_to_str(symtab_t *permtab)
    482 {
    483 	struct strs *strs;
    484 	char *perms = NULL;
    485 	int rc = 0;
    486 
    487 	rc = strs_init(&strs, permtab->nprim);
    488 	if (rc != 0) {
    489 		goto exit;
    490 	}
    491 
    492 	rc = hashtab_map(permtab->table, hashtab_ordered_to_strs, strs);
    493 	if (rc != 0) {
    494 		goto exit;
    495 	}
    496 
    497 	if (strs_num_items(strs) > 0) {
    498 		perms = strs_to_str(strs);
    499 	}
    500 
    501 exit:
    502 	strs_destroy(&strs);
    503 
    504 	return perms;
    505 }
    506 
    507 static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb)
    508 {
    509 	class_datum_t *class;
    510 	common_datum_t *common;
    511 	int *used;
    512 	char *name, *perms;
    513 	unsigned i;
    514 	int rc = 0;
    515 
    516 	/* common */
    517 	used = calloc(pdb->p_commons.nprim, sizeof(*used));
    518 	if (!used) {
    519 		sepol_log_err("Out of memory");
    520 		rc = -1;
    521 		goto exit;
    522 	}
    523 	for (i=0; i < pdb->p_classes.nprim; i++) {
    524 		class = pdb->class_val_to_struct[i];
    525 		name = class->comkey;
    526 		if (!name) continue;
    527 		common = hashtab_search(pdb->p_commons.table, name);
    528 		if (!common) {
    529 			rc = -1;
    530 			free(used);
    531 			goto exit;
    532 		}
    533 		/* Only write common rule once */
    534 		if (!used[common->s.value-1]) {
    535 			perms = class_or_common_perms_to_str(&common->permissions);
    536 			if (!perms) {
    537 				rc = -1;
    538 				free(used);
    539 				goto exit;
    540 			}
    541 			sepol_printf(out, "common %s { %s }\n", name, perms);
    542 			free(perms);
    543 			used[common->s.value-1] = 1;
    544 		}
    545 	}
    546 	free(used);
    547 
    548 	/* class */
    549 	for (i=0; i < pdb->p_classes.nprim; i++) {
    550 		class = pdb->class_val_to_struct[i];
    551 		name = pdb->p_class_val_to_name[i];
    552 		sepol_printf(out, "class %s", name);
    553 		if (class->comkey) {
    554 			sepol_printf(out, " inherits %s", class->comkey);
    555 		}
    556 		perms = class_or_common_perms_to_str(&class->permissions);
    557 		if (perms) {
    558 			sepol_printf(out, " { %s }", perms);
    559 			free(perms);
    560 		}
    561 		sepol_printf(out, "\n");
    562 	}
    563 
    564 exit:
    565 	if (rc != 0) {
    566 		sepol_log_err("Error writing class rules to policy.conf\n");
    567 	}
    568 
    569 	return rc;
    570 }
    571 
    572 static int write_default_user_to_conf(FILE *out, char *class_name, class_datum_t *class)
    573 {
    574 	const char *dft;
    575 
    576 	switch (class->default_user) {
    577 	case DEFAULT_SOURCE:
    578 		dft = "source";
    579 		break;
    580 	case DEFAULT_TARGET:
    581 		dft = "target";
    582 		break;
    583 	default:
    584 		sepol_log_err("Unknown default role value: %i", class->default_user);
    585 		return -1;
    586 	}
    587 	sepol_printf(out, "default_user { %s } %s;\n", class_name, dft);
    588 
    589 	return 0;
    590 }
    591 
    592 static int write_default_role_to_conf(FILE *out, char *class_name, class_datum_t *class)
    593 {
    594 	const char *dft;
    595 
    596 	switch (class->default_role) {
    597 	case DEFAULT_SOURCE:
    598 		dft = "source";
    599 		break;
    600 	case DEFAULT_TARGET:
    601 		dft = "target";
    602 		break;
    603 	default:
    604 		sepol_log_err("Unknown default role value: %i", class->default_role);
    605 		return -1;
    606 	}
    607 	sepol_printf(out, "default_role { %s } %s;\n", class_name, dft);
    608 
    609 	return 0;
    610 }
    611 
    612 static int write_default_type_to_conf(FILE *out, char *class_name, class_datum_t *class)
    613 {
    614 	const char *dft;
    615 
    616 	switch (class->default_type) {
    617 	case DEFAULT_SOURCE:
    618 		dft = "source";
    619 		break;
    620 	case DEFAULT_TARGET:
    621 		dft = "target";
    622 		break;
    623 	default:
    624 		sepol_log_err("Unknown default type value: %i", class->default_type);
    625 		return -1;
    626 	}
    627 	sepol_printf(out, "default_type { %s } %s;\n", class_name, dft);
    628 
    629 	return 0;
    630 }
    631 
    632 static int write_default_range_to_conf(FILE *out, char *class_name, class_datum_t *class)
    633 {
    634 	const char *dft;
    635 
    636 	switch (class->default_range) {
    637 	case DEFAULT_SOURCE_LOW:
    638 		dft = "source low";
    639 		break;
    640 	case DEFAULT_SOURCE_HIGH:
    641 		dft = "source high";
    642 		break;
    643 	case DEFAULT_SOURCE_LOW_HIGH:
    644 		dft = "source low-high";
    645 		break;
    646 	case DEFAULT_TARGET_LOW:
    647 		dft = "target low";
    648 		break;
    649 	case DEFAULT_TARGET_HIGH:
    650 		dft = "target high";
    651 		break;
    652 	case DEFAULT_TARGET_LOW_HIGH:
    653 		dft = "target low-high";
    654 		break;
    655 	default:
    656 		sepol_log_err("Unknown default type value: %i", class->default_range);
    657 		return -1;
    658 	}
    659 	sepol_printf(out, "default_range { %s } %s;\n", class_name, dft);
    660 
    661 	return 0;
    662 }
    663 
    664 static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
    665 {
    666 	class_datum_t *class;
    667 	unsigned i;
    668 	int rc = 0;
    669 
    670 	/* default_user */
    671 	for (i=0; i < pdb->p_classes.nprim; i++) {
    672 		class = pdb->class_val_to_struct[i];
    673 		if (class->default_user != 0) {
    674 			rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class);
    675 			if (rc != 0) {
    676 				goto exit;
    677 			}
    678 		}
    679 	}
    680 
    681 	/* default_role */
    682 	for (i=0; i < pdb->p_classes.nprim; i++) {
    683 		class = pdb->class_val_to_struct[i];
    684 		if (class->default_role != 0) {
    685 			rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class);
    686 			if (rc != 0) {
    687 				goto exit;
    688 			}
    689 		}
    690 	}
    691 
    692 	/* default_type */
    693 	for (i=0; i < pdb->p_classes.nprim; i++) {
    694 		class = pdb->class_val_to_struct[i];
    695 		if (class->default_type != 0) {
    696 			rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class);
    697 			if (rc != 0) {
    698 				goto exit;
    699 			}
    700 		}
    701 	}
    702 
    703 	if (!pdb->mls) {
    704 		return 0;
    705 	}
    706 
    707 	/* default_range */
    708 	for (i=0; i < pdb->p_classes.nprim; i++) {
    709 		class = pdb->class_val_to_struct[i];
    710 		if (class->default_range != 0) {
    711 			rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class);
    712 			if (rc != 0) {
    713 				goto exit;
    714 			}
    715 		}
    716 	}
    717 
    718 exit:
    719 	if (rc != 0) {
    720 		sepol_log_err("Error writing default rules to policy.conf\n");
    721 	}
    722 
    723 	return rc;
    724 }
    725 
    726 static int map_sensitivity_aliases_to_strs(char *key, void *data, void *args)
    727 {
    728 	level_datum_t *sens = data;
    729 	struct strs *strs = args;
    730 	int rc = 0;
    731 
    732 	if (sens->isalias) {
    733 		rc = strs_add(strs, key);
    734 	}
    735 
    736 	return rc;
    737 }
    738 
    739 static int write_sensitivity_rules_to_conf(FILE *out, struct policydb *pdb)
    740 {
    741 	level_datum_t *level;
    742 	struct strs *strs;
    743 	char **sens_alias_map = NULL;
    744 	char *name, *prev, *alias;
    745 	unsigned i, j, num;
    746 	int rc = 0;
    747 
    748 	rc = strs_init(&strs, pdb->p_levels.nprim);
    749 	if (rc != 0) {
    750 		goto exit;
    751 	}
    752 
    753 	rc = hashtab_map(pdb->p_levels.table, map_sensitivity_aliases_to_strs, strs);
    754 	if (rc != 0) {
    755 		goto exit;
    756 	}
    757 
    758 	num = strs_num_items(strs);
    759 
    760 	if (num > 0) {
    761 		sens_alias_map = calloc(sizeof(*sens_alias_map), pdb->p_levels.nprim);
    762 		if (!sens_alias_map) {
    763 			rc = -1;
    764 			goto exit;
    765 		}
    766 
    767 		/* map aliases to sensitivities */
    768 		for (i=0; i < num; i++) {
    769 			name = strs_read_at_index(strs, i);
    770 			level = hashtab_search(pdb->p_levels.table, name);
    771 			if (!level) {
    772 				rc = -1;
    773 				goto exit;
    774 			}
    775 			j = level->level->sens - 1;
    776 			if (!sens_alias_map[j]) {
    777 				sens_alias_map[j] = strdup(name);
    778 			} else {
    779 				alias = sens_alias_map[j];
    780 				sens_alias_map[j] = create_str("%s %s", 2, alias, name);
    781 				free(alias);
    782 				if (!sens_alias_map[j]) {
    783 					rc = -1;
    784 					goto exit;
    785 				}
    786 			}
    787 		}
    788 	}
    789 
    790 	/* sensitivities */
    791 	for (i=0; i < pdb->p_levels.nprim; i++) {
    792 		name = pdb->p_sens_val_to_name[i];
    793 		if (!name) continue;
    794 		level = hashtab_search(pdb->p_levels.table, name);
    795 		if (!level) {
    796 			rc = -1;
    797 			goto exit;
    798 		}
    799 		if (level->isalias) continue;
    800 
    801 		if (sens_alias_map && sens_alias_map[i]) {
    802 			alias = sens_alias_map[i];
    803 			if (strchr(alias, ' ')) {
    804 				sepol_printf(out, "sensitivity %s alias { %s };\n", name, alias);
    805 			} else {
    806 				sepol_printf(out, "sensitivity %s alias %s;\n", name, alias);
    807 			}
    808 		} else {
    809 			sepol_printf(out, "sensitivity %s;\n", name);
    810 		}
    811 	}
    812 
    813 	/* dominance */
    814 	sepol_printf(out, "dominance { ");
    815 	prev = NULL;
    816 	for (i=0; i < pdb->p_levels.nprim; i++) {
    817 		name = pdb->p_sens_val_to_name[i];
    818 		if (!name) continue;
    819 		level = hashtab_search(pdb->p_levels.table, name);
    820 		if (!level) {
    821 			rc = -1;
    822 			goto exit;
    823 		}
    824 		if (level->isalias) continue;
    825 
    826 		if (prev) {
    827 			sepol_printf(out, "%s ", prev);
    828 		}
    829 		prev = name;
    830 	}
    831 	if (prev) {
    832 		sepol_printf(out, "%s", prev);
    833 	}
    834 	sepol_printf(out, " }\n");
    835 
    836 exit:
    837 	if (sens_alias_map) {
    838 		for (i=0; i < pdb->p_levels.nprim; i++) {
    839 			free(sens_alias_map[i]);
    840 		}
    841 		free(sens_alias_map);
    842 	}
    843 
    844 	strs_destroy(&strs);
    845 
    846 	if (rc != 0) {
    847 		sepol_log_err("Error writing sensitivity rules to CIL\n");
    848 	}
    849 
    850 	return rc;
    851 }
    852 
    853 static int map_category_aliases_to_strs(char *key, void *data, void *args)
    854 {
    855 	cat_datum_t *cat = data;
    856 	struct strs *strs = args;
    857 	int rc = 0;
    858 
    859 	if (cat->isalias) {
    860 		rc = strs_add(strs, key);
    861 	}
    862 
    863 	return rc;
    864 }
    865 
    866 static int write_category_rules_to_conf(FILE *out, struct policydb *pdb)
    867 {
    868 	cat_datum_t *cat;
    869 	struct strs *strs;
    870 	char **cat_alias_map = NULL;
    871 	char *name, *alias;
    872 	unsigned i, j, num;
    873 	int rc = 0;
    874 
    875 	rc = strs_init(&strs, pdb->p_levels.nprim);
    876 	if (rc != 0) {
    877 		goto exit;
    878 	}
    879 
    880 	rc = hashtab_map(pdb->p_cats.table, map_category_aliases_to_strs, strs);
    881 	if (rc != 0) {
    882 		goto exit;
    883 	}
    884 
    885 	num = strs_num_items(strs);
    886 
    887 	if (num > 0) {
    888 		cat_alias_map = calloc(sizeof(*cat_alias_map), pdb->p_cats.nprim);
    889 		if (!cat_alias_map) {
    890 			rc = -1;
    891 			goto exit;
    892 		}
    893 
    894 		/* map aliases to categories */
    895 		for (i=0; i < num; i++) {
    896 			name = strs_read_at_index(strs, i);
    897 			cat = hashtab_search(pdb->p_cats.table, name);
    898 			if (!cat) {
    899 				rc = -1;
    900 				goto exit;
    901 			}
    902 			j = cat->s.value - 1;
    903 			if (!cat_alias_map[j]) {
    904 				cat_alias_map[j] = strdup(name);
    905 			} else {
    906 				alias = cat_alias_map[j];
    907 				cat_alias_map[j] = create_str("%s %s", 2, alias, name);
    908 				free(alias);
    909 				if (!cat_alias_map[j]) {
    910 					rc = -1;
    911 					goto exit;
    912 				}
    913 			}
    914 		}
    915 	}
    916 
    917 	/* categories */
    918 	for (i=0; i < pdb->p_cats.nprim; i++) {
    919 		name = pdb->p_cat_val_to_name[i];
    920 		if (!name) continue;
    921 		cat = hashtab_search(pdb->p_cats.table, name);
    922 		if (!cat) {
    923 			rc = -1;
    924 			goto exit;
    925 		}
    926 		if (cat->isalias) continue;
    927 
    928 		if (cat_alias_map && cat_alias_map[i]) {
    929 			alias = cat_alias_map[i];
    930 			if (strchr(alias, ' ')) {
    931 				sepol_printf(out, "category %s alias { %s };\n", name, alias);
    932 			} else {
    933 				sepol_printf(out, "category %s alias %s;\n", name, alias);
    934 			}
    935 		} else {
    936 			sepol_printf(out, "category %s;\n", name);
    937 		}
    938 	}
    939 
    940 exit:
    941 	if (cat_alias_map) {
    942 		for (i=0; i < pdb->p_cats.nprim; i++) {
    943 			free(cat_alias_map[i]);
    944 		}
    945 		free(cat_alias_map);
    946 	}
    947 
    948 	strs_destroy(&strs);
    949 
    950 	if (rc != 0) {
    951 		sepol_log_err("Error writing category rules to policy.conf\n");
    952 	}
    953 
    954 	return rc;
    955 }
    956 
    957 static size_t cats_ebitmap_len(struct ebitmap *cats, char **val_to_name)
    958 {
    959 	struct ebitmap_node *node;
    960 	uint32_t i, start, range;
    961 	size_t len = 0;
    962 
    963 	range = 0;
    964 	ebitmap_for_each_bit(cats, node, i) {
    965 		if (!ebitmap_get_bit(cats, i))
    966 			continue;
    967 
    968 		if (range == 0)
    969 			start = i;
    970 
    971 		range++;
    972 
    973 		if (ebitmap_get_bit(cats, i+1))
    974 			continue;
    975 
    976 		len += strlen(val_to_name[start]) + 1;
    977 		if (range > 1) {
    978 			len += strlen(val_to_name[i]) + 1;
    979 		}
    980 
    981 		range = 0;
    982 	}
    983 
    984 	return len;
    985 }
    986 
    987 static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
    988 {
    989 	struct ebitmap_node *node;
    990 	uint32_t i, start, range, first;
    991 	char *catsbuf, *p;
    992 	const char *fmt;
    993 	char sep;
    994 	int len, remaining;
    995 
    996 	remaining = (int)cats_ebitmap_len(cats, val_to_name);
    997 	catsbuf = malloc(remaining);
    998 	if (!catsbuf) {
    999 		goto exit;
   1000 	}
   1001 
   1002 	p = catsbuf;
   1003 
   1004 	first = 1;
   1005 	range = 0;
   1006 	ebitmap_for_each_bit(cats, node, i) {
   1007 		if (!ebitmap_get_bit(cats, i))
   1008 			continue;
   1009 
   1010 		if (range == 0)
   1011 			start = i;
   1012 
   1013 		range++;
   1014 
   1015 		if (ebitmap_get_bit(cats, i+1))
   1016 			continue;
   1017 
   1018 		if (range > 1) {
   1019 			sep = (range == 2) ? ',' : '.';
   1020 			fmt = first ? "%s%c%s" : ",%s%c%s";
   1021 			len = snprintf(p, remaining, fmt,
   1022 				       val_to_name[start], sep, val_to_name[i]);
   1023 		} else {
   1024 			fmt = first ? "%s" : ",%s";
   1025 			len = snprintf(p, remaining, fmt, val_to_name[start]);
   1026 
   1027 		}
   1028 		if (len < 0 || len >= remaining) {
   1029 			goto exit;
   1030 		}
   1031 		p += len;
   1032 		remaining -= len;
   1033 		first = 0;
   1034 		range = 0;
   1035 	}
   1036 
   1037 	*p = '\0';
   1038 
   1039 	return catsbuf;
   1040 
   1041 exit:
   1042 	free(catsbuf);
   1043 	return NULL;
   1044 }
   1045 
   1046 static int write_level_rules_to_conf(FILE *out, struct policydb *pdb)
   1047 {
   1048 	level_datum_t *level;
   1049 	char *name, *cats;
   1050 	unsigned i;
   1051 	int rc = 0;
   1052 
   1053 	for (i=0; i < pdb->p_levels.nprim; i++) {
   1054 		name = pdb->p_sens_val_to_name[i];
   1055 		if (!name) continue;
   1056 		level = hashtab_search(pdb->p_levels.table, name);
   1057 		if (!level) {
   1058 			rc = -1;
   1059 			goto exit;
   1060 		}
   1061 		if (level->isalias) continue;
   1062 
   1063 		if (ebitmap_cardinality(&level->level->cat) > 0) {
   1064 			cats = cats_ebitmap_to_str(&level->level->cat, pdb->p_cat_val_to_name);
   1065 			sepol_printf(out, "level %s:%s;\n", name, cats);
   1066 			free(cats);
   1067 		} else {
   1068 			sepol_printf(out, "level %s;\n", name);
   1069 		}
   1070 	}
   1071 
   1072 exit:
   1073 	if (rc != 0) {
   1074 		sepol_log_err("Error writing level rules to policy.conf\n");
   1075 	}
   1076 
   1077 	return rc;
   1078 }
   1079 
   1080 static int write_mls_rules_to_conf(FILE *out, struct policydb *pdb)
   1081 {
   1082 	int rc = 0;
   1083 
   1084 	if (!pdb->mls) {
   1085 		return 0;
   1086 	}
   1087 
   1088 	rc = write_sensitivity_rules_to_conf(out, pdb);
   1089 	if (rc != 0) {
   1090 		goto exit;
   1091 	}
   1092 
   1093 	rc = write_category_rules_to_conf(out, pdb);
   1094 	if (rc != 0) {
   1095 		goto exit;
   1096 	}
   1097 
   1098 	rc = write_level_rules_to_conf(out, pdb);
   1099 	if (rc != 0) {
   1100 		goto exit;
   1101 	}
   1102 
   1103 exit:
   1104 	if (rc != 0) {
   1105 		sepol_log_err("Error writing mls rules to policy.conf\n");
   1106 	}
   1107 
   1108 	return rc;
   1109 }
   1110 
   1111 static int write_polcap_rules_to_conf(FILE *out, struct policydb *pdb)
   1112 {
   1113 	struct strs *strs;
   1114 	struct ebitmap_node *node;
   1115 	const char *name;
   1116 	uint32_t i;
   1117 	int rc = 0;
   1118 
   1119 	rc = strs_init(&strs, 32);
   1120 	if (rc != 0) {
   1121 		goto exit;
   1122 	}
   1123 
   1124 	ebitmap_for_each_bit(&pdb->policycaps, node, i) {
   1125 		if (!ebitmap_get_bit(&pdb->policycaps, i)) continue;
   1126 
   1127 		name = sepol_polcap_getname(i);
   1128 		if (name == NULL) {
   1129 			sepol_log_err("Unknown policy capability id: %i", i);
   1130 			rc = -1;
   1131 			goto exit;
   1132 		}
   1133 
   1134 		rc = strs_create_and_add(strs, "policycap %s;", 1, name);
   1135 		if (rc != 0) {
   1136 			goto exit;
   1137 		}
   1138 	}
   1139 
   1140 	strs_sort(strs);
   1141 	strs_write_each(strs, out);
   1142 
   1143 exit:
   1144 	strs_free_all(strs);
   1145 	strs_destroy(&strs);
   1146 
   1147 	if (rc != 0) {
   1148 		sepol_log_err("Error writing polcap rules to policy.conf\n");
   1149 	}
   1150 
   1151 	return rc;
   1152 }
   1153 
   1154 static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
   1155 {
   1156 	type_datum_t *type;
   1157 	char *name;
   1158 	struct strs *strs;
   1159 	unsigned i, num;
   1160 	int rc = 0;
   1161 
   1162 	rc = strs_init(&strs, pdb->p_types.nprim);
   1163 	if (rc != 0) {
   1164 		goto exit;
   1165 	}
   1166 
   1167 	for (i=0; i < pdb->p_types.nprim; i++) {
   1168 		type = pdb->type_val_to_struct[i];
   1169 		if (type->flavor == TYPE_ATTRIB) {
   1170 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
   1171 			if (rc != 0) {
   1172 				goto exit;
   1173 			}
   1174 		}
   1175 	}
   1176 
   1177 	strs_sort(strs);
   1178 
   1179 	num = strs_num_items(strs);
   1180 	for (i = 0; i < num; i++) {
   1181 		name = strs_read_at_index(strs, i);
   1182 		if (!name) {
   1183 			rc = -1;
   1184 			goto exit;
   1185 		}
   1186 		sepol_printf(out, "attribute %s;\n", name);
   1187 	}
   1188 
   1189 exit:
   1190 	strs_destroy(&strs);
   1191 
   1192 	if (rc != 0) {
   1193 		sepol_log_err("Error writing typeattribute rules to policy.conf\n");
   1194 	}
   1195 
   1196 	return rc;
   1197 }
   1198 
   1199 static int write_role_attributes_to_conf(FILE *out, struct policydb *pdb)
   1200 {
   1201 	role_datum_t *role;
   1202 	char *name;
   1203 	struct strs *strs;
   1204 	unsigned i, num;
   1205 	int rc = 0;
   1206 
   1207 	rc = strs_init(&strs, pdb->p_roles.nprim);
   1208 	if (rc != 0) {
   1209 		goto exit;
   1210 	}
   1211 
   1212 	for (i=0; i < pdb->p_roles.nprim; i++) {
   1213 		role = pdb->role_val_to_struct[i];
   1214 		if (role && role->flavor == ROLE_ATTRIB) {
   1215 			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
   1216 			if (rc != 0) {
   1217 				goto exit;
   1218 			}
   1219 		}
   1220 	}
   1221 
   1222 	strs_sort(strs);
   1223 
   1224 	num = strs_num_items(strs);
   1225 	for (i=0; i<num; i++) {
   1226 		name = strs_read_at_index(strs, i);
   1227 		if (!name) {
   1228 			rc = -1;
   1229 			goto exit;
   1230 		}
   1231 		sepol_printf(out, "attribute_role %s;\n", name);
   1232 	}
   1233 
   1234 exit:
   1235 	strs_destroy(&strs);
   1236 
   1237 	if (rc != 0) {
   1238 		sepol_log_err("Error writing roleattribute rules to policy.conf\n");
   1239 	}
   1240 
   1241 	return rc;
   1242 }
   1243 
   1244 static int map_boolean_to_strs(char *key, void *data, void *args)
   1245 {
   1246 	struct strs *strs = (struct strs *)args;
   1247 	struct cond_bool_datum *boolean = data;
   1248 	const char *value;
   1249 
   1250 	value = boolean->state ? "true" : "false";
   1251 
   1252 	return strs_create_and_add(strs, "bool %s %s;", 2, key, value);
   1253 }
   1254 
   1255 static int write_boolean_decl_rules_to_conf(FILE *out, struct policydb *pdb)
   1256 {
   1257 	struct strs *strs;
   1258 	int rc = 0;
   1259 
   1260 	rc = strs_init(&strs, 32);
   1261 	if (rc != 0) {
   1262 		goto exit;
   1263 	}
   1264 
   1265 	rc = hashtab_map(pdb->p_bools.table, map_boolean_to_strs, strs);
   1266 	if (rc != 0) {
   1267 		goto exit;
   1268 	}
   1269 
   1270 	strs_sort(strs);
   1271 	strs_write_each(strs, out);
   1272 
   1273 exit:
   1274 	strs_free_all(strs);
   1275 	strs_destroy(&strs);
   1276 
   1277 	if (rc != 0) {
   1278 		sepol_log_err("Error writing boolean declarations to policy.conf\n");
   1279 	}
   1280 
   1281 	return rc;
   1282 }
   1283 
   1284 static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
   1285 {
   1286 	type_datum_t *type;
   1287 	struct strs *strs;
   1288 	char *name;
   1289 	unsigned i, num;
   1290 	int rc = 0;
   1291 
   1292 	rc = strs_init(&strs, pdb->p_types.nprim);
   1293 	if (rc != 0) {
   1294 		goto exit;
   1295 	}
   1296 
   1297 	for (i=0; i < pdb->p_types.nprim; i++) {
   1298 		type = pdb->type_val_to_struct[i];
   1299 		if (type->flavor == TYPE_TYPE && type->primary) {
   1300 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
   1301 			if (rc != 0) {
   1302 				goto exit;
   1303 			}
   1304 		}
   1305 	}
   1306 
   1307 	strs_sort(strs);
   1308 
   1309 	num = strs_num_items(strs);
   1310 	for (i=0; i<num; i++) {
   1311 		name = strs_read_at_index(strs, i);
   1312 		if (!name) {
   1313 			rc = -1;
   1314 			goto exit;
   1315 		}
   1316 		sepol_printf(out, "type %s;\n", name);
   1317 	}
   1318 
   1319 exit:
   1320 	strs_destroy(&strs);
   1321 
   1322 	if (rc != 0) {
   1323 		sepol_log_err("Error writing type declarations to policy.con\n");
   1324 	}
   1325 
   1326 	return rc;
   1327 }
   1328 
   1329 static int write_type_alias_rules_to_conf(FILE *out, struct policydb *pdb)
   1330 {
   1331 	type_datum_t *alias;
   1332 	struct strs *strs;
   1333 	char *name;
   1334 	char *type;
   1335 	unsigned i, num;
   1336 	int rc = 0;
   1337 
   1338 	rc = strs_init(&strs, pdb->p_types.nprim);
   1339 	if (rc != 0) {
   1340 		goto exit;
   1341 	}
   1342 
   1343 	for (i=0; i < pdb->p_types.nprim; i++) {
   1344 		alias = pdb->type_val_to_struct[i];
   1345 		if (!alias->primary) {
   1346 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
   1347 			if (rc != 0) {
   1348 				goto exit;
   1349 			}
   1350 		}
   1351 	}
   1352 
   1353 	strs_sort(strs);
   1354 
   1355 	num = strs_num_items(strs);
   1356 
   1357 	for (i=0; i<num; i++) {
   1358 		name = strs_read_at_index(strs, i);
   1359 		if (!name) {
   1360 			rc = -1;
   1361 			goto exit;
   1362 		}
   1363 		alias = hashtab_search(pdb->p_types.table, name);
   1364 		if (!alias) {
   1365 			rc = -1;
   1366 			goto exit;
   1367 		}
   1368 		type = pdb->p_type_val_to_name[alias->s.value - 1];
   1369 		sepol_printf(out, "typealias %s %s;\n", type, name);
   1370 	}
   1371 
   1372 exit:
   1373 	strs_destroy(&strs);
   1374 
   1375 	if (rc != 0) {
   1376 		sepol_log_err("Error writing type alias rules to policy.conf\n");
   1377 	}
   1378 
   1379 	return rc;
   1380 }
   1381 
   1382 static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
   1383 {
   1384 	type_datum_t *type;
   1385 	struct strs *strs;
   1386 	char *parent;
   1387 	char *child;
   1388 	unsigned i, num;
   1389 	int rc = 0;
   1390 
   1391 	rc = strs_init(&strs, pdb->p_types.nprim);
   1392 	if (rc != 0) {
   1393 		goto exit;
   1394 	}
   1395 
   1396 	for (i=0; i < pdb->p_types.nprim; i++) {
   1397 		type = pdb->type_val_to_struct[i];
   1398 		if (type->flavor == TYPE_TYPE) {
   1399 			if (type->bounds > 0) {
   1400 				rc = strs_add(strs, pdb->p_type_val_to_name[i]);
   1401 				if (rc != 0) {
   1402 					goto exit;
   1403 				}
   1404 			}
   1405 		}
   1406 	}
   1407 
   1408 	strs_sort(strs);
   1409 
   1410 	num = strs_num_items(strs);
   1411 	for (i=0; i<num; i++) {
   1412 		child = strs_read_at_index(strs, i);
   1413 		if (!child) {
   1414 			rc = -1;
   1415 			goto exit;
   1416 		}
   1417 		type = hashtab_search(pdb->p_types.table, child);
   1418 		if (!type) {
   1419 			rc = -1;
   1420 			goto exit;
   1421 		}
   1422 		parent = pdb->p_type_val_to_name[type->bounds - 1];
   1423 		sepol_printf(out, "typebounds %s %s;\n", parent, child);
   1424 	}
   1425 
   1426 exit:
   1427 	strs_destroy(&strs);
   1428 
   1429 	if (rc != 0) {
   1430 		sepol_log_err("Error writing type bounds rules to policy.conf\n");
   1431 	}
   1432 
   1433 	return rc;
   1434 }
   1435 
   1436 static char *attr_strs_to_str(struct strs *strs)
   1437 {
   1438 	char *str = NULL;
   1439 	size_t len = 0;
   1440 	char *p;
   1441 	unsigned i;
   1442 	int rc;
   1443 
   1444 	if (strs->num == 0) {
   1445 		goto exit;
   1446 	}
   1447 
   1448 	/* 2*strs->num - 1 because ", " follows all but last attr (followed by '\0') */
   1449 	len = strs_len_items(strs) + 2*strs->num - 1;
   1450 	str = malloc(len);
   1451 	if (!str) {
   1452 		sepol_log_err("Out of memory");
   1453 		goto exit;
   1454 	}
   1455 
   1456 	p = str;
   1457 	for (i=0; i<strs->num; i++) {
   1458 		if (!strs->list[i]) continue;
   1459 		len = strlen(strs->list[i]);
   1460 		rc = snprintf(p, len+1, "%s", strs->list[i]);
   1461 		if (rc < 0 || rc > (int)len) {
   1462 			free(str);
   1463 			str = NULL;
   1464 			goto exit;
   1465 		}
   1466 		p += len;
   1467 		if (i < strs->num - 1) {
   1468 			*p++ = ',';
   1469 			*p++ = ' ';
   1470 		}
   1471 	}
   1472 
   1473 	*p = '\0';
   1474 
   1475 exit:
   1476 	return str;
   1477 }
   1478 
   1479 static char *attrmap_to_str(struct ebitmap *map, char **val_to_name)
   1480 {
   1481 	struct strs *strs;
   1482 	char *str = NULL;
   1483 	int rc;
   1484 
   1485 	rc = strs_init(&strs, 32);
   1486 	if (rc != 0) {
   1487 		goto exit;
   1488 	}
   1489 
   1490 	rc = ebitmap_to_strs(map, strs, val_to_name);
   1491 	if (rc != 0) {
   1492 		goto exit;
   1493 	}
   1494 
   1495 	strs_sort(strs);
   1496 
   1497 	str = attr_strs_to_str(strs);
   1498 
   1499 exit:
   1500 	strs_destroy(&strs);
   1501 
   1502 	return str;
   1503 }
   1504 
   1505 static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
   1506 {
   1507 	type_datum_t *type;
   1508 	struct strs *strs;
   1509 	ebitmap_t attrmap;
   1510 	char *name, *attrs;
   1511 	unsigned i;
   1512 	int rc;
   1513 
   1514 	rc = strs_init(&strs, pdb->p_types.nprim);
   1515 	if (rc != 0) {
   1516 		goto exit;
   1517 	}
   1518 
   1519 	for (i=0; i < pdb->p_types.nprim; i++) {
   1520 		type = pdb->type_val_to_struct[i];
   1521 		if (type->flavor != TYPE_TYPE || !type->primary) continue;
   1522 		if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
   1523 
   1524 		rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
   1525 		if (rc != 0) {
   1526 			goto exit;
   1527 		}
   1528 		rc = ebitmap_set_bit(&attrmap, i, 0);
   1529 		if (rc != 0) {
   1530 			ebitmap_destroy(&attrmap);
   1531 			goto exit;
   1532 		}
   1533 		name = pdb->p_type_val_to_name[i];
   1534 		attrs = attrmap_to_str(&attrmap, pdb->p_type_val_to_name);
   1535 		ebitmap_destroy(&attrmap);
   1536 		if (!attrs) {
   1537 			rc = -1;
   1538 			goto exit;
   1539 		}
   1540 
   1541 		rc = strs_create_and_add(strs, "typeattribute %s %s;",
   1542 					 2, name, attrs);
   1543 		free(attrs);
   1544 		if (rc != 0) {
   1545 			goto exit;
   1546 		}
   1547 	}
   1548 
   1549 	strs_sort(strs);
   1550 	strs_write_each(strs, out);
   1551 
   1552 exit:
   1553 	strs_free_all(strs);
   1554 	strs_destroy(&strs);
   1555 
   1556 	if (rc != 0) {
   1557 		sepol_log_err("Error writing typeattributeset rules to policy.conf\n");
   1558 	}
   1559 
   1560 	return rc;
   1561 }
   1562 
   1563 static int write_type_permissive_rules_to_conf(FILE *out, struct policydb *pdb)
   1564 {
   1565 	type_datum_t *type;
   1566 	struct strs *strs;
   1567 	char *name;
   1568 	unsigned i, num;
   1569 	int rc = 0;
   1570 
   1571 	rc = strs_init(&strs, pdb->p_types.nprim);
   1572 	if (rc != 0) {
   1573 		goto exit;
   1574 	}
   1575 
   1576 	for (i=0; i < pdb->p_types.nprim; i++) {
   1577 		type = pdb->type_val_to_struct[i];
   1578 		if (type->flavor == TYPE_TYPE && (type->flags & TYPE_FLAGS_PERMISSIVE)) {
   1579 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
   1580 			if (rc != 0) {
   1581 				goto exit;
   1582 			}
   1583 		}
   1584 	}
   1585 
   1586 	strs_sort(strs);
   1587 
   1588 	num = strs_num_items(strs);
   1589 	for (i=0; i<num; i++) {
   1590 		name = strs_read_at_index(strs, i);
   1591 		if (!name) {
   1592 			rc = -1;
   1593 			goto exit;
   1594 		}
   1595 		sepol_printf(out, "permissive %s;\n", name);
   1596 	}
   1597 
   1598 exit:
   1599 	strs_destroy(&strs);
   1600 
   1601 	if (rc != 0) {
   1602 		sepol_log_err("Error writing typepermissive rules to policy.conf\n");
   1603 	}
   1604 
   1605 	return rc;
   1606 }
   1607 
   1608 static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum)
   1609 {
   1610 	uint32_t data = datum->data;
   1611 	type_datum_t *type;
   1612 	const char *flavor, *src, *tgt, *class, *perms, *new;
   1613 	char *rule = NULL;
   1614 
   1615 	switch (0xFFF & key->specified) {
   1616 	case AVTAB_ALLOWED:
   1617 		flavor = "allow";
   1618 		break;
   1619 	case AVTAB_AUDITALLOW:
   1620 		flavor = "auditallow";
   1621 		break;
   1622 	case AVTAB_AUDITDENY:
   1623 		flavor = "dontaudit";
   1624 		data = ~data;
   1625 		break;
   1626 	case AVTAB_XPERMS_ALLOWED:
   1627 		flavor = "allowxperm";
   1628 		break;
   1629 	case AVTAB_XPERMS_AUDITALLOW:
   1630 		flavor = "auditallowxperm";
   1631 		break;
   1632 	case AVTAB_XPERMS_DONTAUDIT:
   1633 		flavor = "dontauditxperm";
   1634 		break;
   1635 	case AVTAB_TRANSITION:
   1636 		flavor = "type_transition";
   1637 		break;
   1638 	case AVTAB_MEMBER:
   1639 		flavor = "type_member";
   1640 		break;
   1641 	case AVTAB_CHANGE:
   1642 		flavor = "type_change";
   1643 		break;
   1644 	default:
   1645 		sepol_log_err("Unknown avtab type: %i", key->specified);
   1646 		goto exit;
   1647 	}
   1648 
   1649 	src = pdb->p_type_val_to_name[key->source_type - 1];
   1650 	tgt = pdb->p_type_val_to_name[key->target_type - 1];
   1651 	if (key->source_type == key->target_type && !(key->specified & AVTAB_TYPE)) {
   1652 		type = pdb->type_val_to_struct[key->source_type - 1];
   1653 		if (type->flavor != TYPE_ATTRIB) {
   1654 			tgt = "self";
   1655 		}
   1656 	}
   1657 	class = pdb->p_class_val_to_name[key->target_class - 1];
   1658 
   1659 	if (key->specified & AVTAB_AV) {
   1660 		perms = sepol_av_to_string(pdb, key->target_class, data);
   1661 		if (perms == NULL) {
   1662 			sepol_log_err("Failed to generate permission string");
   1663 			goto exit;
   1664 		}
   1665 		rule = create_str("%s %s %s:%s { %s };", 5,
   1666 				  flavor, src, tgt, class, perms+1);
   1667 	} else if (key->specified & AVTAB_XPERMS) {
   1668 		perms = sepol_extended_perms_to_string(datum->xperms);
   1669 		if (perms == NULL) {
   1670 			sepol_log_err("Failed to generate extended permission string");
   1671 			goto exit;
   1672 		}
   1673 
   1674 		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms);
   1675 	} else {
   1676 		new = pdb->p_type_val_to_name[data - 1];
   1677 
   1678 		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, new);
   1679 	}
   1680 
   1681 	if (!rule) {
   1682 		goto exit;
   1683 	}
   1684 
   1685 	return rule;
   1686 
   1687 exit:
   1688 	return NULL;
   1689 }
   1690 
   1691 struct map_avtab_args {
   1692 	struct policydb *pdb;
   1693 	uint32_t flavor;
   1694 	struct strs *strs;
   1695 };
   1696 
   1697 static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void *args)
   1698 {
   1699 	struct map_avtab_args *map_args = args;
   1700 	uint32_t flavor = map_args->flavor;
   1701 	struct policydb *pdb = map_args->pdb;
   1702 	struct strs *strs = map_args->strs;
   1703 	char *rule;
   1704 	int rc = 0;
   1705 
   1706 	if (key->specified & flavor) {
   1707 		rule = avtab_node_to_str(pdb, key, datum);
   1708 		if (!rule) {
   1709 			rc = -1;
   1710 			goto exit;
   1711 		}
   1712 		rc = strs_add(strs, rule);
   1713 		if (rc != 0) {
   1714 			free(rule);
   1715 			goto exit;
   1716 		}
   1717 	}
   1718 
   1719 exit:
   1720 	return rc;
   1721 }
   1722 
   1723 static int write_avtab_flavor_to_conf(FILE *out, struct policydb *pdb, uint32_t flavor, int indent)
   1724 {
   1725 	struct map_avtab_args args;
   1726 	struct strs *strs;
   1727 	int rc = 0;
   1728 
   1729 	rc = strs_init(&strs, 1000);
   1730 	if (rc != 0) {
   1731 		goto exit;
   1732 	}
   1733 
   1734 	args.pdb = pdb;
   1735 	args.flavor = flavor;
   1736 	args.strs = strs;
   1737 
   1738 	rc = avtab_map(&pdb->te_avtab, map_avtab_write_helper, &args);
   1739 	if (rc != 0) {
   1740 		goto exit;
   1741 	}
   1742 
   1743 	strs_sort(strs);
   1744 	strs_write_each_indented(strs, out, indent);
   1745 
   1746 exit:
   1747 	strs_free_all(strs);
   1748 	strs_destroy(&strs);
   1749 
   1750 	return rc;
   1751 }
   1752 
   1753 static int write_avtab_to_conf(FILE *out, struct policydb *pdb, int indent)
   1754 {
   1755 	unsigned i;
   1756 	int rc = 0;
   1757 
   1758 	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
   1759 		rc = write_avtab_flavor_to_conf(out, pdb, avtab_flavors[i], indent);
   1760 		if (rc != 0) {
   1761 			goto exit;
   1762 		}
   1763 	}
   1764 
   1765 exit:
   1766 	if (rc != 0) {
   1767 		sepol_log_err("Error writing avtab rules to policy.conf\n");
   1768 	}
   1769 
   1770 	return rc;
   1771 }
   1772 
   1773 struct map_filename_trans_args {
   1774 	struct policydb *pdb;
   1775 	struct strs *strs;
   1776 };
   1777 
   1778 static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
   1779 {
   1780 	filename_trans_t *ft = (filename_trans_t *)key;
   1781 	filename_trans_datum_t *datum = data;
   1782 	struct map_filename_trans_args *map_args = arg;
   1783 	struct policydb *pdb = map_args->pdb;
   1784 	struct strs *strs = map_args->strs;
   1785 	char *src, *tgt, *class, *filename, *new;
   1786 
   1787 	src = pdb->p_type_val_to_name[ft->stype - 1];
   1788 	tgt = pdb->p_type_val_to_name[ft->ttype - 1];
   1789 	class = pdb->p_class_val_to_name[ft->tclass - 1];
   1790 	filename = ft->name;
   1791 	new =  pdb->p_type_val_to_name[datum->otype - 1];
   1792 
   1793 	return strs_create_and_add(strs, "type_transition %s %s:%s %s \"%s\";", 5,
   1794 				   src, tgt, class, new, filename);
   1795 }
   1796 
   1797 static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
   1798 {
   1799 	struct map_filename_trans_args args;
   1800 	struct strs *strs;
   1801 	int rc = 0;
   1802 
   1803 	rc = strs_init(&strs, 100);
   1804 	if (rc != 0) {
   1805 		goto exit;
   1806 	}
   1807 
   1808 	args.pdb = pdb;
   1809 	args.strs = strs;
   1810 
   1811 	rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
   1812 	if (rc != 0) {
   1813 		goto exit;
   1814 	}
   1815 
   1816 	strs_sort(strs);
   1817 	strs_write_each(strs, out);
   1818 
   1819 exit:
   1820 	strs_free_all(strs);
   1821 	strs_destroy(&strs);
   1822 
   1823 	if (rc != 0) {
   1824 		sepol_log_err("Error writing filename typetransition rules to policy.conf\n");
   1825 	}
   1826 
   1827 	return rc;
   1828 }
   1829 
   1830 static char *level_to_str(struct policydb *pdb, struct mls_level *level)
   1831 {
   1832 	ebitmap_t *cats = &level->cat;
   1833 	char *level_str = NULL;
   1834 	char *sens_str = pdb->p_sens_val_to_name[level->sens - 1];
   1835 	char *cats_str;
   1836 
   1837 	if (ebitmap_cardinality(cats) > 0) {
   1838 		cats_str = cats_ebitmap_to_str(cats, pdb->p_cat_val_to_name);
   1839 		level_str = create_str("%s:%s", 2, sens_str, cats_str);
   1840 		free(cats_str);
   1841 	} else {
   1842 		level_str = create_str("%s", 1, sens_str);
   1843 	}
   1844 
   1845 	return level_str;
   1846 }
   1847 
   1848 static char *range_to_str(struct policydb *pdb, mls_range_t *range)
   1849 {
   1850 	char *low = NULL;
   1851 	char *high = NULL;
   1852 	char *range_str = NULL;
   1853 
   1854 	low = level_to_str(pdb, &range->level[0]);
   1855 	if (!low) {
   1856 		goto exit;
   1857 	}
   1858 
   1859 	high = level_to_str(pdb, &range->level[1]);
   1860 	if (!high) {
   1861 		goto exit;
   1862 	}
   1863 
   1864 	range_str = create_str("%s - %s", 2, low, high);
   1865 
   1866 exit:
   1867 	free(low);
   1868 	free(high);
   1869 
   1870 	return range_str;
   1871 }
   1872 
   1873 struct map_range_trans_args {
   1874 	struct policydb *pdb;
   1875 	struct strs *strs;
   1876 };
   1877 
   1878 static int map_range_trans_to_str(hashtab_key_t key, void *data, void *arg)
   1879 {
   1880 	range_trans_t *rt = (range_trans_t *)key;
   1881 	mls_range_t *mls_range = data;
   1882 	struct map_range_trans_args *map_args = arg;
   1883 	struct policydb *pdb = map_args->pdb;
   1884 	struct strs *strs = map_args->strs;
   1885 	char *src, *tgt, *class, *range;
   1886 	int rc;
   1887 
   1888 	src = pdb->p_type_val_to_name[rt->source_type - 1];
   1889 	tgt = pdb->p_type_val_to_name[rt->target_type - 1];
   1890 	class = pdb->p_class_val_to_name[rt->target_class - 1];
   1891 	range = range_to_str(pdb, mls_range);
   1892 	if (!range) {
   1893 		rc = -1;
   1894 		goto exit;
   1895 	}
   1896 
   1897 	rc = strs_create_and_add(strs, "range_transition %s %s:%s %s;", 4,
   1898 				 src, tgt, class, range);
   1899 	free(range);
   1900 	if (rc != 0) {
   1901 		goto exit;
   1902 	}
   1903 
   1904 exit:
   1905 	return rc;
   1906 }
   1907 
   1908 static int write_range_trans_rules_to_conf(FILE *out, struct policydb *pdb)
   1909 {
   1910 	struct map_range_trans_args args;
   1911 	struct strs *strs;
   1912 	int rc = 0;
   1913 
   1914 	rc = strs_init(&strs, 100);
   1915 	if (rc != 0) {
   1916 		goto exit;
   1917 	}
   1918 
   1919 	args.pdb = pdb;
   1920 	args.strs = strs;
   1921 
   1922 	rc = hashtab_map(pdb->range_tr, map_range_trans_to_str, &args);
   1923 	if (rc != 0) {
   1924 		goto exit;
   1925 	}
   1926 
   1927 	strs_sort(strs);
   1928 	strs_write_each(strs, out);
   1929 
   1930 exit:
   1931 	strs_free_all(strs);
   1932 	strs_destroy(&strs);
   1933 
   1934 	if (rc != 0) {
   1935 		sepol_log_err("Error writing range transition rules to policy.conf\n");
   1936 	}
   1937 
   1938 	return rc;
   1939 }
   1940 
   1941 static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_list_t *cond_list, int indent)
   1942 {
   1943 	cond_av_list_t *cond_av;
   1944 	avtab_ptr_t node;
   1945 	uint32_t flavor;
   1946 	avtab_key_t *key;
   1947 	avtab_datum_t *datum;
   1948 	struct strs *strs;
   1949 	char *rule;
   1950 	unsigned i;
   1951 	int rc;
   1952 
   1953 	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
   1954 		flavor = avtab_flavors[i];
   1955 		rc = strs_init(&strs, 64);
   1956 		if (rc != 0) {
   1957 			goto exit;
   1958 		}
   1959 
   1960 		for (cond_av = cond_list; cond_av != NULL; cond_av = cond_av->next) {
   1961 			node = cond_av->node;
   1962 			key = &node->key;
   1963 			datum = &node->datum;
   1964 			if (key->specified & flavor) {
   1965 				rule = avtab_node_to_str(pdb, key, datum);
   1966 				if (!rule) {
   1967 					rc = -1;
   1968 					goto exit;
   1969 				}
   1970 				rc = strs_add(strs, rule);
   1971 				if (rc != 0) {
   1972 					free(rule);
   1973 					goto exit;
   1974 				}
   1975 			}
   1976 		}
   1977 
   1978 		strs_sort(strs);
   1979 		strs_write_each_indented(strs, out, indent);
   1980 		strs_free_all(strs);
   1981 		strs_destroy(&strs);
   1982 	}
   1983 
   1984 	return 0;
   1985 
   1986 exit:
   1987 	return rc;
   1988 }
   1989 
   1990 struct cond_data {
   1991 	char *expr;
   1992 	struct cond_node *cond;
   1993 };
   1994 
   1995 static int cond_node_cmp(const void *a, const void *b)
   1996 {
   1997 	const struct cond_data *aa = a;
   1998 	const struct cond_data *bb = b;
   1999 	return strcmp(aa->expr, bb->expr);
   2000 }
   2001 
   2002 static int write_cond_nodes_to_conf(FILE *out, struct policydb *pdb)
   2003 {
   2004 	struct cond_data *cond_data;
   2005 	char *expr;
   2006 	struct cond_node *cond;
   2007 	unsigned i, num;
   2008 	int rc = 0;
   2009 
   2010 	num = 0;
   2011 	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
   2012 		num++;
   2013 	}
   2014 
   2015 	if (num == 0) {
   2016 		return 0;
   2017 	}
   2018 
   2019 	cond_data = calloc(sizeof(struct cond_data), num);
   2020 	if (!cond_data) {
   2021 		rc = -1;
   2022 		goto exit;
   2023 	}
   2024 
   2025 	i = 0;
   2026 	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
   2027 		cond_data[i].cond = cond;
   2028 		expr = cond_expr_to_str(pdb, cond->expr);
   2029 		if (!expr) {
   2030 			num = i;
   2031 			goto exit;
   2032 		}
   2033 		cond_data[i].expr = expr;
   2034 		i++;
   2035 	}
   2036 
   2037 	qsort(cond_data, num, sizeof(*cond_data), cond_node_cmp);
   2038 
   2039 	for (i=0; i<num; i++) {
   2040 		expr = cond_data[i].expr;
   2041 		cond = cond_data[i].cond;
   2042 
   2043 		sepol_printf(out, "if (%s) {\n", expr);
   2044 
   2045 		if (cond->true_list != NULL) {
   2046 			rc = write_cond_av_list_to_conf(out, pdb, cond->true_list, 1);
   2047 			if (rc != 0) {
   2048 				goto exit;
   2049 			}
   2050 		}
   2051 
   2052 		if (cond->false_list != NULL) {
   2053 			sepol_printf(out, "} else {\n");
   2054 			rc = write_cond_av_list_to_conf(out, pdb, cond->false_list, 1);
   2055 			if (rc != 0) {
   2056 				goto exit;
   2057 			}
   2058 		}
   2059 		sepol_printf(out, "}\n");
   2060 	}
   2061 
   2062 exit:
   2063 	if (cond_data) {
   2064 		for (i=0; i<num; i++) {
   2065 			free(cond_data[i].expr);
   2066 		}
   2067 		free(cond_data);
   2068 	}
   2069 
   2070 	if (rc != 0) {
   2071 		sepol_log_err("Error writing conditional rules to policy.conf\n");
   2072 	}
   2073 
   2074 	return rc;
   2075 }
   2076 
   2077 static int write_role_decl_rules_to_conf(FILE *out, struct policydb *pdb)
   2078 {
   2079 	struct role_datum *role;
   2080 	struct strs *strs;
   2081 	char *name, *types, *p1, *p2;
   2082 	unsigned i, num;
   2083 	int rc = 0;
   2084 
   2085 	rc = strs_init(&strs, pdb->p_roles.nprim);
   2086 	if (rc != 0) {
   2087 		goto exit;
   2088 	}
   2089 
   2090 	/* Start at 1 to skip object_r */
   2091 	for (i=1; i < pdb->p_roles.nprim; i++) {
   2092 		role = pdb->role_val_to_struct[i];
   2093 		if (role && role->flavor == ROLE_ROLE) {
   2094 			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
   2095 			if (rc != 0) {
   2096 				goto exit;
   2097 			}
   2098 		}
   2099 	}
   2100 
   2101 	strs_sort(strs);
   2102 
   2103 	num = strs_num_items(strs);
   2104 
   2105 	for (i=0; i<num; i++) {
   2106 		name = strs_read_at_index(strs, i);
   2107 		if (!name) {
   2108 			continue;
   2109 		}
   2110 		sepol_printf(out, "role %s;\n", name);
   2111 	}
   2112 
   2113 	for (i=0; i<num; i++) {
   2114 		name = strs_read_at_index(strs, i);
   2115 		if (!name) continue;
   2116 		role = hashtab_search(pdb->p_roles.table, name);
   2117 		if (!role) {
   2118 			rc = -1;
   2119 			goto exit;
   2120 		}
   2121 		if (ebitmap_cardinality(&role->types.types) == 0) continue;
   2122 		types = ebitmap_to_str(&role->types.types, pdb->p_type_val_to_name, 1);
   2123 		if (!types) {
   2124 			rc = -1;
   2125 			goto exit;
   2126 		}
   2127 		if (strlen(types) > 900) {
   2128 			p1 = types;
   2129 			while (p1) {
   2130 				p2 = p1;
   2131 				while (p2 - p1 < 600) {
   2132 					p2 = strchr(p2, ' ');
   2133 					if (!p2)
   2134 						break;
   2135 					p2++;
   2136 				}
   2137 				if (p2) {
   2138 					*(p2-1) = '\0';
   2139 				}
   2140 				sepol_printf(out, "role %s types { %s };\n", name, p1);
   2141 				p1 = p2;
   2142 			}
   2143 		} else {
   2144 			sepol_printf(out, "role %s types { %s };\n", name, types);
   2145 		}
   2146 		free(types);
   2147 	}
   2148 
   2149 exit:
   2150 	strs_destroy(&strs);
   2151 
   2152 	if (rc != 0) {
   2153 		sepol_log_err("Error writing role declarations to policy.conf\n");
   2154 	}
   2155 
   2156 	return rc;
   2157 }
   2158 
   2159 static int write_role_transition_rules_to_conf(FILE *out, struct policydb *pdb)
   2160 {
   2161 	role_trans_t *curr = pdb->role_tr;
   2162 	struct strs *strs;
   2163 	char *role, *type, *class, *new;
   2164 	int rc = 0;
   2165 
   2166 	rc = strs_init(&strs, 32);
   2167 	if (rc != 0) {
   2168 		goto exit;
   2169 	}
   2170 
   2171 	while (curr) {
   2172 		role = pdb->p_role_val_to_name[curr->role - 1];
   2173 		type = pdb->p_type_val_to_name[curr->type - 1];
   2174 		class = pdb->p_class_val_to_name[curr->tclass - 1];
   2175 		new = pdb->p_role_val_to_name[curr->new_role - 1];
   2176 
   2177 		rc = strs_create_and_add(strs, "role_transition %s %s:%s %s;", 4,
   2178 					 role, type, class, new);
   2179 		if (rc != 0) {
   2180 			goto exit;
   2181 		}
   2182 
   2183 		curr = curr->next;
   2184 	}
   2185 
   2186 	strs_sort(strs);
   2187 	strs_write_each(strs, out);
   2188 
   2189 exit:
   2190 	strs_free_all(strs);
   2191 	strs_destroy(&strs);
   2192 
   2193 	if (rc != 0) {
   2194 		sepol_log_err("Error writing role transition rules to policy.conf\n");
   2195 	}
   2196 
   2197 	return rc;
   2198 }
   2199 
   2200 static int write_role_allow_rules_to_conf(FILE *out, struct policydb *pdb)
   2201 {
   2202 	role_allow_t *curr = pdb->role_allow;
   2203 	struct strs *strs;
   2204 	char *role, *new;
   2205 	int rc = 0;
   2206 
   2207 	rc = strs_init(&strs, 32);
   2208 	if (rc != 0) {
   2209 		goto exit;
   2210 	}
   2211 
   2212 	while (curr) {
   2213 		role = pdb->p_role_val_to_name[curr->role - 1];
   2214 		new =  pdb->p_role_val_to_name[curr->new_role - 1];
   2215 
   2216 		rc = strs_create_and_add(strs, "allow %s %s;", 2, role, new);
   2217 		if (rc != 0) {
   2218 			goto exit;
   2219 		}
   2220 
   2221 		curr = curr->next;
   2222 	}
   2223 
   2224 	strs_sort(strs);
   2225 	strs_write_each(strs, out);
   2226 
   2227 exit:
   2228 	strs_free_all(strs);
   2229 	strs_destroy(&strs);
   2230 
   2231 	if (rc != 0) {
   2232 		sepol_log_err("Error writing role allow rules to policy.conf\n");
   2233 	}
   2234 
   2235 	return rc;
   2236 }
   2237 
   2238 static int write_user_decl_rules_to_conf(FILE *out, struct policydb *pdb)
   2239 {
   2240 	struct user_datum *user;
   2241 	struct strs *strs;
   2242 	char *name, *roles, *level, *range;
   2243 	unsigned i, num;
   2244 	int rc = 0;
   2245 
   2246 	rc = strs_init(&strs, pdb->p_users.nprim);
   2247 	if (rc != 0) {
   2248 		goto exit;
   2249 	}
   2250 
   2251 	for (i=0; i < pdb->p_users.nprim; i++) {
   2252 		rc = strs_add(strs, pdb->p_user_val_to_name[i]);
   2253 		if (rc != 0) {
   2254 			goto exit;
   2255 		}
   2256 	}
   2257 
   2258 	strs_sort(strs);
   2259 
   2260 	num = strs_num_items(strs);
   2261 
   2262 	for (i=0; i<num; i++) {
   2263 		name = strs_read_at_index(strs, i);
   2264 		if (!name) {
   2265 			continue;
   2266 		}
   2267 		user = hashtab_search(pdb->p_users.table, name);
   2268 		if (!user) {
   2269 			rc = -1;
   2270 			goto exit;
   2271 		}
   2272 		sepol_printf(out, "user %s", name);
   2273 
   2274 		if (ebitmap_cardinality(&user->roles.roles) > 0) {
   2275 			roles = ebitmap_to_str(&user->roles.roles,
   2276 					       pdb->p_role_val_to_name, 1);
   2277 			if (!roles) {
   2278 				rc = -1;
   2279 				goto exit;
   2280 			}
   2281 			if (strchr(roles, ' ')) {
   2282 				sepol_printf(out, " roles { %s }", roles);
   2283 			} else {
   2284 				sepol_printf(out, " roles %s", roles);
   2285 			}
   2286 			free(roles);
   2287 		}
   2288 
   2289 		if (pdb->mls) {
   2290 			level = level_to_str(pdb, &user->exp_dfltlevel);
   2291 			if (!level) {
   2292 				rc = -1;
   2293 				goto exit;
   2294 			}
   2295 			sepol_printf(out, " level %s", level);
   2296 			free(level);
   2297 
   2298 			range = range_to_str(pdb, &user->exp_range);
   2299 			if (!range) {
   2300 				rc = -1;
   2301 				goto exit;
   2302 			}
   2303 			sepol_printf(out, " range %s", range);
   2304 			free(range);
   2305 		}
   2306 		sepol_printf(out, ";\n");
   2307 	}
   2308 
   2309 	strs_destroy(&strs);
   2310 
   2311 exit:
   2312 	if (rc != 0) {
   2313 		sepol_log_err("Error writing user declarations to policy.conf\n");
   2314 	}
   2315 
   2316 	return rc;
   2317 }
   2318 
   2319 static char *context_to_str(struct policydb *pdb, struct context_struct *con)
   2320 {
   2321 	char *user, *role, *type, *range;
   2322 	char *ctx = NULL;
   2323 
   2324 	user = pdb->p_user_val_to_name[con->user - 1];
   2325 	role = pdb->p_role_val_to_name[con->role - 1];
   2326 	type = pdb->p_type_val_to_name[con->type - 1];
   2327 
   2328 	if (pdb->mls) {
   2329 		range = range_to_str(pdb, &con->range);
   2330 		ctx = create_str("%s:%s:%s:%s", 4, user, role, type, range);
   2331 		free(range);
   2332 	} else {
   2333 		ctx = create_str("%s:%s:%s", 3, user, role, type);
   2334 	}
   2335 
   2336 	return ctx;
   2337 }
   2338 
   2339 static int write_sid_context_rules_to_conf(FILE *out, struct policydb *pdb, const char *const *sid_to_str)
   2340 {
   2341 	struct ocontext *isid;
   2342 	struct strs *strs;
   2343 	const char *sid;
   2344 	char *ctx, *rule;
   2345 	unsigned i;
   2346 	int rc;
   2347 
   2348 	rc = strs_init(&strs, 32);
   2349 	if (rc != 0) {
   2350 		goto exit;
   2351 	}
   2352 
   2353 	for (isid = pdb->ocontexts[0]; isid != NULL; isid = isid->next) {
   2354 		i = isid->sid[0];
   2355 		sid = sid_to_str[i];
   2356 		ctx = context_to_str(pdb, &isid->context[0]);
   2357 		if (!ctx) {
   2358 			rc = -1;
   2359 			goto exit;
   2360 		}
   2361 
   2362 		rule = create_str("sid %s %s", 2, sid, ctx);
   2363 		free(ctx);
   2364 		if (!rule) {
   2365 			rc = -1;
   2366 			goto exit;
   2367 		}
   2368 
   2369 		rc = strs_add_at_index(strs, rule, i);
   2370 		if (rc != 0) {
   2371 			free(rule);
   2372 			goto exit;
   2373 		}
   2374 	}
   2375 
   2376 	strs_write_each(strs, out);
   2377 
   2378 exit:
   2379 	strs_free_all(strs);
   2380 	strs_destroy(&strs);
   2381 
   2382 	if (rc != 0) {
   2383 		sepol_log_err("Error writing sidcontext rules to policy.conf\n");
   2384 	}
   2385 
   2386 	return rc;
   2387 }
   2388 
   2389 static int write_selinux_isid_rules_to_conf(FILE *out, struct policydb *pdb)
   2390 {
   2391 	return write_sid_context_rules_to_conf(out, pdb, selinux_sid_to_str);
   2392 }
   2393 
   2394 static int write_selinux_fsuse_rules_to_conf(FILE *out, struct policydb *pdb)
   2395 {
   2396 	struct ocontext *fsuse;
   2397 	const char *behavior;
   2398 	char *name, *ctx;
   2399 	int rc = 0;
   2400 
   2401 	for (fsuse = pdb->ocontexts[5]; fsuse != NULL; fsuse = fsuse->next) {
   2402 		switch (fsuse->v.behavior) {
   2403 		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
   2404 		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
   2405 		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
   2406 		default:
   2407 			sepol_log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
   2408 			rc = -1;
   2409 			goto exit;
   2410 		}
   2411 
   2412 		name = fsuse->u.name;
   2413 		ctx = context_to_str(pdb, &fsuse->context[0]);
   2414 		if (!ctx) {
   2415 			rc = -1;
   2416 			goto exit;
   2417 		}
   2418 
   2419 		sepol_printf(out, "fs_use_%s %s %s;\n", behavior, name, ctx);
   2420 
   2421 		free(ctx);
   2422 	}
   2423 
   2424 exit:
   2425 	if (rc != 0) {
   2426 		sepol_log_err("Error writing fsuse rules to policy.conf\n");
   2427 	}
   2428 
   2429 	return rc;
   2430 }
   2431 
   2432 static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb)
   2433 {
   2434 	struct genfs *genfs;
   2435 	struct ocontext *ocon;
   2436 	struct strs *strs;
   2437 	char *fstype, *name, *ctx;
   2438 	int rc;
   2439 
   2440 	rc = strs_init(&strs, 32);
   2441 	if (rc != 0) {
   2442 		goto exit;
   2443 	}
   2444 
   2445 	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
   2446 		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
   2447 			fstype = genfs->fstype;
   2448 			name = ocon->u.name;
   2449 
   2450 			ctx = context_to_str(pdb, &ocon->context[0]);
   2451 			if (!ctx) {
   2452 				rc = -1;
   2453 				goto exit;
   2454 			}
   2455 
   2456 			rc = strs_create_and_add(strs, "genfscon %s %s %s", 3,
   2457 						 fstype, name, ctx);
   2458 			free(ctx);
   2459 			if (rc != 0) {
   2460 				goto exit;
   2461 			}
   2462 		}
   2463 	}
   2464 
   2465 	strs_sort(strs);
   2466 	strs_write_each(strs, out);
   2467 
   2468 exit:
   2469 	strs_free_all(strs);
   2470 	strs_destroy(&strs);
   2471 
   2472 	if (rc != 0) {
   2473 		sepol_log_err("Error writing genfscon rules to policy.conf\n");
   2474 	}
   2475 
   2476 	return rc;
   2477 }
   2478 
   2479 static int write_selinux_port_rules_to_conf(FILE *out, struct policydb *pdb)
   2480 {
   2481 	struct ocontext *portcon;
   2482 	const char *protocol;
   2483 	uint16_t low;
   2484 	uint16_t high;
   2485 	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
   2486 	char *ctx;
   2487 	int rc = 0;
   2488 
   2489 	for (portcon = pdb->ocontexts[2]; portcon != NULL; portcon = portcon->next) {
   2490 		switch (portcon->u.port.protocol) {
   2491 		case IPPROTO_TCP: protocol = "tcp"; break;
   2492 		case IPPROTO_UDP: protocol = "udp"; break;
   2493 		case IPPROTO_DCCP: protocol = "dccp"; break;
   2494 		default:
   2495 			sepol_log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
   2496 			rc = -1;
   2497 			goto exit;
   2498 		}
   2499 
   2500 		low = portcon->u.port.low_port;
   2501 		high = portcon->u.port.high_port;
   2502 		if (low == high) {
   2503 			rc = snprintf(low_high_str, 44, "%u", low);
   2504 		} else {
   2505 			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
   2506 		}
   2507 		if (rc < 0 || rc >= 44) {
   2508 			rc = -1;
   2509 			goto exit;
   2510 		}
   2511 
   2512 		ctx = context_to_str(pdb, &portcon->context[0]);
   2513 		if (!ctx) {
   2514 			rc = -1;
   2515 			goto exit;
   2516 		}
   2517 
   2518 		sepol_printf(out, "portcon %s %s %s\n", protocol, low_high_str, ctx);
   2519 
   2520 		free(ctx);
   2521 	}
   2522 
   2523 	rc = 0;
   2524 
   2525 exit:
   2526 	if (rc != 0) {
   2527 		sepol_log_err("Error writing portcon rules to policy.conf\n");
   2528 	}
   2529 
   2530 	return rc;
   2531 }
   2532 
   2533 static int write_selinux_netif_rules_to_conf(FILE *out, struct policydb *pdb)
   2534 {
   2535 	struct ocontext *netif;
   2536 	char *name, *ctx1, *ctx2;
   2537 	int rc = 0;
   2538 
   2539 	for (netif = pdb->ocontexts[3]; netif != NULL; netif = netif->next) {
   2540 		name = netif->u.name;
   2541 		ctx1 = context_to_str(pdb, &netif->context[0]);
   2542 		if (!ctx1) {
   2543 			rc = -1;
   2544 			goto exit;
   2545 		}
   2546 		ctx2 = context_to_str(pdb, &netif->context[1]);
   2547 		if (!ctx2) {
   2548 			free(ctx1);
   2549 			rc = -1;
   2550 			goto exit;
   2551 		}
   2552 
   2553 		sepol_printf(out, "netifcon %s %s %s\n", name, ctx1, ctx2);
   2554 
   2555 		free(ctx1);
   2556 		free(ctx2);
   2557 	}
   2558 
   2559 exit:
   2560 	if (rc != 0) {
   2561 		sepol_log_err("Error writing netifcon rules to policy.conf\n");
   2562 	}
   2563 
   2564 	return rc;
   2565 }
   2566 
   2567 static int write_selinux_node_rules_to_conf(FILE *out, struct policydb *pdb)
   2568 {
   2569 	struct ocontext *node;
   2570 	char addr[INET_ADDRSTRLEN];
   2571 	char mask[INET_ADDRSTRLEN];
   2572 	char *ctx;
   2573 	int rc = 0;
   2574 
   2575 	for (node = pdb->ocontexts[4]; node != NULL; node = node->next) {
   2576 		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
   2577 			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
   2578 			rc = -1;
   2579 			goto exit;
   2580 		}
   2581 
   2582 		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
   2583 			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
   2584 			rc = -1;
   2585 			goto exit;
   2586 		}
   2587 
   2588 		ctx = context_to_str(pdb, &node->context[0]);
   2589 		if (!ctx) {
   2590 			rc = -1;
   2591 			goto exit;
   2592 		}
   2593 
   2594 		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
   2595 
   2596 		free(ctx);
   2597 	}
   2598 
   2599 exit:
   2600 	if (rc != 0) {
   2601 		sepol_log_err("Error writing nodecon rules to policy.conf\n");
   2602 	}
   2603 
   2604 	return rc;
   2605 }
   2606 
   2607 
   2608 static int write_selinux_node6_rules_to_conf(FILE *out, struct policydb *pdb)
   2609 {
   2610 	struct ocontext *node6;
   2611 	char addr[INET6_ADDRSTRLEN];
   2612 	char mask[INET6_ADDRSTRLEN];
   2613 	char *ctx;
   2614 	int rc = 0;
   2615 
   2616 	for (node6 = pdb->ocontexts[6]; node6 != NULL; node6 = node6->next) {
   2617 		if (inet_ntop(AF_INET6, &node6->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
   2618 			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
   2619 			rc = -1;
   2620 			goto exit;
   2621 		}
   2622 
   2623 		if (inet_ntop(AF_INET6, &node6->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
   2624 			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
   2625 			rc = -1;
   2626 			goto exit;
   2627 		}
   2628 
   2629 		ctx = context_to_str(pdb, &node6->context[0]);
   2630 		if (!ctx) {
   2631 			rc = -1;
   2632 			goto exit;
   2633 		}
   2634 
   2635 		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
   2636 
   2637 		free(ctx);
   2638 	}
   2639 
   2640 exit:
   2641 	if (rc != 0) {
   2642 		sepol_log_err("Error writing nodecon rules to policy.conf\n");
   2643 	}
   2644 
   2645 	return rc;
   2646 }
   2647 
   2648 static int write_selinux_ibpkey_rules_to_conf(FILE *out, struct policydb *pdb)
   2649 {
   2650 	struct ocontext *ibpkeycon;
   2651 	char subnet_prefix_str[INET6_ADDRSTRLEN];
   2652 	struct in6_addr subnet_prefix = IN6ADDR_ANY_INIT;
   2653 	uint16_t low;
   2654 	uint16_t high;
   2655 	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
   2656 	char *ctx;
   2657 	int rc = 0;
   2658 
   2659 	for (ibpkeycon = pdb->ocontexts[OCON_IBPKEY]; ibpkeycon != NULL;
   2660 	     ibpkeycon = ibpkeycon->next) {
   2661 		memcpy(&subnet_prefix.s6_addr, &ibpkeycon->u.ibpkey.subnet_prefix,
   2662 		       sizeof(ibpkeycon->u.ibpkey.subnet_prefix));
   2663 
   2664 		if (inet_ntop(AF_INET6, &subnet_prefix.s6_addr,
   2665 			      subnet_prefix_str, INET6_ADDRSTRLEN) == NULL) {
   2666 			sepol_log_err("ibpkeycon address is invalid: %s",
   2667 				      strerror(errno));
   2668 			rc = -1;
   2669 			goto exit;
   2670 		}
   2671 
   2672 		low = ibpkeycon->u.ibpkey.low_pkey;
   2673 		high = ibpkeycon->u.ibpkey.high_pkey;
   2674 		if (low == high) {
   2675 			rc = snprintf(low_high_str, 44, "%u", low);
   2676 		} else {
   2677 			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
   2678 		}
   2679 		if (rc < 0 || rc >= 44) {
   2680 			rc = -1;
   2681 			goto exit;
   2682 		}
   2683 
   2684 		ctx = context_to_str(pdb, &ibpkeycon->context[0]);
   2685 		if (!ctx) {
   2686 			rc = -1;
   2687 			goto exit;
   2688 		}
   2689 
   2690 		sepol_printf(out, "ibpkeycon %s %s %s\n", subnet_prefix_str,
   2691 			     low_high_str, ctx);
   2692 
   2693 		free(ctx);
   2694 	}
   2695 
   2696 	rc = 0;
   2697 
   2698 exit:
   2699 	if (rc != 0) {
   2700 		sepol_log_err("Error writing ibpkeycon rules to policy.conf\n");
   2701 	}
   2702 
   2703 	return rc;
   2704 }
   2705 
   2706 static int write_selinux_ibendport_rules_to_conf(FILE *out, struct policydb *pdb)
   2707 {
   2708 	struct ocontext *ibendportcon;
   2709 	char port_str[4];
   2710 	char *ctx;
   2711 	int rc = 0;
   2712 
   2713 	for (ibendportcon = pdb->ocontexts[OCON_IBENDPORT];
   2714 	     ibendportcon != NULL; ibendportcon = ibendportcon->next) {
   2715 		rc = snprintf(port_str, 4, "%u", ibendportcon->u.ibendport.port);
   2716 		if (rc < 0 || rc >= 4) {
   2717 			rc = -1;
   2718 			goto exit;
   2719 		}
   2720 
   2721 		ctx = context_to_str(pdb, &ibendportcon->context[0]);
   2722 		if (!ctx) {
   2723 			rc = -1;
   2724 			goto exit;
   2725 		}
   2726 
   2727 		sepol_printf(out, "ibendportcon %s %s %s\n", ibendportcon->u.ibendport.dev_name, port_str, ctx);
   2728 
   2729 		free(ctx);
   2730 	}
   2731 
   2732 	rc = 0;
   2733 
   2734 exit:
   2735 	if (rc != 0) {
   2736 		sepol_log_err("Error writing ibendportcon rules to policy.conf\n");
   2737 	}
   2738 
   2739 	return rc;
   2740 }
   2741 
   2742 static int write_xen_isid_rules_to_conf(FILE *out, struct policydb *pdb)
   2743 {
   2744 	return write_sid_context_rules_to_conf(out, pdb, xen_sid_to_str);
   2745 }
   2746 
   2747 
   2748 static int write_xen_pirq_rules_to_conf(FILE *out, struct policydb *pdb)
   2749 {
   2750 	struct ocontext *pirq;
   2751 	char pirq_str[21]; /* 2^64-1 <= 20 digits */
   2752 	char *ctx;
   2753 	int rc = 0;
   2754 
   2755 	for (pirq = pdb->ocontexts[1]; pirq != NULL; pirq = pirq->next) {
   2756 		rc = snprintf(pirq_str, 21, "%i", pirq->u.pirq);
   2757 		if (rc < 0 || rc >= 21) {
   2758 			fprintf(stderr,"error1\n");
   2759 			rc = -1;
   2760 			goto exit;
   2761 		}
   2762 
   2763 		ctx = context_to_str(pdb, &pirq->context[0]);
   2764 		if (!ctx) {
   2765 			rc = -1;
   2766 			fprintf(stderr,"error2\n");
   2767 			goto exit;
   2768 		}
   2769 
   2770 		sepol_printf(out, "pirqcon %s %s\n", pirq_str, ctx);
   2771 
   2772 		free(ctx);
   2773 	}
   2774 
   2775 	rc = 0;
   2776 
   2777 exit:
   2778 	if (rc != 0) {
   2779 		sepol_log_err("Error writing pirqcon rules to policy.conf\n");
   2780 	}
   2781 
   2782 	return rc;
   2783 }
   2784 
   2785 static int write_xen_ioport_rules_to_conf(FILE *out, struct policydb *pdb)
   2786 {
   2787 	struct ocontext *ioport;
   2788 	uint32_t low;
   2789 	uint32_t high;
   2790 	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
   2791 	char *ctx;
   2792 	int rc = 0;
   2793 
   2794 	for (ioport = pdb->ocontexts[2]; ioport != NULL; ioport = ioport->next) {
   2795 		low = ioport->u.ioport.low_ioport;
   2796 		high = ioport->u.ioport.high_ioport;
   2797 		if (low == high) {
   2798 			rc = snprintf(low_high_str, 40, "0x%x", low);
   2799 		} else {
   2800 			rc = snprintf(low_high_str, 40, "0x%x-0x%x", low, high);
   2801 		}
   2802 		if (rc < 0 || rc >= 40) {
   2803 			rc = -1;
   2804 			goto exit;
   2805 		}
   2806 
   2807 		ctx = context_to_str(pdb, &ioport->context[0]);
   2808 		if (!ctx) {
   2809 			rc = -1;
   2810 			goto exit;
   2811 		}
   2812 
   2813 		sepol_printf(out, "ioportcon %s %s\n", low_high_str, ctx);
   2814 
   2815 		free(ctx);
   2816 	}
   2817 
   2818 	rc = 0;
   2819 
   2820 exit:
   2821 	if (rc != 0) {
   2822 		sepol_log_err("Error writing ioportcon rules to policy.conf\n");
   2823 	}
   2824 
   2825 	return rc;
   2826 }
   2827 
   2828 static int write_xen_iomem_rules_to_conf(FILE *out, struct policydb *pdb)
   2829 {
   2830 	struct ocontext *iomem;
   2831 	uint64_t low;
   2832 	uint64_t high;
   2833 	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
   2834 	char *ctx;
   2835 	int rc = 0;
   2836 
   2837 	for (iomem = pdb->ocontexts[3]; iomem != NULL; iomem = iomem->next) {
   2838 		low = iomem->u.iomem.low_iomem;
   2839 		high = iomem->u.iomem.high_iomem;
   2840 		if (low == high) {
   2841 			rc = snprintf(low_high_str, 40, "0x%"PRIx64, low);
   2842 		} else {
   2843 			rc = snprintf(low_high_str, 40, "0x%"PRIx64"-0x%"PRIx64, low, high);
   2844 		}
   2845 		if (rc < 0 || rc >= 40) {
   2846 			rc = -1;
   2847 			goto exit;
   2848 		}
   2849 
   2850 		ctx = context_to_str(pdb, &iomem->context[0]);
   2851 		if (!ctx) {
   2852 			rc = -1;
   2853 			goto exit;
   2854 		}
   2855 
   2856 		sepol_printf(out, "iomemcon %s %s\n", low_high_str, ctx);
   2857 
   2858 		free(ctx);
   2859 	}
   2860 
   2861 	rc = 0;
   2862 
   2863 exit:
   2864 	if (rc != 0) {
   2865 		sepol_log_err("Error writing iomemcon rules to policy.conf\n");
   2866 	}
   2867 
   2868 	return rc;
   2869 }
   2870 
   2871 static int write_xen_pcidevice_rules_to_conf(FILE *out, struct policydb *pdb)
   2872 {
   2873 	struct ocontext *pcid;
   2874 	char device_str[20]; /* 2^64-1 <= 16 digits (hex) so < 19 chars */
   2875 	char *ctx;
   2876 	int rc = 0;
   2877 
   2878 	for (pcid = pdb->ocontexts[4]; pcid != NULL; pcid = pcid->next) {
   2879 		rc = snprintf(device_str, 20, "0x%lx", (unsigned long)pcid->u.device);
   2880 		if (rc < 0 || rc >= 20) {
   2881 			rc = -1;
   2882 			goto exit;
   2883 		}
   2884 
   2885 		ctx = context_to_str(pdb, &pcid->context[0]);
   2886 		if (!ctx) {
   2887 			rc = -1;
   2888 			goto exit;
   2889 		}
   2890 
   2891 		sepol_printf(out, "pcidevicecon %s %s\n", device_str, ctx);
   2892 
   2893 		free(ctx);
   2894 	}
   2895 
   2896 	rc = 0;
   2897 
   2898 exit:
   2899 	if (rc != 0) {
   2900 		sepol_log_err("Error writing pcidevicecon rules to policy.conf\n");
   2901 	}
   2902 
   2903 	return rc;
   2904 }
   2905 
   2906 static int write_xen_devicetree_rules_to_conf(FILE *out, struct policydb *pdb)
   2907 {
   2908 	struct ocontext *dtree;
   2909 	char *name, *ctx;
   2910 	int rc = 0;
   2911 
   2912 	for (dtree = pdb->ocontexts[5]; dtree != NULL; dtree = dtree->next) {
   2913 		name = dtree->u.name;
   2914 		ctx = context_to_str(pdb, &dtree->context[0]);
   2915 		if (!ctx) {
   2916 			rc = -1;
   2917 			goto exit;
   2918 		}
   2919 
   2920 		sepol_printf(out, "devicetreecon %s %s\n", name, ctx);
   2921 
   2922 		free(ctx);
   2923 	}
   2924 
   2925 exit:
   2926 	if (rc != 0) {
   2927 		sepol_log_err("Error writing devicetreecon rules to policy.conf\n");
   2928 	}
   2929 
   2930 	return rc;
   2931 }
   2932 
   2933 int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
   2934 {
   2935 	struct strs *mls_constraints = NULL;
   2936 	struct strs *non_mls_constraints = NULL;
   2937 	struct strs *mls_validatetrans = NULL;
   2938 	struct strs *non_mls_validatetrans = NULL;
   2939 	int rc = 0;
   2940 
   2941 	rc = strs_init(&mls_constraints, 32);
   2942 	if (rc != 0) {
   2943 		goto exit;
   2944 	}
   2945 
   2946 	rc = strs_init(&non_mls_constraints, 32);
   2947 	if (rc != 0) {
   2948 		goto exit;
   2949 	}
   2950 
   2951 	rc = strs_init(&mls_validatetrans, 32);
   2952 	if (rc != 0) {
   2953 		goto exit;
   2954 	}
   2955 
   2956 	rc = strs_init(&non_mls_validatetrans, 32);
   2957 	if (rc != 0) {
   2958 		goto exit;
   2959 	}
   2960 
   2961 	if (pdb == NULL) {
   2962 		sepol_log_err("No policy");
   2963 		rc = -1;
   2964 		goto exit;
   2965 	}
   2966 
   2967 	if (pdb->policy_type != SEPOL_POLICY_KERN) {
   2968 		sepol_log_err("Policy is not a kernel policy");
   2969 		rc = -1;
   2970 		goto exit;
   2971 	}
   2972 
   2973 	rc = constraint_rules_to_strs(pdb, mls_constraints, non_mls_constraints);
   2974 	if (rc != 0) {
   2975 		goto exit;
   2976 	}
   2977 
   2978 	rc = validatetrans_rules_to_strs(pdb, mls_validatetrans, non_mls_validatetrans);
   2979 	if (rc != 0) {
   2980 		goto exit;
   2981 	}
   2982 
   2983 	rc = write_handle_unknown_to_conf(out, pdb);
   2984 	if (rc != 0) {
   2985 		goto exit;
   2986 	}
   2987 
   2988 	rc = write_class_decl_rules_to_conf(out, pdb);
   2989 	if (rc != 0) {
   2990 		goto exit;
   2991 	}
   2992 
   2993 	rc = write_sid_decl_rules_to_conf(out, pdb);
   2994 	if (rc != 0) {
   2995 		goto exit;
   2996 	}
   2997 
   2998 	rc = write_class_and_common_rules_to_conf(out, pdb);
   2999 	if (rc != 0) {
   3000 		goto exit;
   3001 	}
   3002 
   3003 	rc = write_default_rules_to_conf(out, pdb);
   3004 	if (rc != 0) {
   3005 		goto exit;
   3006 	}
   3007 
   3008 	rc = write_mls_rules_to_conf(out, pdb);
   3009 	if (rc != 0) {
   3010 		goto exit;
   3011 	}
   3012 
   3013 	strs_write_each(mls_constraints, out);
   3014 	strs_write_each(mls_validatetrans, out);
   3015 
   3016 	rc = write_polcap_rules_to_conf(out, pdb);
   3017 	if (rc != 0) {
   3018 		goto exit;
   3019 	}
   3020 
   3021 	rc = write_type_attributes_to_conf(out, pdb);
   3022 	if (rc != 0) {
   3023 		goto exit;
   3024 	}
   3025 
   3026 	rc = write_role_attributes_to_conf(out, pdb);
   3027 	if (rc != 0) {
   3028 		goto exit;
   3029 	}
   3030 
   3031 	rc = write_boolean_decl_rules_to_conf(out, pdb);
   3032 	if (rc != 0) {
   3033 		goto exit;
   3034 	}
   3035 
   3036 	rc = write_type_decl_rules_to_conf(out, pdb);
   3037 	if (rc != 0) {
   3038 		goto exit;
   3039 	}
   3040 
   3041 	rc = write_type_alias_rules_to_conf(out, pdb);
   3042 	if (rc != 0) {
   3043 		goto exit;
   3044 	}
   3045 
   3046 	rc = write_type_bounds_rules_to_conf(out, pdb);
   3047 	if (rc != 0) {
   3048 		goto exit;
   3049 	}
   3050 
   3051 	rc = write_type_attribute_sets_to_conf(out, pdb);
   3052 	if (rc != 0) {
   3053 		goto exit;
   3054 	}
   3055 
   3056 	rc = write_type_permissive_rules_to_conf(out, pdb);
   3057 	if (rc != 0) {
   3058 		goto exit;
   3059 	}
   3060 
   3061 	rc = write_avtab_to_conf(out, pdb, 0);
   3062 	if (rc != 0) {
   3063 		goto exit;
   3064 	}
   3065 	write_filename_trans_rules_to_conf(out, pdb);
   3066 
   3067 	if (pdb->mls) {
   3068 		rc = write_range_trans_rules_to_conf(out, pdb);
   3069 		if (rc != 0) {
   3070 			goto exit;
   3071 		}
   3072 	}
   3073 
   3074 	rc = write_cond_nodes_to_conf(out, pdb);
   3075 	if (rc != 0) {
   3076 		goto exit;
   3077 	}
   3078 
   3079 	rc = write_role_decl_rules_to_conf(out, pdb);
   3080 	if (rc != 0) {
   3081 		goto exit;
   3082 	}
   3083 
   3084 	rc = write_role_transition_rules_to_conf(out, pdb);
   3085 	if (rc != 0) {
   3086 		goto exit;
   3087 	}
   3088 
   3089 	rc = write_role_allow_rules_to_conf(out, pdb);
   3090 	if (rc != 0) {
   3091 		goto exit;
   3092 	}
   3093 
   3094 	rc = write_user_decl_rules_to_conf(out, pdb);
   3095 	if (rc != 0) {
   3096 		goto exit;
   3097 	}
   3098 
   3099 	strs_write_each(non_mls_constraints, out);
   3100 	strs_write_each(non_mls_validatetrans, out);
   3101 
   3102 	rc = sort_ocontexts(pdb);
   3103 	if (rc != 0) {
   3104 		goto exit;
   3105 	}
   3106 
   3107 	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
   3108 		rc = write_selinux_isid_rules_to_conf(out, pdb);
   3109 		if (rc != 0) {
   3110 			goto exit;
   3111 		}
   3112 
   3113 		rc = write_selinux_fsuse_rules_to_conf(out, pdb);
   3114 		if (rc != 0) {
   3115 			goto exit;
   3116 		}
   3117 
   3118 		rc = write_genfscon_rules_to_conf(out, pdb);
   3119 		if (rc != 0) {
   3120 			goto exit;
   3121 		}
   3122 
   3123 		rc = write_selinux_port_rules_to_conf(out, pdb);
   3124 		if (rc != 0) {
   3125 			goto exit;
   3126 		}
   3127 
   3128 		rc = write_selinux_netif_rules_to_conf(out, pdb);
   3129 		if (rc != 0) {
   3130 			goto exit;
   3131 		}
   3132 
   3133 		rc = write_selinux_node_rules_to_conf(out, pdb);
   3134 		if (rc != 0) {
   3135 			goto exit;
   3136 		}
   3137 
   3138 		rc = write_selinux_node6_rules_to_conf(out, pdb);
   3139 		if (rc != 0) {
   3140 			goto exit;
   3141 		}
   3142 
   3143 		rc = write_selinux_ibpkey_rules_to_conf(out, pdb);
   3144 		if (rc != 0) {
   3145 			goto exit;
   3146 		}
   3147 
   3148 		rc = write_selinux_ibendport_rules_to_conf(out, pdb);
   3149 		if (rc != 0) {
   3150 			goto exit;
   3151 		}
   3152 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
   3153 		rc = write_xen_isid_rules_to_conf(out, pdb);
   3154 		if (rc != 0) {
   3155 			goto exit;
   3156 		}
   3157 
   3158 		rc = write_genfscon_rules_to_conf(out, pdb);
   3159 		if (rc != 0) {
   3160 			goto exit;
   3161 		}
   3162 
   3163 		rc = write_xen_pirq_rules_to_conf(out, pdb);
   3164 		if (rc != 0) {
   3165 			goto exit;
   3166 		}
   3167 
   3168 		rc = write_xen_iomem_rules_to_conf(out, pdb);
   3169 		if (rc != 0) {
   3170 			goto exit;
   3171 		}
   3172 
   3173 		rc = write_xen_ioport_rules_to_conf(out, pdb);
   3174 		if (rc != 0) {
   3175 			goto exit;
   3176 		}
   3177 
   3178 		rc = write_xen_pcidevice_rules_to_conf(out, pdb);
   3179 		if (rc != 0) {
   3180 			goto exit;
   3181 		}
   3182 
   3183 		rc = write_xen_devicetree_rules_to_conf(out, pdb);
   3184 		if (rc != 0) {
   3185 			goto exit;
   3186 		}
   3187 	}
   3188 
   3189 exit:
   3190 	strs_free_all(mls_constraints);
   3191 	strs_destroy(&mls_constraints);
   3192 	strs_free_all(non_mls_constraints);
   3193 	strs_destroy(&non_mls_constraints);
   3194 	strs_free_all(mls_validatetrans);
   3195 	strs_destroy(&mls_validatetrans);
   3196 	strs_free_all(non_mls_validatetrans);
   3197 	strs_destroy(&non_mls_validatetrans);
   3198 
   3199 	return rc;
   3200 }
   3201