| #include <stdlib.h> |
| |
| #include "cil_flavor.h" |
| #include "cil_internal.h" |
| #include "cil_log.h" |
| #include "cil_tree.h" |
| |
| struct cil_args_write { |
| FILE *cil_out; |
| struct cil_db *db; |
| }; |
| |
| static int cil_unfill_expr(struct cil_list *expr_str, char **out_str, int paren); |
| static int cil_unfill_classperms_list(struct cil_list *classperms, char **out_str, int paren); |
| static int __cil_write_first_child_helper(struct cil_tree_node *node, void *extra_args); |
| static int __cil_write_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args); |
| static int __cil_write_last_child_helper(struct cil_tree_node *node, void *extra_args); |
| |
| static int __cil_strlist_concat(struct cil_list *str_list, char **out_str, int paren) { |
| size_t len = paren ? 3 : 1; |
| size_t num_elems = 0; |
| char *p = NULL; |
| struct cil_list_item *curr; |
| |
| /* get buffer size */ |
| cil_list_for_each(curr, str_list) { |
| len += strlen((char *)curr->data); |
| num_elems++; |
| } |
| if (num_elems != 0) { |
| /* add spaces between elements */ |
| len += num_elems - 1; |
| } |
| *out_str = cil_malloc(len); |
| p = *out_str; |
| if (paren) |
| *p++ = '('; |
| cil_list_for_each(curr, str_list) { |
| size_t src_len = strlen((char *)curr->data); |
| memcpy(p, curr->data, src_len); |
| p += src_len; |
| if (curr->next != NULL) |
| *p++ = ' '; |
| } |
| if (paren) |
| *p++ = ')'; |
| *p++ = '\0'; |
| return SEPOL_OK; |
| } |
| |
| static int __cil_unfill_expr_helper(struct cil_list_item *curr, |
| struct cil_list_item **next, char **out_str, int paren) { |
| int rc = SEPOL_ERR; |
| char *str = NULL; |
| char *operand1 = NULL; |
| char *operand2 = NULL; |
| |
| switch(curr->flavor) { |
| case CIL_LIST: |
| rc = cil_unfill_expr((struct cil_list *)curr->data, &str, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| *out_str = str; |
| *next = curr->next; |
| break; |
| case CIL_STRING: |
| str = strdup((char *)curr->data); |
| if (!str) { |
| cil_log(CIL_ERR, "OOM. Unable to copy string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| *out_str = str; |
| *next = curr->next; |
| break; |
| case CIL_DATUM: |
| str = strdup(((struct cil_symtab_datum *)curr->data)->name); |
| if (!str) { |
| cil_log(CIL_ERR, "OOM. Unable to copy string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| *out_str = str; |
| *next = curr->next; |
| break; |
| case CIL_OP: { |
| char *op_str = NULL; |
| size_t len = 0; |
| enum cil_flavor op_flavor = (enum cil_flavor)curr->data; |
| switch (op_flavor) { |
| case CIL_AND: |
| op_str = CIL_KEY_AND; |
| break; |
| case CIL_OR: |
| op_str = CIL_KEY_OR; |
| break; |
| case CIL_NOT: |
| op_str = CIL_KEY_NOT; |
| break; |
| case CIL_ALL: |
| op_str = CIL_KEY_ALL; |
| break; |
| case CIL_EQ: |
| op_str = CIL_KEY_EQ; |
| break; |
| case CIL_NEQ: |
| op_str = CIL_KEY_NEQ; |
| break; |
| case CIL_RANGE: |
| op_str = CIL_KEY_RANGE; |
| break; |
| case CIL_XOR: |
| op_str = CIL_KEY_XOR; |
| break; |
| case CIL_CONS_DOM: |
| op_str = CIL_KEY_CONS_DOM; |
| break; |
| case CIL_CONS_DOMBY: |
| op_str = CIL_KEY_CONS_DOMBY; |
| break; |
| case CIL_CONS_INCOMP: |
| op_str = CIL_KEY_CONS_INCOMP; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown operator in expression: %d\n", op_flavor); |
| goto exit; |
| break; |
| } |
| /* all operands take two args except for 'all' and 'not', which take |
| * one and two, respectively */ |
| len = strlen(op_str) + 3; |
| if (op_flavor == CIL_ALL) { |
| *out_str = cil_malloc(len); |
| sprintf(*out_str, "(%s)", op_str); |
| *next = curr->next; |
| } else if (op_flavor == CIL_NOT) { |
| rc = __cil_unfill_expr_helper(curr->next, next, &operand1, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(operand1) + 1; |
| *out_str = cil_malloc(len); |
| sprintf(*out_str, "(%s %s)", op_str, operand1); |
| // *next already set by recursive call |
| } else { |
| rc = __cil_unfill_expr_helper(curr->next, next, &operand1, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(operand1) + 1; |
| // *next contains operand2, but keep track of next after that |
| rc = __cil_unfill_expr_helper(*next, next, &operand2, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(operand2) + 1; |
| *out_str = cil_malloc(len); |
| sprintf(*out_str, "(%s %s %s)", op_str, operand1, operand2); |
| // *next already set by recursive call |
| } |
| } |
| break; |
| case CIL_CONS_OPERAND: { |
| enum cil_flavor operand_flavor = (enum cil_flavor)curr->data; |
| char *operand_str = NULL; |
| switch (operand_flavor) { |
| case CIL_CONS_U1: |
| operand_str = CIL_KEY_CONS_U1; |
| break; |
| case CIL_CONS_U2: |
| operand_str = CIL_KEY_CONS_U2; |
| break; |
| case CIL_CONS_U3: |
| operand_str = CIL_KEY_CONS_U3; |
| break; |
| case CIL_CONS_T1: |
| operand_str = CIL_KEY_CONS_T1; |
| break; |
| case CIL_CONS_T2: |
| operand_str = CIL_KEY_CONS_T2; |
| break; |
| case CIL_CONS_T3: |
| operand_str = CIL_KEY_CONS_T3; |
| break; |
| case CIL_CONS_R1: |
| operand_str = CIL_KEY_CONS_R1; |
| break; |
| case CIL_CONS_R2: |
| operand_str = CIL_KEY_CONS_R2; |
| break; |
| case CIL_CONS_R3: |
| operand_str = CIL_KEY_CONS_R3; |
| break; |
| case CIL_CONS_L1: |
| operand_str = CIL_KEY_CONS_L1; |
| break; |
| case CIL_CONS_L2: |
| operand_str = CIL_KEY_CONS_L2; |
| break; |
| case CIL_CONS_H1: |
| operand_str = CIL_KEY_CONS_H1; |
| break; |
| case CIL_CONS_H2: |
| operand_str = CIL_KEY_CONS_H2; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown operand in expression\n"); |
| goto exit; |
| break; |
| } |
| str = strdup(operand_str); |
| if (!str) { |
| cil_log(CIL_ERR, "OOM. Unable to copy string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| *out_str = str; |
| *next = curr->next; |
| } |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown flavor in expression\n"); |
| goto exit; |
| break; |
| } |
| rc = SEPOL_OK; |
| exit: |
| free(operand1); |
| free(operand2); |
| return rc; |
| } |
| |
| static int cil_unfill_expr(struct cil_list *expr_str, char **out_str, int paren) { |
| int rc = SEPOL_ERR; |
| |
| /* reuse cil_list to keep track of strings */ |
| struct cil_list *str_list = NULL; |
| struct cil_list_item *curr = NULL; |
| |
| cil_list_init(&str_list, CIL_NONE); |
| |
| /* iterate through cil_list, grabbing elements as needed */ |
| curr = expr_str->head; |
| while(curr != NULL) { |
| char *str = NULL; |
| struct cil_list_item *next = NULL; |
| |
| rc = __cil_unfill_expr_helper(curr, &next, &str, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| cil_list_append(str_list, CIL_STRING, (void *) str); |
| str = NULL; |
| curr = next; |
| } |
| rc = __cil_strlist_concat(str_list, out_str, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| rc = SEPOL_OK; |
| exit: |
| cil_list_for_each(curr, str_list) { |
| free(curr->data); |
| } |
| cil_list_destroy(&str_list, 0); |
| return rc; |
| } |
| |
| static int cil_unfill_cats(struct cil_cats *cats, char **out_str) { |
| return cil_unfill_expr(cats->str_expr, out_str, 0); |
| } |
| |
| static int cil_unfill_level(struct cil_level *lvl, char **out_str) { |
| int rc = SEPOL_ERR; |
| size_t len = 0; |
| char *sens, *cats = NULL; |
| sens = lvl->sens_str; |
| len = strlen(sens) + 3; // '()\0' |
| if (lvl->cats != NULL) { |
| rc = cil_unfill_cats(lvl->cats, &cats); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(cats) + 1; |
| } |
| *out_str = cil_malloc(len); |
| if (cats == NULL) { |
| if (sprintf(*out_str, "(%s)", sens) < 0) { |
| cil_log(CIL_ERR, "Error unpacking and writing level\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| if (sprintf(*out_str, "(%s %s)", sens, cats) < 0) { |
| cil_log(CIL_ERR, "Error unpacking and writing level\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } |
| rc = SEPOL_OK; |
| exit: |
| free(cats); |
| return rc; |
| } |
| |
| static int cil_unfill_levelrange(struct cil_levelrange *lvlrnge, char **out_str) { |
| int rc = SEPOL_ERR; |
| size_t len = 0; |
| char *low = NULL, *high = NULL; |
| if (lvlrnge->low_str != NULL) { |
| low = strdup(lvlrnge->low_str); |
| if (low == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy level string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_level(lvlrnge->low, &low); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| if (lvlrnge->high_str != NULL) { |
| high = strdup(lvlrnge->high_str); |
| if (high == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy level string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_level(lvlrnge->high, &high); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| len = strlen(low) + strlen(high) + 4; |
| *out_str = cil_malloc(len); |
| if (sprintf(*out_str, "(%s %s)", low, high) < 0) { |
| cil_log(CIL_ERR, "Error unpacking and writing levelrange\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| rc = SEPOL_OK; |
| exit: |
| free(low); |
| free(high); |
| return rc; |
| } |
| |
| static int cil_unfill_context(struct cil_context *context, char **out_str) { |
| int rc = SEPOL_ERR; |
| size_t len = 0; |
| char *user_str, *role_str, *type_str; |
| char *range_str = NULL; |
| |
| user_str = context->user_str; |
| role_str = context->role_str; |
| type_str = context->type_str; |
| if (context->range_str != NULL) { |
| range_str = strdup(context->range_str); |
| if (range_str == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy range string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_levelrange(context->range, &range_str); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| len = strlen(user_str) + strlen(role_str) + strlen(type_str) |
| + strlen(range_str) + 6; |
| *out_str = cil_malloc(len); |
| if (sprintf(*out_str, "(%s %s %s %s)", user_str, role_str, type_str, range_str) < 0) { |
| cil_log(CIL_ERR, "Error unpacking and writing context\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| rc = SEPOL_OK; |
| exit: |
| free(range_str); |
| return rc; |
| } |
| |
| static int cil_unfill_permx(struct cil_permissionx *permx, char **out_str) { |
| size_t len = 3; |
| int rc = SEPOL_ERR; |
| char *kind, *obj; |
| char *expr = NULL; |
| |
| switch (permx->kind) { |
| case CIL_PERMX_KIND_IOCTL: |
| kind = CIL_KEY_IOCTL; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown permissionx kind: %d\n", permx->kind); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| obj = permx->obj_str; |
| rc = cil_unfill_expr(permx->expr_str, &expr, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(kind) + strlen(obj) + strlen(expr) + 2; |
| *out_str = cil_malloc(len); |
| if (sprintf(*out_str, "(%s %s %s)", kind, obj, expr) < 0) { |
| cil_log(CIL_ERR, "Error writing xperm\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| rc = SEPOL_OK; |
| exit: |
| free(expr); |
| return rc; |
| } |
| |
| #define cil_write_unsupported(flavor) _cil_write_unsupported(flavor, __LINE__) |
| static int _cil_write_unsupported(const char *flavor, int line) { |
| cil_log(CIL_ERR, |
| "flavor \"%s\" is not supported, look in file \"%s\"" |
| " on line %d to add support.\n", flavor, __FILE__, line); |
| return SEPOL_ENOTSUP; |
| } |
| |
| static int cil_write_policycap(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_policycap *polcap = (struct cil_policycap *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_POLICYCAP, polcap->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_perm(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_perm *perm = (struct cil_perm *)node->data; |
| fprintf(cil_out, "%s", perm->datum.name); |
| if (node->next != NULL) |
| fprintf(cil_out, " "); |
| return SEPOL_OK; |
| } |
| |
| |
| static int cil_write_class(struct cil_tree_node *node, uint32_t *finished, |
| struct cil_args_write *extra_args) { |
| int rc = SEPOL_ERR; |
| FILE *cil_out = extra_args->cil_out; |
| struct cil_symtab_datum *datum = (struct cil_symtab_datum *)node->data; |
| char *class_type = (node->flavor == CIL_CLASS) ? CIL_KEY_CLASS : CIL_KEY_COMMON; |
| |
| /* print preamble */ |
| fprintf(cil_out, "(%s %s ", class_type, datum->name); |
| |
| if (node->cl_head == NULL) { |
| /* no associated perms in this part of tree */ |
| fprintf(cil_out, "()"); |
| } else { |
| |
| /* visit subtree (perms) */ |
| rc = cil_tree_walk(node, __cil_write_node_helper, |
| __cil_write_first_child_helper, |
| __cil_write_last_child_helper, |
| extra_args); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| |
| /* postamble (trailing paren) */ |
| fprintf(cil_out, ")\n"); |
| *finished = CIL_TREE_SKIP_HEAD; |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int cil_write_classorder(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *ord_str = NULL; |
| struct cil_classorder *classord = (struct cil_classorder *)node->data; |
| |
| /* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */ |
| rc = cil_unfill_expr(classord->class_list_str, &ord_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_CLASSORDER, ord_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ord_str); |
| return rc; |
| } |
| |
| static int cil_write_classcommon(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_classcommon *classcommon = (struct cil_classcommon *)node->data; |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_CLASSCOMMON, classcommon->class_str, |
| classcommon->common_str); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_sid(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_sid *sid = (struct cil_sid *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_SID, sid->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_sidcontext(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *sid; |
| char *ctx_str = NULL; |
| struct cil_sidcontext *sidcon = (struct cil_sidcontext *)node->data; |
| |
| sid = sidcon->sid_str; |
| if (sidcon->context_str != NULL) { |
| ctx_str = strdup(sidcon->context_str); |
| if (ctx_str == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy context string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_context(sidcon->context, &ctx_str); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_SIDCONTEXT, sid, ctx_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ctx_str); |
| return rc; |
| } |
| |
| static int cil_write_sidorder(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *ord_str = NULL; |
| struct cil_sidorder *sidord = (struct cil_sidorder *)node->data; |
| |
| /* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */ |
| rc = cil_unfill_expr(sidord->sid_list_str, &ord_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_SIDORDER, ord_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ord_str); |
| return rc; |
| } |
| |
| static int cil_write_user(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_user *user = (struct cil_user *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_USER, user->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_userrole(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_userrole *userrole = (struct cil_userrole *)node->data; |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERROLE, userrole->user_str, |
| userrole->role_str); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_userlevel(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_userlevel *usrlvl = (struct cil_userlevel *)node->data; |
| int rc = SEPOL_ERR; |
| char *usr; |
| char *lvl = NULL; |
| |
| usr = usrlvl->user_str; |
| if (usrlvl->level_str != NULL) { |
| lvl = strdup(usrlvl->level_str); |
| if (lvl == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy level string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_level(usrlvl->level, &lvl); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERLEVEL, usr, lvl); |
| rc = SEPOL_OK; |
| exit: |
| free(lvl); |
| return rc; |
| } |
| |
| static int cil_write_userrange(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_userrange *usrrng = (struct cil_userrange *)node->data; |
| int rc = SEPOL_ERR; |
| char *usr; |
| char *range = NULL; |
| |
| usr = usrrng->user_str; |
| if (usrrng->range_str != NULL) { |
| range = strdup(usrrng->range_str); |
| if (range == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy levelrange string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_levelrange(usrrng->range, &range); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_USERRANGE, usr, range); |
| rc = SEPOL_OK; |
| exit: |
| free(range); |
| return rc; |
| } |
| |
| static int cil_write_role(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_role *role = (struct cil_role *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_ROLE, role->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_roletype(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_roletype *roletype = (struct cil_roletype *)node->data; |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_ROLETYPE, roletype->role_str, roletype->type_str); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_roleattribute(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_roleattribute *roleattr = (struct cil_roleattribute *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_ROLEATTRIBUTE, roleattr->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_type(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_type *type = (struct cil_type *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPE, type->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_typepermissive(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_typepermissive *type = (struct cil_typepermissive *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPEPERMISSIVE, type->type_str); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_typeattribute(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_typeattribute *typeattr = (struct cil_typeattribute *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_TYPEATTRIBUTE, typeattr->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_typeattributeset(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *typeattr; |
| char *set_str = NULL; |
| struct cil_typeattributeset *typeattrset = (struct cil_typeattributeset *)node->data; |
| |
| typeattr = typeattrset->attr_str; |
| rc = cil_unfill_expr(typeattrset->str_expr, &set_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_TYPEATTRIBUTESET, typeattr, set_str); |
| rc = SEPOL_OK; |
| exit: |
| free(set_str); |
| return rc; |
| } |
| |
| static int cil_write_expandtypeattribute(struct cil_tree_node *node, FILE *cil_out) |
| { |
| int rc = SEPOL_ERR; |
| char *attr_strs = NULL; |
| struct cil_expandtypeattribute *expandattr = (struct cil_expandtypeattribute *)node->data; |
| |
| rc = cil_unfill_expr(expandattr->attr_strs, &attr_strs, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| |
| fprintf(cil_out, "(%s %s %s)\n", CIL_KEY_EXPANDTYPEATTRIBUTE, attr_strs, |
| expandattr->expand ? CIL_KEY_CONDTRUE : CIL_KEY_CONDFALSE); |
| rc = SEPOL_OK; |
| exit: |
| free(attr_strs); |
| return rc; |
| } |
| |
| static int cil_write_alias(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *type; |
| struct cil_alias *alias = (struct cil_alias *)node->data; |
| |
| switch (node->flavor) { |
| case CIL_TYPEALIAS: |
| type = CIL_KEY_TYPEALIAS; |
| break; |
| case CIL_SENSALIAS: |
| type = CIL_KEY_SENSALIAS; |
| break; |
| case CIL_CATALIAS: |
| type = CIL_KEY_CATALIAS; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown alias type: %d\n", node->flavor); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| fprintf(cil_out, "(%s %s)\n", type, alias->datum.name); |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int cil_write_aliasactual(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *type, *alias, *actual; |
| struct cil_aliasactual *aliasact = (struct cil_aliasactual *)node->data; |
| |
| switch (node->flavor) { |
| case CIL_TYPEALIASACTUAL: |
| type = CIL_KEY_TYPEALIASACTUAL; |
| break; |
| case CIL_SENSALIASACTUAL: |
| type = CIL_KEY_SENSALIASACTUAL; |
| break; |
| case CIL_CATALIASACTUAL: |
| type = CIL_KEY_CATALIASACTUAL; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown alias type: %d\n", node->flavor); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| alias = aliasact->alias_str; |
| actual = aliasact->actual_str; |
| fprintf(cil_out, "(%s %s %s)\n", type, alias, actual); |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int cil_write_nametypetransition(struct cil_tree_node *node, FILE *cil_out) { |
| char *src, *tgt, *obj, *res, *name; |
| struct cil_nametypetransition *ntrans = (struct cil_nametypetransition *)node->data; |
| |
| src = ntrans->src_str; |
| tgt = ntrans->tgt_str; |
| obj = ntrans->obj_str; |
| res = ntrans->result_str; |
| name = ntrans->name_str; |
| fprintf(cil_out, "(%s %s %s %s \"%s\" %s)\n", CIL_KEY_TYPETRANSITION, |
| src, tgt, obj, name, res); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_avrule_x(struct cil_avrule *avrule, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *rulekind, *src, *tgt; |
| char *xperms = NULL; |
| |
| switch (avrule->rule_kind) { |
| case CIL_AVRULE_ALLOWED: |
| rulekind = CIL_KEY_ALLOWX; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| rulekind = CIL_KEY_AUDITALLOWX; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| rulekind = CIL_KEY_DONTAUDITX; |
| break; |
| case CIL_AVRULE_NEVERALLOW: |
| rulekind = CIL_KEY_NEVERALLOWX; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown AVRULE type: %d\n", avrule->rule_kind); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| src = avrule->src_str; |
| tgt = avrule->tgt_str; |
| |
| if (avrule->perms.x.permx_str != NULL) { |
| xperms = strdup(avrule->perms.x.permx_str); |
| if (xperms == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy xperms string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_permx(avrule->perms.x.permx, &xperms); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s %s)\n", rulekind, src, tgt, xperms); |
| rc = SEPOL_OK; |
| exit: |
| free(xperms); |
| return rc; |
| } |
| |
| static int cil_write_avrule_orig(struct cil_avrule *avrule, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *rulekind, *src, *tgt; |
| char *classperms = NULL; |
| |
| switch (avrule->rule_kind) { |
| case CIL_AVRULE_ALLOWED: |
| rulekind = CIL_KEY_ALLOW; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| rulekind = CIL_KEY_AUDITALLOW; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| rulekind = CIL_KEY_DONTAUDIT; |
| break; |
| case CIL_AVRULE_NEVERALLOW: |
| rulekind = CIL_KEY_NEVERALLOW; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown AVRULE type: %d\n", avrule->rule_kind); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| src = avrule->src_str; |
| tgt = avrule->tgt_str; |
| |
| rc = cil_unfill_classperms_list(avrule->perms.classperms, &classperms, 0); |
| if (rc != SEPOL_OK) |
| goto exit; |
| fprintf(cil_out, "(%s %s %s %s)\n", rulekind, src, tgt, classperms); |
| rc = SEPOL_OK; |
| exit: |
| free(classperms); |
| return rc; |
| } |
| |
| static int cil_write_avrule(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| struct cil_avrule *avrule = (struct cil_avrule *)node->data; |
| |
| if (avrule->is_extended) |
| rc = cil_write_avrule_x(avrule, cil_out); |
| else |
| rc = cil_write_avrule_orig(avrule, cil_out); |
| return rc; |
| } |
| |
| static int cil_write_type_rule(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *type, *src, *tgt, *obj, *res; |
| struct cil_type_rule *typerule = (struct cil_type_rule *)node->data; |
| |
| switch (typerule->rule_kind) { |
| case CIL_TYPE_TRANSITION: |
| type = CIL_KEY_TYPETRANSITION; |
| break; |
| case CIL_TYPE_MEMBER: |
| type = CIL_KEY_TYPEMEMBER; |
| break; |
| case CIL_TYPE_CHANGE: |
| type = CIL_KEY_TYPECHANGE; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown TYPERULE type: %d\n", typerule->rule_kind); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| src = typerule->src_str; |
| tgt = typerule->tgt_str; |
| obj = typerule->obj_str; |
| res = typerule->result_str; |
| fprintf(cil_out, "(%s %s %s %s %s)\n", type, src, tgt, obj, res); |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int cil_write_sens(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_sens *sens = (struct cil_sens *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_SENSITIVITY, sens->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_cat(struct cil_tree_node *node, FILE *cil_out) { |
| struct cil_cat *cat = (struct cil_cat *)node->data; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_CATEGORY, cat->datum.name); |
| return SEPOL_OK; |
| } |
| |
| static int cil_write_senscat(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *sens; |
| char *cats = NULL; |
| struct cil_senscat *senscat = (struct cil_senscat *)node->data; |
| |
| sens = senscat->sens_str; |
| rc = cil_unfill_cats(senscat->cats, &cats); |
| if (rc != SEPOL_OK) |
| goto exit; |
| /* TODO: deal with extra/missing parens */ |
| fprintf(cil_out, "(%s %s (%s))\n", CIL_KEY_SENSCAT, sens, cats); |
| rc = SEPOL_OK; |
| exit: |
| free(cats); |
| return rc; |
| } |
| |
| static int cil_write_catorder(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *ord_str = NULL; |
| struct cil_catorder *catord = (struct cil_catorder *)node->data; |
| |
| /* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */ |
| rc = cil_unfill_expr(catord->cat_list_str, &ord_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_CATORDER, ord_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ord_str); |
| return rc; |
| } |
| |
| static int cil_write_sensorder(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *ord_str = NULL; |
| struct cil_sensorder *sensord = (struct cil_sensorder *)node->data; |
| |
| /* cil_unfill_expr() has logic to stringify a cil_list, reuse that. */ |
| rc = cil_unfill_expr(sensord->sens_list_str, &ord_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_SENSITIVITYORDER, ord_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ord_str); |
| return rc; |
| } |
| |
| static int cil_write_genfscon(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| char *ctx_str = NULL; |
| |
| struct cil_genfscon *genfscon = (struct cil_genfscon *)node->data; |
| if (genfscon->context_str != NULL) { |
| ctx_str = strdup(genfscon->context_str); |
| if (ctx_str == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy context string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_context(genfscon->context, &ctx_str); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s %s)\n", CIL_KEY_GENFSCON, genfscon->fs_str, |
| genfscon->path_str, ctx_str); |
| rc = SEPOL_OK; |
| exit: |
| free(ctx_str); |
| return rc; |
| } |
| |
| static int cil_unfill_classperms(struct cil_list_item *curr, char **out_str) { |
| int rc = SEPOL_ERR; |
| size_t len = 3; |
| char *class_str; |
| char *perms_str = NULL; |
| struct cil_classperms *cp = (struct cil_classperms *)curr->data; |
| |
| class_str = cp->class_str; |
| len += strlen(class_str) + 1; |
| |
| /* fill_perms just calls gen_expr */ |
| rc = cil_unfill_expr(cp->perm_strs, &perms_str, 1); |
| if (rc != SEPOL_OK) |
| goto exit; |
| len += strlen(perms_str); |
| *out_str = cil_malloc(len); |
| sprintf(*out_str, "(%s %s)", class_str, perms_str); |
| rc = SEPOL_OK; |
| exit: |
| free(perms_str); |
| return rc; |
| } |
| |
| static int cil_unfill_classperms_list(struct cil_list *classperms, char **out_str, int paren) { |
| int rc = SEPOL_ERR; |
| struct cil_list_item *curr; |
| char *str = NULL; |
| |
| /* reuse cil_list to keep track of strings */ |
| struct cil_list *str_list = NULL; |
| cil_list_init(&str_list, CIL_NONE); |
| cil_list_for_each(curr, classperms) { |
| switch (curr->flavor) { |
| case CIL_CLASSPERMS_SET: |
| str = strdup(((struct cil_classperms_set *)curr->data)->set_str); |
| if (str == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy classpermset.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| break; |
| case CIL_CLASSPERMS: |
| rc = cil_unfill_classperms(curr, &str); |
| if (rc != SEPOL_OK) |
| goto exit; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unrecognized classperms flavor\n."); |
| goto exit; |
| } |
| cil_list_append(str_list, CIL_STRING, (void *) str); |
| str = NULL; |
| } |
| rc = __cil_strlist_concat(str_list, out_str, paren); |
| if (rc != SEPOL_OK) |
| goto exit; |
| rc = SEPOL_OK; |
| exit: |
| cil_list_for_each(curr, str_list) { |
| free(curr->data); |
| } |
| cil_list_destroy(&str_list, 0); |
| return rc; |
| } |
| |
| static int cil_write_fsuse(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| struct cil_fsuse *fsuse = (struct cil_fsuse *)node->data; |
| char *type, *fsname; |
| char *ctx_str = NULL; |
| |
| switch(fsuse->type) { |
| case CIL_FSUSE_XATTR: |
| type = CIL_KEY_XATTR; |
| break; |
| case CIL_FSUSE_TASK: |
| type = CIL_KEY_TASK; |
| break; |
| case CIL_FSUSE_TRANS: |
| type = CIL_KEY_TRANS; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unrecognized fsuse type\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| |
| fsname = fsuse->fs_str; |
| if (fsuse->context_str != NULL) { |
| ctx_str = strdup(fsuse->context_str); |
| if (ctx_str == NULL) { |
| cil_log(CIL_ERR, "OOM. Unable to copy context string.\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| } else { |
| rc = cil_unfill_context(fsuse->context, &ctx_str); |
| if (rc != SEPOL_OK) |
| goto exit; |
| } |
| fprintf(cil_out, "(%s %s %s %s)\n", CIL_KEY_FSUSE, type, fsname, ctx_str); |
| exit: |
| free(ctx_str); |
| return rc; |
| } |
| |
| static int cil_write_constrain(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_ERR; |
| struct cil_constrain *cons = (struct cil_constrain *)node->data; |
| char *flav; |
| char *classperms = NULL; |
| char *expr = NULL; |
| |
| flav = (node->flavor == CIL_CONSTRAIN) ? CIL_KEY_CONSTRAIN : CIL_KEY_MLSCONSTRAIN; |
| |
| rc = cil_unfill_classperms_list(cons->classperms, &classperms, 0); |
| if (rc != SEPOL_OK) |
| goto exit; |
| |
| rc = cil_unfill_expr(cons->str_expr, &expr, 0); |
| if (rc != SEPOL_OK) |
| goto exit; |
| |
| fprintf(cil_out, "(%s %s %s)\n", flav, classperms, expr); |
| exit: |
| free(classperms); |
| free(expr); |
| return rc; |
| } |
| |
| static int cil_write_handleunknown(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_OK; |
| struct cil_handleunknown *handunknown = (struct cil_handleunknown *)node->data; |
| char *val = NULL; |
| switch (handunknown->handle_unknown) { |
| case SEPOL_ALLOW_UNKNOWN: |
| val = CIL_KEY_HANDLEUNKNOWN_ALLOW; |
| break; |
| case SEPOL_DENY_UNKNOWN: |
| val = CIL_KEY_HANDLEUNKNOWN_DENY; |
| break; |
| case SEPOL_REJECT_UNKNOWN: |
| val = CIL_KEY_HANDLEUNKNOWN_REJECT; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown handleunknown value: %d.\n", |
| handunknown->handle_unknown); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_HANDLEUNKNOWN, val); |
| exit: |
| return rc; |
| } |
| |
| static int cil_write_mls(struct cil_tree_node *node, FILE *cil_out) { |
| int rc = SEPOL_OK; |
| struct cil_mls *mls = (struct cil_mls *)node->data; |
| char *val = NULL; |
| switch (mls->value) { |
| case CIL_TRUE: |
| val = CIL_KEY_CONDTRUE; |
| break; |
| case CIL_FALSE: |
| val = CIL_KEY_CONDFALSE; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown mls value: %d.\n", mls->value); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| fprintf(cil_out, "(%s %s)\n", CIL_KEY_MLS, val); |
| exit: |
| return rc; |
| } |
| |
| static int __cil_write_first_child_helper(struct cil_tree_node *node, void *extra_args) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_args_write *args = (struct cil_args_write *) extra_args; |
| FILE *cil_out = NULL; |
| |
| if (node == NULL || extra_args == NULL) { |
| goto exit; |
| } |
| |
| cil_out = args->cil_out; |
| |
| if (node->parent && node->parent->flavor != CIL_ROOT && node->parent->flavor != CIL_SRC_INFO) |
| fprintf(cil_out,"("); |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| static int __cil_write_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| { |
| int rc = SEPOL_OK; |
| struct cil_args_write *args = NULL; |
| FILE *cil_out = NULL; |
| |
| if (node == NULL || extra_args == NULL) { |
| goto exit; |
| } |
| |
| args = extra_args; |
| cil_out = args->cil_out; |
| |
| switch (node->flavor) { |
| case CIL_BLOCK: |
| rc = cil_write_unsupported("CIL_BLOCK"); |
| break; |
| case CIL_BLOCKABSTRACT: |
| rc = cil_write_unsupported("CIL_BLOCKABSTRACT"); |
| break; |
| case CIL_BLOCKINHERIT: |
| rc = cil_write_unsupported("CIL_BLOCKINHERIT"); |
| break; |
| case CIL_IN: |
| rc = cil_write_unsupported("CIL_IN"); |
| break; |
| case CIL_POLICYCAP: |
| cil_write_policycap(node, cil_out); |
| break; |
| case CIL_PERM: |
| rc = cil_write_perm(node, cil_out); |
| break; |
| case CIL_MAP_PERM: |
| rc = cil_write_unsupported("CIL_MAP_PERM"); |
| break; |
| case CIL_CLASSMAPPING: |
| rc = cil_write_unsupported("CIL_CLASSMAPPING"); |
| break; |
| case CIL_CLASS: |
| rc = cil_write_class(node, finished, extra_args); |
| break; |
| case CIL_COMMON: |
| rc = cil_write_class(node, finished, extra_args); |
| break; |
| case CIL_MAP_CLASS: |
| rc = cil_write_unsupported("CIL_MAP_CLASS"); |
| break; |
| case CIL_CLASSORDER: |
| rc = cil_write_classorder(node, cil_out); |
| break; |
| case CIL_CLASSPERMISSION: |
| rc = cil_write_unsupported("CIL_CLASSPERMISSION"); |
| break; |
| case CIL_CLASSPERMISSIONSET: |
| rc = cil_write_unsupported("CIL_CLASSPERMISSIONSET"); |
| break; |
| case CIL_CLASSCOMMON: |
| rc = cil_write_classcommon(node, cil_out); |
| break; |
| case CIL_SID: |
| rc = cil_write_sid(node, cil_out); |
| break; |
| case CIL_SIDCONTEXT: |
| rc = cil_write_sidcontext(node, cil_out); |
| break; |
| case CIL_SIDORDER: |
| rc = cil_write_sidorder(node, cil_out); |
| break; |
| case CIL_USER: |
| rc = cil_write_user(node, cil_out); |
| break; |
| case CIL_USERATTRIBUTE: |
| rc = cil_write_unsupported("CIL_USERATTRIBUTE"); |
| break; |
| case CIL_USERATTRIBUTESET: |
| rc = cil_write_unsupported("CIL_USERATTRIBUTESET"); |
| break; |
| case CIL_USERROLE: |
| rc = cil_write_userrole(node, cil_out); |
| break; |
| case CIL_USERLEVEL: |
| rc = cil_write_userlevel(node, cil_out); |
| break; |
| case CIL_USERRANGE: |
| rc = cil_write_userrange(node, cil_out); |
| break; |
| case CIL_USERBOUNDS: |
| rc = cil_write_unsupported("CIL_USERBOUNDS"); |
| break; |
| case CIL_USERPREFIX: |
| rc = cil_write_unsupported("CIL_USERPREFIX"); |
| break; |
| case CIL_ROLE: |
| rc = cil_write_role(node, cil_out); |
| break; |
| case CIL_ROLETYPE: |
| rc = cil_write_roletype(node, cil_out); |
| break; |
| case CIL_ROLEBOUNDS: |
| rc = cil_write_unsupported("CIL_ROLEBOUNDS"); |
| break; |
| case CIL_ROLEATTRIBUTE: |
| cil_write_roleattribute(node, cil_out); |
| break; |
| case CIL_ROLEATTRIBUTESET: |
| rc = cil_write_unsupported("CIL_ROLEATTRIBUTESET"); |
| break; |
| case CIL_ROLEALLOW: |
| rc = cil_write_unsupported("CIL_ROLEALLOW"); |
| break; |
| case CIL_TYPE: |
| rc = cil_write_type(node, cil_out); |
| break; |
| case CIL_TYPEBOUNDS: |
| rc = cil_write_unsupported("CIL_TYPEBOUNDS"); |
| break; |
| case CIL_TYPEPERMISSIVE: |
| rc = cil_write_typepermissive(node, cil_out); |
| break; |
| case CIL_TYPEATTRIBUTE: |
| rc = cil_write_typeattribute(node, cil_out); |
| break; |
| case CIL_TYPEATTRIBUTESET: |
| rc = cil_write_typeattributeset(node, cil_out); |
| break; |
| case CIL_EXPANDTYPEATTRIBUTE: |
| rc = cil_write_expandtypeattribute(node, cil_out); |
| break; |
| case CIL_TYPEALIAS: |
| rc = cil_write_alias(node, cil_out); |
| break; |
| case CIL_TYPEALIASACTUAL: |
| rc = cil_write_aliasactual(node, cil_out); |
| break; |
| case CIL_ROLETRANSITION: |
| rc = cil_write_unsupported("CIL_ROLETRANSITION"); |
| break; |
| case CIL_NAMETYPETRANSITION: |
| rc = cil_write_nametypetransition(node, cil_out); |
| break; |
| case CIL_RANGETRANSITION: |
| rc = cil_write_unsupported("CIL_RANGETRANSITION"); |
| break; |
| case CIL_TUNABLE: |
| rc = cil_write_unsupported("CIL_TUNABLE"); |
| break; |
| case CIL_BOOL: |
| rc = cil_write_unsupported("CIL_BOOL"); |
| break; |
| case CIL_AVRULE: |
| case CIL_AVRULEX: |
| rc = cil_write_avrule(node, cil_out); |
| break; |
| case CIL_PERMISSIONX: |
| rc = cil_write_unsupported("CIL_PERMISSIONX"); |
| break; |
| case CIL_TYPE_RULE: |
| cil_write_type_rule(node, cil_out); |
| break; |
| case CIL_SENS: |
| rc = cil_write_sens(node, cil_out); |
| break; |
| case CIL_SENSALIAS: |
| rc = cil_write_alias(node, cil_out); |
| break; |
| case CIL_SENSALIASACTUAL: |
| rc = cil_write_aliasactual(node, cil_out); |
| break; |
| case CIL_CAT: |
| rc = cil_write_cat(node, cil_out); |
| break; |
| case CIL_CATALIAS: |
| rc = cil_write_alias(node, cil_out); |
| break; |
| case CIL_CATALIASACTUAL: |
| rc = cil_write_aliasactual(node, cil_out); |
| break; |
| case CIL_CATSET: |
| rc = cil_write_unsupported("CIL_CATSET"); |
| break; |
| case CIL_SENSCAT: |
| rc = cil_write_senscat(node, cil_out); |
| break; |
| case CIL_CATORDER: |
| rc = cil_write_catorder(node, cil_out); |
| break; |
| case CIL_SENSITIVITYORDER: |
| rc = cil_write_sensorder(node, cil_out); |
| break; |
| case CIL_LEVEL: |
| rc = cil_write_unsupported("CIL_LEVEL"); |
| break; |
| case CIL_LEVELRANGE: |
| rc = cil_write_unsupported("CIL_LEVELRANGE"); |
| break; |
| case CIL_CONTEXT: |
| rc = cil_write_unsupported("CIL_CONTEXT"); |
| break; |
| case CIL_NETIFCON: |
| rc = cil_write_unsupported("CIL_NETIFCON"); |
| break; |
| case CIL_GENFSCON: |
| rc = cil_write_genfscon(node, cil_out); |
| break; |
| case CIL_FILECON: |
| rc = cil_write_unsupported("CIL_FILECON"); |
| break; |
| case CIL_NODECON: |
| rc = cil_write_unsupported("CIL_NODECON"); |
| break; |
| case CIL_PORTCON: |
| rc = cil_write_unsupported("CIL_PORTCON"); |
| break; |
| case CIL_PIRQCON: |
| rc = cil_write_unsupported("CIL_PIRQCON"); |
| break; |
| case CIL_IOMEMCON: |
| rc = cil_write_unsupported("CIL_IOMEMCON"); |
| break; |
| case CIL_IOPORTCON: |
| rc = cil_write_unsupported("CIL_IOPORTCON"); |
| break; |
| case CIL_PCIDEVICECON: |
| rc = cil_write_unsupported("CIL_PCIDEVICECON"); |
| break; |
| case CIL_DEVICETREECON: |
| rc = cil_write_unsupported("CIL_DEVICETREECON"); |
| break; |
| case CIL_FSUSE: |
| rc = cil_write_fsuse(node, cil_out); |
| break; |
| case CIL_CONSTRAIN: |
| rc = cil_write_unsupported("CIL_CONSTRAIN"); |
| break; |
| case CIL_MLSCONSTRAIN: |
| rc = cil_write_constrain(node, cil_out); |
| break; |
| case CIL_VALIDATETRANS: |
| rc = cil_write_unsupported("CIL_VALIDATETRANS"); |
| break; |
| case CIL_MLSVALIDATETRANS: |
| rc = cil_write_unsupported("CIL_MLSVALIDATETRANS"); |
| break; |
| case CIL_CALL: |
| rc = cil_write_unsupported("CIL_CALL"); |
| break; |
| case CIL_MACRO: |
| rc = cil_write_unsupported("CIL_MACRO"); |
| break; |
| case CIL_NODE: |
| rc = cil_write_unsupported("CIL_NODE"); |
| break; |
| case CIL_OPTIONAL: |
| rc = cil_write_unsupported("CIL_OPTIONAL"); |
| break; |
| case CIL_IPADDR: |
| rc = cil_write_unsupported("CIL_IPADDR"); |
| break; |
| case CIL_CONDBLOCK: |
| rc = cil_write_unsupported("CIL_CONDBLOCK"); |
| break; |
| case CIL_BOOLEANIF: |
| rc = cil_write_unsupported("CIL_BOOLEANIF"); |
| break; |
| case CIL_TUNABLEIF: |
| rc = cil_write_unsupported("CIL_TUNABLEIF"); |
| break; |
| case CIL_DEFAULTUSER: |
| rc = cil_write_unsupported("CIL_DEFAULTUSER"); |
| break; |
| case CIL_DEFAULTROLE: |
| rc = cil_write_unsupported("CIL_DEFAULTROLE"); |
| break; |
| case CIL_DEFAULTTYPE: |
| rc = cil_write_unsupported("CIL_DEFAULTTYPE"); |
| break; |
| case CIL_DEFAULTRANGE: |
| rc = cil_write_unsupported("CIL_DEFAULTRANGE"); |
| break; |
| case CIL_SELINUXUSER: |
| rc = cil_write_unsupported("CIL_SELINUXUSER"); |
| break; |
| case CIL_SELINUXUSERDEFAULT: |
| rc = cil_write_unsupported("CIL_SELINUXUSERDEFAULT"); |
| break; |
| case CIL_HANDLEUNKNOWN: |
| rc = cil_write_handleunknown(node, cil_out); |
| break; |
| case CIL_MLS: |
| rc = cil_write_mls(node, cil_out); |
| break; |
| case CIL_SRC_INFO: |
| break; |
| case CIL_NONE: |
| // TODO: add proper removal support |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| default: |
| cil_log(CIL_ERR, "Unknown AST flavor: %d.\n", node->flavor); |
| rc = SEPOL_ERR; |
| goto exit; |
| break; |
| } |
| exit: |
| return rc; |
| } |
| |
| static int __cil_write_last_child_helper(struct cil_tree_node *node, void *extra_args) |
| { |
| int rc = SEPOL_ERR; |
| struct cil_args_write *args = NULL; |
| FILE *cil_out = NULL; |
| |
| if (node == NULL || extra_args == NULL) { |
| goto exit; |
| } |
| |
| args = extra_args; |
| cil_out = args->cil_out; |
| |
| if (node->parent && node->parent->flavor != CIL_ROOT && node->parent->flavor != CIL_SRC_INFO) { |
| fprintf(cil_out,")"); |
| } |
| rc = SEPOL_OK; |
| exit: |
| return rc; |
| } |
| |
| /* main exported function */ |
| int cil_write_ast(struct cil_db *db, const char* path) { |
| int rc = SEPOL_ERR; |
| struct cil_args_write extra_args; |
| FILE *cil_out = NULL; |
| |
| cil_out = fopen(path, "we"); |
| if (cil_out == NULL) { |
| cil_log(CIL_ERR, "Failure opening output file for writing AST\n"); |
| rc = SEPOL_ERR; |
| goto exit; |
| } |
| |
| extra_args.cil_out = cil_out; |
| extra_args.db = db; |
| rc = cil_tree_walk(db->ast->root, __cil_write_node_helper, |
| __cil_write_first_child_helper, |
| __cil_write_last_child_helper, |
| &extra_args); |
| if (rc != SEPOL_OK) { |
| cil_log(CIL_INFO, "cil_tree_walk failed, rc: %d\n", rc); |
| goto exit; |
| } |
| |
| exit: |
| fclose(cil_out); |
| cil_out = NULL; |
| return rc; |
| } |