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