| /* |
| * Copyright 2011 Tresys Technology, LLC. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS |
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * The views and conclusions contained in the software and documentation are those |
| * of the authors and should not be interpreted as representing official policies, |
| * either expressed or implied, of Tresys Technology, LLC. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <unistd.h> |
| #include <inttypes.h> |
| |
| #include <sepol/policydb/conditional.h> |
| #include <sepol/errcodes.h> |
| |
| #include "cil_internal.h" |
| #include "cil_flavor.h" |
| #include "cil_find.h" |
| #include "cil_mem.h" |
| #include "cil_tree.h" |
| #include "cil_list.h" |
| #include "cil_symtab.h" |
| |
| |
| enum cil_statement_list { |
| CIL_LIST_COMMON = 1, |
| CIL_LIST_DEFAULT_USER, |
| CIL_LIST_DEFAULT_ROLE, |
| CIL_LIST_DEFAULT_TYPE, |
| CIL_LIST_DEFAULT_RANGE, |
| CIL_LIST_SENSALIAS, |
| CIL_LIST_CATALIAS, |
| CIL_LIST_MLSCONSTRAIN, |
| CIL_LIST_MLSVALIDATETRANS, |
| CIL_LIST_POLICYCAP, |
| CIL_LIST_TYPEATTRIBUTE, |
| CIL_LIST_ROLEATTRIBUTE, |
| CIL_LIST_BOOL, |
| CIL_LIST_TYPE, |
| CIL_LIST_TYPEALIAS, |
| CIL_LIST_ROLE, |
| CIL_LIST_ROLEALLOW, |
| CIL_LIST_ROLETRANSITION, |
| CIL_LIST_USER, |
| CIL_LIST_CONSTRAINT, |
| CIL_LIST_VALIDATETRANS, |
| CIL_LIST_NUM_LISTS |
| }; |
| |
| static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| { |
| struct cil_list **lists; |
| int kind = 0; |
| |
| lists = (struct cil_list **)extra_args; |
| |
| switch (node->flavor) { |
| case CIL_BLOCK: { |
| struct cil_block *blk = node->data; |
| if (blk->is_abstract == CIL_TRUE) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| } |
| break; |
| } |
| case CIL_MACRO: |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| case CIL_BOOLEANIF: |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| case CIL_COMMON: |
| kind = CIL_LIST_COMMON; |
| break; |
| case CIL_DEFAULTUSER: |
| kind = CIL_LIST_DEFAULT_USER; |
| break; |
| case CIL_DEFAULTROLE: |
| kind = CIL_LIST_DEFAULT_ROLE; |
| break; |
| case CIL_DEFAULTTYPE: |
| kind = CIL_LIST_DEFAULT_TYPE; |
| break; |
| case CIL_DEFAULTRANGE: |
| kind = CIL_LIST_DEFAULT_RANGE; |
| break; |
| case CIL_SENSALIAS: |
| kind = CIL_LIST_SENSALIAS; |
| break; |
| case CIL_CATALIAS: |
| kind = CIL_LIST_CATALIAS; |
| break; |
| case CIL_MLSCONSTRAIN: |
| kind = CIL_LIST_MLSCONSTRAIN; |
| break; |
| case CIL_MLSVALIDATETRANS: |
| kind = CIL_LIST_MLSVALIDATETRANS; |
| break; |
| case CIL_POLICYCAP: |
| kind = CIL_LIST_POLICYCAP; |
| break; |
| case CIL_TYPEATTRIBUTE: { |
| struct cil_typeattribute *attr = node->data; |
| if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) { |
| kind = CIL_LIST_TYPEATTRIBUTE; |
| } |
| break; |
| } |
| case CIL_ROLEATTRIBUTE: { |
| struct cil_roleattribute *attr = node->data; |
| if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) { |
| kind = CIL_LIST_ROLEATTRIBUTE; |
| } |
| break; |
| } |
| case CIL_BOOL: |
| kind = CIL_LIST_BOOL; |
| break; |
| case CIL_TYPE: |
| kind = CIL_LIST_TYPE; |
| break; |
| case CIL_TYPEALIAS: |
| kind = CIL_LIST_TYPEALIAS; |
| break; |
| case CIL_ROLE: { |
| struct cil_role *role = node->data; |
| if (strcmp(role->datum.fqn, "object_r") != 0) { |
| kind = CIL_LIST_ROLE; |
| } |
| break; |
| } |
| case CIL_ROLEALLOW: |
| kind = CIL_LIST_ROLEALLOW; |
| break; |
| case CIL_ROLETRANSITION: |
| kind = CIL_LIST_ROLETRANSITION; |
| break; |
| case CIL_USER: |
| kind = CIL_LIST_USER; |
| break; |
| case CIL_CONSTRAIN: |
| kind = CIL_LIST_CONSTRAINT; |
| break; |
| case CIL_VALIDATETRANS: |
| kind = CIL_LIST_VALIDATETRANS; |
| break; |
| default: |
| break; |
| } |
| |
| if (kind > 0) { |
| cil_list_append(lists[kind], node->flavor, node->data); |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static void cil_gather_statements(struct cil_tree_node *start, struct cil_list *lists[]) |
| { |
| cil_tree_walk(start, __cil_gather_statements_helper, NULL, NULL, lists); |
| } |
| |
| static void cil_simple_rules_to_policy(FILE *out, struct cil_list *rules, const char *kind) |
| { |
| struct cil_list_item *i1; |
| |
| cil_list_for_each(i1, rules) { |
| fprintf(out, "%s %s;\n", kind, DATUM(i1->data)->fqn); |
| } |
| } |
| |
| static void cil_cats_to_policy(FILE *out, struct cil_cats *cats) |
| { |
| const char *lead = ""; |
| struct cil_cat *first = NULL, *last = NULL, *cat; |
| struct cil_list_item *i1; |
| |
| cil_list_for_each(i1, cats->datum_expr) { |
| cat = i1->data; |
| if (first == NULL) { |
| first = cat; |
| } else if (last == NULL) { |
| if (cat->value == first->value + 1) { |
| last = cat; |
| } else { |
| fprintf(out, "%s%s", lead, DATUM(first)->fqn); |
| lead = ","; |
| first = cat; |
| } |
| } else if (cat->value == last->value + 1) { |
| last = cat; |
| } else { |
| fprintf(out, "%s%s", lead, DATUM(first)->fqn); |
| lead = ","; |
| if (last->value >= first->value + 1) { |
| fprintf(out, "."); |
| } else { |
| fprintf(out, ","); |
| } |
| fprintf(out, "%s", DATUM(last)->fqn); |
| first = cat; |
| last = NULL; |
| } |
| } |
| if (first) { |
| fprintf(out, "%s%s", lead, DATUM(first)->fqn); |
| if (last != NULL) { |
| if (last->value >= first->value + 1) { |
| fprintf(out, "."); |
| } else { |
| fprintf(out, ","); |
| } |
| fprintf(out, "%s", DATUM(last)->fqn); |
| } |
| } |
| } |
| |
| static void cil_level_to_policy(FILE *out, struct cil_level *level) |
| { |
| fprintf(out, "%s", DATUM(level->sens)->fqn); |
| if (level->cats != NULL) { |
| fprintf(out, ":"); |
| cil_cats_to_policy(out, level->cats); |
| } |
| } |
| |
| static int cil_levels_simple_and_equal(struct cil_level *l1, struct cil_level *l2) |
| { |
| /* Mostly just want to detect s0 - s0 ranges */ |
| if (l1 == l2) |
| return CIL_TRUE; |
| |
| if (l1->sens == l2->sens && (l1->cats == NULL && l2->cats == NULL)) |
| return CIL_TRUE; |
| |
| return CIL_FALSE; |
| } |
| |
| static void cil_levelrange_to_policy(FILE *out, struct cil_levelrange *lvlrange) |
| { |
| cil_level_to_policy(out, lvlrange->low); |
| if (cil_levels_simple_and_equal(lvlrange->low, lvlrange->high) == CIL_FALSE) { |
| fprintf(out, " - "); |
| cil_level_to_policy(out, lvlrange->high); |
| } |
| } |
| |
| static void cil_context_to_policy(FILE *out, struct cil_context *context, int mls) |
| { |
| fprintf(out, "%s:", DATUM(context->user)->fqn); |
| fprintf(out, "%s:", DATUM(context->role)->fqn); |
| fprintf(out, "%s", DATUM(context->type)->fqn); |
| if (mls) { |
| fprintf(out, ":"); |
| cil_levelrange_to_policy(out, context->range); |
| } |
| } |
| |
| static void cil_cond_expr_to_policy(FILE *out, struct cil_list *expr, int first) |
| { |
| struct cil_list_item *i1 = expr->head; |
| |
| if (i1->flavor == CIL_OP) { |
| enum cil_flavor op = (enum cil_flavor)i1->data; |
| fprintf(out, "("); |
| switch (op) { |
| case CIL_NOT: |
| fprintf(out, "! "); |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| break; |
| case CIL_OR: |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| fprintf(out, " || "); |
| cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); |
| break; |
| case CIL_AND: |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| fprintf(out, " && "); |
| cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); |
| break; |
| case CIL_XOR: |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| fprintf(out, " ^ "); |
| cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); |
| break; |
| case CIL_EQ: |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| fprintf(out, " == "); |
| cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); |
| break; |
| case CIL_NEQ: |
| cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); |
| fprintf(out, " != "); |
| cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); |
| break; |
| default: |
| fprintf(out, "???"); |
| break; |
| } |
| fprintf(out, ")"); |
| } else if (i1->flavor == CIL_DATUM) { |
| if (first == CIL_TRUE) { |
| fprintf(out, "("); |
| } |
| fprintf(out, "%s", DATUM(i1->data)->fqn); |
| if (first == CIL_TRUE) { |
| fprintf(out, ")"); |
| } |
| } else if (i1->flavor == CIL_LIST) { |
| cil_cond_expr_to_policy(out, i1->data, CIL_FALSE); |
| } else { |
| fprintf(out, "???"); |
| } |
| } |
| |
| static size_t __cil_userattribute_len(struct cil_db *db, struct cil_userattribute *attr) |
| { |
| ebitmap_node_t *unode; |
| unsigned int i; |
| size_t len = 0; |
| |
| ebitmap_for_each_bit(attr->users, unode, i) { |
| if (!ebitmap_get_bit(attr->users, i)) |
| continue; |
| len += strlen(DATUM(db->val_to_user[i])->fqn); |
| len++; |
| } |
| |
| return len; |
| } |
| |
| static size_t __cil_cons_leaf_operand_len(struct cil_db *db, struct cil_list_item *operand) |
| { |
| struct cil_list_item *i1; |
| enum cil_flavor flavor = operand->flavor; |
| size_t len = 0; |
| |
| if (flavor == CIL_CONS_OPERAND) { |
| len = 2; |
| } else if (flavor == CIL_DATUM) { |
| struct cil_tree_node *node = NODE(operand->data); |
| if (node->flavor == CIL_USERATTRIBUTE) { |
| len = __cil_userattribute_len(db, operand->data); |
| len++; /* "{" */ |
| } else { |
| len = strlen(DATUM(operand->data)->fqn); |
| } |
| } else if (flavor == CIL_LIST) { |
| len = 1; /* "{" */ |
| cil_list_for_each(i1, (struct cil_list *)operand->data) { |
| struct cil_tree_node *node = NODE(operand->data); |
| if (node->flavor == CIL_USERATTRIBUTE) { |
| len = __cil_userattribute_len(db, operand->data); |
| } else { |
| len += strlen(DATUM(operand->data)->fqn); |
| len++; /* " " or "}" */ |
| } |
| } |
| } |
| |
| return len; |
| } |
| |
| static size_t __cil_cons_leaf_op_len(struct cil_list_item *op) |
| { |
| enum cil_flavor flavor = (enum cil_flavor)op->data; |
| size_t len; |
| |
| switch (flavor) { |
| case CIL_EQ: |
| len = 4; /* " == " */ |
| break; |
| case CIL_NEQ: |
| len = 4; /* " != " */ |
| break; |
| case CIL_CONS_DOM: |
| len = 5; /* " dom " */ |
| break; |
| case CIL_CONS_DOMBY: |
| len = 7; /* " domby " */ |
| break; |
| case CIL_CONS_INCOMP: |
| len = 8; /* " incomp " */ |
| break; |
| default: |
| /* Should be impossible to be here */ |
| len = 5; /* " ??? " */ |
| } |
| |
| return len; |
| } |
| |
| static size_t cil_cons_expr_len(struct cil_db *db, struct cil_list *cons_expr) |
| { |
| struct cil_list_item *i1; |
| enum cil_flavor op; |
| size_t len; |
| |
| i1 = cons_expr->head; |
| |
| op = (enum cil_flavor)i1->data; |
| switch (op) { |
| case CIL_NOT: |
| len = 6; /* "(not )" */ |
| len += cil_cons_expr_len(db, i1->next->data); |
| break; |
| case CIL_AND: |
| len = 7; /* "( and )" */ |
| len += cil_cons_expr_len(db, i1->next->data); |
| len += cil_cons_expr_len(db, i1->next->next->data); |
| break; |
| case CIL_OR: |
| len = 6; /* "( or )" */ |
| len += cil_cons_expr_len(db, i1->next->data); |
| len += cil_cons_expr_len(db, i1->next->next->data); |
| break; |
| default: |
| len = 2; /* "()" */ |
| len += __cil_cons_leaf_operand_len(db, i1->next); |
| len += __cil_cons_leaf_op_len(i1); |
| len += __cil_cons_leaf_operand_len(db, i1->next->next); |
| } |
| |
| return len; |
| } |
| |
| static char *__cil_userattribute_to_string(struct cil_db *db, struct cil_userattribute *attr, char *new) |
| { |
| ebitmap_node_t *unode; |
| unsigned int i; |
| char *str; |
| size_t len; |
| |
| ebitmap_for_each_bit(attr->users, unode, i) { |
| if (!ebitmap_get_bit(attr->users, i)) |
| continue; |
| str = DATUM(db->val_to_user[i])->fqn; |
| len = strlen(str); |
| memcpy(new, str, len); |
| new += len; |
| *new++ = ' '; |
| } |
| |
| return new; |
| } |
| |
| static char *__cil_cons_leaf_operand_to_string(struct cil_db *db, struct cil_list_item *operand, char *new) |
| { |
| struct cil_list_item *i1; |
| enum cil_flavor flavor = operand->flavor; |
| const char *o_str; |
| size_t o_len; |
| |
| if (flavor == CIL_CONS_OPERAND) { |
| enum cil_flavor o_flavor = (enum cil_flavor)operand->data; |
| switch (o_flavor) { |
| case CIL_CONS_U1: |
| o_str = "u1"; |
| break; |
| case CIL_CONS_U2: |
| o_str = "u2"; |
| break; |
| case CIL_CONS_U3: |
| o_str = "u3"; |
| break; |
| case CIL_CONS_R1: |
| o_str = "r1"; |
| break; |
| case CIL_CONS_R2: |
| o_str = "r2"; |
| break; |
| case CIL_CONS_R3: |
| o_str = "r3"; |
| break; |
| case CIL_CONS_T1: |
| o_str = "t1"; |
| break; |
| case CIL_CONS_T2: |
| o_str = "t2"; |
| break; |
| case CIL_CONS_T3: |
| o_str = "t3"; |
| break; |
| case CIL_CONS_L1: |
| o_str = "l1"; |
| break; |
| case CIL_CONS_L2: |
| o_str = "l2"; |
| break; |
| case CIL_CONS_H1: |
| o_str = "h1"; |
| break; |
| case CIL_CONS_H2: |
| o_str = "h2"; |
| break; |
| default: |
| /* Impossible */ |
| o_str = "??"; |
| } |
| strcpy(new, o_str); |
| new += 2; |
| } else if (flavor == CIL_DATUM) { |
| struct cil_tree_node *node = NODE(operand->data); |
| if (node->flavor == CIL_USERATTRIBUTE) { |
| *new++ = '{'; |
| new = __cil_userattribute_to_string(db, operand->data, new); |
| new--; |
| *new++ = '}'; |
| } else { |
| o_str = DATUM(operand->data)->fqn; |
| o_len = strlen(o_str); |
| memcpy(new, o_str, o_len); |
| new += o_len; |
| } |
| } else if (flavor == CIL_LIST) { |
| *new++ = '{'; |
| cil_list_for_each(i1, (struct cil_list *)operand->data) { |
| struct cil_tree_node *node = NODE(operand->data); |
| if (node->flavor == CIL_USERATTRIBUTE) { |
| new = __cil_userattribute_to_string(db, operand->data, new); |
| } else { |
| o_str = DATUM(operand->data)->fqn; |
| o_len = strlen(o_str); |
| memcpy(new, o_str, o_len); |
| new += o_len; |
| *new++ = ' '; |
| } |
| } |
| new--; |
| *new++ = '}'; |
| } |
| |
| return new; |
| } |
| |
| static char *__cil_cons_leaf_op_to_string(struct cil_list_item *op, char *new) |
| { |
| enum cil_flavor flavor = (enum cil_flavor)op->data; |
| const char *op_str; |
| size_t len; |
| |
| switch (flavor) { |
| case CIL_EQ: |
| op_str = " == "; |
| len = 4; |
| break; |
| case CIL_NEQ: |
| op_str = " != "; |
| len = 4; |
| break; |
| case CIL_CONS_DOM: |
| op_str = " dom "; |
| len = 5; |
| break; |
| case CIL_CONS_DOMBY: |
| op_str = " domby "; |
| len = 7; |
| break; |
| case CIL_CONS_INCOMP: |
| op_str = " incomp "; |
| len = 8; |
| break; |
| default: |
| /* Should be impossible to be here */ |
| op_str = " ??? "; |
| len = 5; |
| } |
| |
| strcpy(new, op_str); |
| new += len; |
| |
| return new; |
| } |
| |
| static char *__cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr, char *new) |
| { |
| struct cil_list_item *i1; |
| enum cil_flavor op; |
| |
| i1 = cons_expr->head; |
| |
| op = (enum cil_flavor)i1->data; |
| switch (op) { |
| case CIL_NOT: |
| *new++ = '('; |
| strcpy(new, "not "); |
| new += 4; |
| new = __cil_cons_expr_to_string(db, i1->next->data, new); |
| *new++ = ')'; |
| break; |
| case CIL_AND: |
| *new++ = '('; |
| new = __cil_cons_expr_to_string(db, i1->next->data, new); |
| strcpy(new, " and "); |
| new += 5; |
| new = __cil_cons_expr_to_string(db, i1->next->next->data, new); |
| *new++ = ')'; |
| break; |
| case CIL_OR: |
| *new++ = '('; |
| new = __cil_cons_expr_to_string(db, i1->next->data, new); |
| strcpy(new, " or "); |
| new += 4; |
| new = __cil_cons_expr_to_string(db, i1->next->next->data, new); |
| *new++ = ')'; |
| break; |
| default: |
| *new++ = '('; |
| new = __cil_cons_leaf_operand_to_string(db, i1->next, new); |
| new = __cil_cons_leaf_op_to_string(i1, new); |
| new = __cil_cons_leaf_operand_to_string(db, i1->next->next, new); |
| *new++ = ')'; |
| } |
| |
| return new; |
| } |
| |
| static char *cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr) |
| { |
| char *new, *tail; |
| size_t len = cil_cons_expr_len(db, cons_expr); |
| |
| new = cil_malloc(len+1); |
| tail = __cil_cons_expr_to_string(db, cons_expr, new); |
| *tail = '\0'; |
| |
| return new; |
| } |
| |
| static void cil_classperms_to_string(struct cil_classperms *classperms, struct cil_list *classperms_strs) |
| { |
| struct cil_list_item *i1; |
| size_t len = 0; |
| char *new, *curr; |
| |
| len += strlen(DATUM(classperms->class)->fqn) + 1; |
| cil_list_for_each(i1, classperms->perms) { |
| len += strlen(DATUM(i1->data)->fqn) + 1; |
| } |
| len += 4; /* for "{ " and " }" */ |
| |
| new = cil_malloc(len); |
| curr = new; |
| |
| curr[len-1] = '\0'; |
| |
| len = strlen(DATUM(classperms->class)->fqn); |
| memcpy(curr, DATUM(classperms->class)->fqn, len); |
| curr += len; |
| *curr++ = ' '; |
| |
| *curr++ = '{'; |
| *curr++ = ' '; |
| cil_list_for_each(i1, classperms->perms) { |
| len = strlen(DATUM(i1->data)->fqn); |
| memcpy(curr, DATUM(i1->data)->fqn, len); |
| curr += len; |
| *curr++ = ' '; |
| } |
| *curr++ = '}'; |
| |
| cil_list_append(classperms_strs, CIL_STRING, new); |
| } |
| |
| static void cil_classperms_to_strings(struct cil_list *classperms, struct cil_list *classperms_strs) |
| { |
| struct cil_list_item *i1; |
| |
| cil_list_for_each(i1, classperms) { |
| if (i1->flavor == CIL_CLASSPERMS) { |
| struct cil_classperms *cp = i1->data; |
| if (FLAVOR(cp->class) == CIL_CLASS) { |
| cil_classperms_to_string(cp, classperms_strs); |
| } else { /* MAP */ |
| struct cil_list_item *i2 = NULL; |
| cil_list_for_each(i2, cp->perms) { |
| struct cil_perm *cmp = i2->data; |
| cil_classperms_to_strings(cmp->classperms, classperms_strs); |
| } |
| } |
| } else { /* SET */ |
| struct cil_classperms_set *cp_set = i1->data; |
| struct cil_classpermission *cp = cp_set->set; |
| cil_classperms_to_strings(cp->classperms, classperms_strs); |
| } |
| } |
| } |
| |
| static void cil_class_decls_to_policy(FILE *out, struct cil_list *classorder) |
| { |
| struct cil_list_item *i1; |
| |
| cil_list_for_each(i1, classorder) { |
| fprintf(out, "class %s\n", DATUM(i1->data)->fqn); |
| } |
| } |
| |
| static void cil_sid_decls_to_policy(FILE *out, struct cil_list *sidorder) |
| { |
| struct cil_list_item *i1; |
| |
| cil_list_for_each(i1, sidorder) { |
| fprintf(out, "sid %s\n", DATUM(i1->data)->fqn); |
| } |
| } |
| |
| static void cil_commons_to_policy(FILE *out, struct cil_list *commons) |
| { |
| struct cil_list_item *i1; |
| struct cil_class* common; |
| struct cil_tree_node *node; |
| struct cil_tree_node *perm; |
| |
| cil_list_for_each(i1, commons) { |
| common = i1->data; |
| node = NODE(&common->datum); |
| perm = node->cl_head; |
| |
| fprintf(out, "common %s {", common->datum.fqn); |
| while (perm != NULL) { |
| fprintf(out, "%s ", DATUM(perm->data)->fqn); |
| perm = perm->next; |
| } |
| fprintf(out, "}\n"); |
| } |
| } |
| |
| static void cil_classes_to_policy(FILE *out, struct cil_list *classorder) |
| { |
| struct cil_list_item *i1; |
| struct cil_class *class; |
| struct cil_tree_node *node; |
| |
| cil_list_for_each(i1, classorder) { |
| class = i1->data; |
| node = NODE(&class->datum); |
| |
| fprintf(out, "class %s", class->datum.fqn); |
| if (class->common != NULL) { |
| fprintf(out, " inherits %s", class->common->datum.fqn); |
| } |
| if (node->cl_head != NULL) { |
| struct cil_tree_node *perm = node->cl_head; |
| fprintf(out, " {"); |
| while (perm != NULL) { |
| fprintf(out, " %s", DATUM(perm->data)->fqn); |
| perm = perm->next; |
| } |
| fprintf(out, " }"); |
| } |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_defaults_to_policy(FILE *out, struct cil_list *defaults, const char *kind) |
| { |
| struct cil_list_item *i1, *i2, *i3; |
| struct cil_default *def; |
| struct cil_list *class_list; |
| |
| cil_list_for_each(i1, defaults) { |
| def = i1->data; |
| fprintf(out, "%s {",kind); |
| cil_list_for_each(i2, def->class_datums) { |
| class_list = cil_expand_class(i2->data); |
| cil_list_for_each(i3, class_list) { |
| fprintf(out, " %s", DATUM(i3->data)->fqn); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| fprintf(out, " }"); |
| if (def->object == CIL_DEFAULT_SOURCE) { |
| fprintf(out," %s",CIL_KEY_SOURCE); |
| } else if (def->object == CIL_DEFAULT_TARGET) { |
| fprintf(out," %s",CIL_KEY_TARGET); |
| } |
| fprintf(out,";\n"); |
| } |
| } |
| |
| static void cil_default_ranges_to_policy(FILE *out, struct cil_list *defaults) |
| { |
| struct cil_list_item *i1, *i2, *i3; |
| struct cil_defaultrange *def; |
| struct cil_list *class_list; |
| |
| cil_list_for_each(i1, defaults) { |
| def = i1->data; |
| fprintf(out, "default_range {"); |
| cil_list_for_each(i2, def->class_datums) { |
| class_list = cil_expand_class(i2->data); |
| cil_list_for_each(i3, class_list) { |
| fprintf(out, " %s", DATUM(i3->data)->fqn); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| fprintf(out, " }"); |
| |
| switch (def->object_range) { |
| case CIL_DEFAULT_SOURCE_LOW: |
| fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW); |
| break; |
| case CIL_DEFAULT_SOURCE_HIGH: |
| fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_HIGH); |
| break; |
| case CIL_DEFAULT_SOURCE_LOW_HIGH: |
| fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW_HIGH); |
| break; |
| case CIL_DEFAULT_TARGET_LOW: |
| fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW); |
| break; |
| case CIL_DEFAULT_TARGET_HIGH: |
| fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_HIGH); |
| break; |
| case CIL_DEFAULT_TARGET_LOW_HIGH: |
| fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW_HIGH); |
| break; |
| default: |
| break; |
| } |
| fprintf(out,";\n"); |
| } |
| } |
| |
| static void cil_sensitivities_to_policy(FILE *out, struct cil_list *sensorder, struct cil_list *all_aliases) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_sens *sens; |
| struct cil_list *aliases = NULL; |
| struct cil_alias *alias; |
| struct cil_sens *actual; |
| int num_aliases; |
| |
| cil_list_for_each(i1, sensorder) { |
| sens = i1->data; |
| num_aliases = 0; |
| cil_list_for_each(i2, all_aliases) { |
| alias = i2->data; |
| actual = alias->actual; |
| if (sens == actual) { |
| if (num_aliases == 0) { |
| cil_list_init(&aliases, CIL_LIST); |
| } |
| cil_list_append(aliases, CIL_SENSALIAS, alias); |
| num_aliases++; |
| } |
| } |
| fprintf(out, "sensitivity %s", sens->datum.fqn); |
| if (num_aliases > 0) { |
| fprintf(out, " alias"); |
| if (num_aliases > 1) { |
| fprintf(out, " {"); |
| } |
| cil_list_for_each(i2, aliases) { |
| alias = i2->data; |
| fprintf(out, " %s", alias->datum.fqn); |
| } |
| if (num_aliases > 1) { |
| fprintf(out, " }"); |
| } |
| cil_list_destroy(&aliases, CIL_FALSE); |
| } |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_dominance_to_policy(FILE *out, struct cil_list *sensorder) |
| { |
| struct cil_list_item *item; |
| struct cil_sens *sens; |
| |
| fprintf(out, "dominance {"); |
| cil_list_for_each(item, sensorder) { |
| sens = item->data; |
| fprintf(out, " %s", sens->datum.fqn); |
| } |
| fprintf(out, " }\n"); |
| } |
| |
| static void cil_categories_to_policy(FILE *out, struct cil_list *catorder, struct cil_list *all_aliases) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_sens *cat; |
| struct cil_list *aliases = NULL; |
| struct cil_alias *alias; |
| struct cil_sens *actual; |
| int num_aliases; |
| |
| cil_list_for_each(i1, catorder) { |
| cat = i1->data; |
| num_aliases = 0; |
| cil_list_for_each(i2, all_aliases) { |
| alias = i2->data; |
| actual = alias->actual; |
| if (cat == actual) { |
| if (num_aliases == 0) { |
| cil_list_init(&aliases, CIL_LIST); |
| } |
| cil_list_append(aliases, CIL_CATALIAS, alias); |
| num_aliases++; |
| } |
| } |
| fprintf(out, "category %s",cat->datum.fqn); |
| if (num_aliases > 0) { |
| fprintf(out, " alias"); |
| if (num_aliases > 1) { |
| fprintf(out, " { "); |
| } |
| cil_list_for_each(i2, aliases) { |
| alias = i2->data; |
| fprintf(out, " %s", alias->datum.fqn); |
| } |
| if (num_aliases > 1) { |
| fprintf(out, " }"); |
| } |
| cil_list_destroy(&aliases, CIL_FALSE); |
| } |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_levels_to_policy(FILE *out, struct cil_list *sensorder) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_sens *sens; |
| |
| cil_list_for_each(i1, sensorder) { |
| sens = i1->data; |
| if (sens->cats_list) { |
| cil_list_for_each(i2, sens->cats_list) { |
| fprintf(out, "level %s:",sens->datum.fqn); |
| cil_cats_to_policy(out, i2->data); |
| fprintf(out,";\n"); |
| } |
| } else { |
| fprintf(out, "level %s;\n",sens->datum.fqn); |
| } |
| } |
| } |
| |
| static void cil_mlsconstrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *mlsconstrains) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_constrain *cons; |
| struct cil_list *classperms_strs; |
| char *cp_str; |
| char *expr_str; |
| |
| cil_list_for_each(i1, mlsconstrains) { |
| cons = i1->data; |
| cil_list_init(&classperms_strs, CIL_LIST); |
| cil_classperms_to_strings(cons->classperms, classperms_strs); |
| expr_str = cil_cons_expr_to_string(db, cons->datum_expr); |
| cil_list_for_each(i2, classperms_strs) { |
| cp_str = i2->data; |
| fprintf(out, "mlsconstrain %s %s;\n", cp_str, expr_str); |
| free(cp_str); |
| } |
| free(expr_str); |
| cil_list_destroy(&classperms_strs, CIL_FALSE); |
| } |
| } |
| |
| static void cil_validatetrans_to_policy(FILE *out, struct cil_db *db, struct cil_list *validatetrans, char *kind) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_validatetrans *trans; |
| struct cil_list *class_list; |
| struct cil_class *class; |
| char *expr_str; |
| |
| cil_list_for_each(i1, validatetrans) { |
| trans = i1->data; |
| class_list = cil_expand_class(trans->class); |
| expr_str = cil_cons_expr_to_string(db, trans->datum_expr); |
| cil_list_for_each(i2, class_list) { |
| class = i2->data; |
| fprintf(out, "%s %s %s;\n", kind, class->datum.fqn, expr_str); |
| } |
| free(expr_str); |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| } |
| |
| static void cil_bools_to_policy(FILE *out, struct cil_list *bools) |
| { |
| struct cil_list_item *i1; |
| struct cil_bool *bool; |
| const char *value; |
| |
| cil_list_for_each(i1, bools) { |
| bool = i1->data; |
| value = bool->value ? "true" : "false"; |
| fprintf(out, "bool %s %s;\n", bool->datum.fqn, value); |
| } |
| } |
| |
| static void cil_typealiases_to_policy(FILE *out, struct cil_list *types, struct cil_list *all_aliases) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_type *type; |
| struct cil_list *aliases = NULL; |
| struct cil_alias *alias; |
| struct cil_type *actual; |
| int num_aliases; |
| |
| cil_list_for_each(i1, types) { |
| type = i1->data; |
| num_aliases = 0; |
| cil_list_for_each(i2, all_aliases) { |
| alias = i2->data; |
| actual = alias->actual; |
| if (type == actual) { |
| if (num_aliases == 0) { |
| cil_list_init(&aliases, CIL_LIST); |
| } |
| cil_list_append(aliases, CIL_TYPEALIAS, alias); |
| num_aliases++; |
| } |
| } |
| if (num_aliases > 0) { |
| fprintf(out, "typealias %s alias", type->datum.fqn); |
| if (num_aliases > 1) { |
| fprintf(out, " {"); |
| } |
| cil_list_for_each(i2, aliases) { |
| alias = i2->data; |
| fprintf(out, " %s", alias->datum.fqn); |
| } |
| if (num_aliases > 1) { |
| fprintf(out, " }"); |
| } |
| fprintf(out, ";\n"); |
| cil_list_destroy(&aliases, CIL_FALSE); |
| } |
| } |
| } |
| |
| static void cil_typebounds_to_policy(FILE *out, struct cil_list *types) |
| { |
| struct cil_list_item *i1; |
| struct cil_type *child; |
| struct cil_type *parent; |
| |
| cil_list_for_each(i1, types) { |
| child = i1->data; |
| if (child->bounds != NULL) { |
| parent = child->bounds; |
| fprintf(out, "typebounds %s %s;\n", parent->datum.fqn, child->datum.fqn); |
| } |
| } |
| } |
| |
| static void cil_typeattributes_to_policy(FILE *out, struct cil_list *types, struct cil_list *attributes) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_type *type; |
| struct cil_typeattribute *attribute; |
| int first = CIL_TRUE; |
| |
| cil_list_for_each(i1, types) { |
| type = i1->data; |
| cil_list_for_each(i2, attributes) { |
| attribute = i2->data; |
| if (!attribute->keep) |
| continue; |
| if (ebitmap_get_bit(attribute->types, type->value)) { |
| if (first) { |
| fprintf(out, "typeattribute %s %s", type->datum.fqn, attribute->datum.fqn); |
| first = CIL_FALSE; |
| } else { |
| fprintf(out, ", %s", attribute->datum.fqn); |
| } |
| } |
| } |
| if (!first) { |
| fprintf(out, ";\n"); |
| first = CIL_TRUE; |
| } |
| } |
| } |
| |
| static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx) |
| { |
| ebitmap_node_t *node; |
| unsigned int i, first = 0, last = 0; |
| int need_first = CIL_TRUE, need_last = CIL_TRUE; |
| const char *kind; |
| |
| if (permx->kind == CIL_PERMX_KIND_IOCTL) { |
| kind = "ioctl"; |
| } else { |
| kind = "???"; |
| } |
| |
| fprintf(out, "%s %s {", DATUM(permx->obj)->fqn, kind); |
| |
| ebitmap_for_each_bit(permx->perms, node, i) { |
| if (!ebitmap_get_bit(permx->perms, i)) |
| continue; |
| if (need_first == CIL_TRUE) { |
| first = i; |
| need_first = CIL_FALSE; |
| } else if (need_last == CIL_TRUE) { |
| if (i == first+1) { |
| last = i; |
| need_last = CIL_FALSE; |
| } else { |
| fprintf(out, " 0x%x", first); |
| first = i; |
| } |
| } else if (i == last+1) { |
| last = i; |
| } else { |
| if (last > first+1) { |
| fprintf(out, " 0x%x-0x%x", first, last); |
| } else { |
| fprintf(out, " 0x%x 0x%x", first, last); |
| } |
| first = i; |
| need_last = CIL_TRUE; |
| } |
| } |
| if (need_first == CIL_FALSE) { |
| if (need_last == CIL_FALSE) { |
| fprintf(out, " 0x%x-0x%x", first, last); |
| } else { |
| fprintf(out, " 0x%x", first); |
| } |
| } |
| fprintf(out," }"); |
| } |
| |
| static void cil_av_rulex_to_policy(FILE *out, struct cil_avrule *rule) |
| { |
| const char *kind; |
| struct cil_symtab_datum *src, *tgt; |
| |
| src = rule->src; |
| tgt = rule->tgt; |
| |
| switch (rule->rule_kind) { |
| case CIL_AVRULE_ALLOWED: |
| kind = "allowxperm"; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| kind = "auditallowxperm"; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| kind = "dontauditxperm"; |
| break; |
| case CIL_AVRULE_NEVERALLOW: |
| kind = "neverallowxperm"; |
| break; |
| default: |
| kind = "???"; |
| break; |
| } |
| |
| fprintf(out, "%s %s %s : ", kind, src->fqn, tgt->fqn); |
| cil_xperms_to_policy(out, rule->perms.x.permx); |
| fprintf(out, ";\n"); |
| } |
| |
| static void cil_av_rule_to_policy(FILE *out, struct cil_avrule *rule) |
| { |
| const char *kind; |
| struct cil_symtab_datum *src, *tgt; |
| struct cil_list *classperms_strs; |
| struct cil_list_item *i1; |
| |
| src = rule->src; |
| tgt = rule->tgt; |
| |
| switch (rule->rule_kind) { |
| case CIL_AVRULE_ALLOWED: |
| kind = "allow"; |
| break; |
| case CIL_AVRULE_AUDITALLOW: |
| kind = "auditallow"; |
| break; |
| case CIL_AVRULE_DONTAUDIT: |
| kind = "dontaudit"; |
| break; |
| case CIL_AVRULE_NEVERALLOW: |
| kind = "neverallow"; |
| break; |
| default: |
| kind = "???"; |
| break; |
| } |
| |
| cil_list_init(&classperms_strs, CIL_LIST); |
| cil_classperms_to_strings(rule->perms.classperms, classperms_strs); |
| cil_list_for_each(i1, classperms_strs) { |
| char *cp_str = i1->data; |
| fprintf(out, "%s %s %s : %s;\n", kind, src->fqn, tgt->fqn, cp_str); |
| free(cp_str); |
| } |
| cil_list_destroy(&classperms_strs, CIL_FALSE); |
| } |
| |
| static void cil_type_rule_to_policy(FILE *out, struct cil_type_rule *rule) |
| { |
| const char *kind; |
| struct cil_symtab_datum *src, *tgt, *res; |
| struct cil_list *class_list; |
| struct cil_list_item *i1; |
| |
| src = rule->src; |
| tgt = rule->tgt; |
| res = rule->result; |
| |
| switch (rule->rule_kind) { |
| case CIL_TYPE_TRANSITION: |
| kind = "type_transition"; |
| break; |
| case CIL_TYPE_MEMBER: |
| kind = "type_member"; |
| break; |
| case CIL_TYPE_CHANGE: |
| kind = "type_change"; |
| break; |
| default: |
| kind = "???"; |
| break; |
| } |
| |
| class_list = cil_expand_class(rule->obj); |
| cil_list_for_each(i1, class_list) { |
| fprintf(out, "%s %s %s : %s %s;\n", kind, src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| |
| static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetransition *trans) |
| { |
| struct cil_symtab_datum *src, *tgt, *res; |
| struct cil_name *name; |
| struct cil_list *class_list; |
| struct cil_list_item *i1; |
| |
| src = trans->src; |
| tgt = trans->tgt; |
| name = trans->name; |
| res = trans->result; |
| |
| class_list = cil_expand_class(trans->obj); |
| cil_list_for_each(i1, class_list) { |
| fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| |
| static void cil_rangetransition_to_policy(FILE *out, struct cil_rangetransition *trans) |
| { |
| struct cil_symtab_datum *src, *exec; |
| struct cil_list *class_list; |
| struct cil_list_item *i1; |
| |
| src = trans->src; |
| exec = trans->exec; |
| |
| class_list = cil_expand_class(trans->obj); |
| cil_list_for_each(i1, class_list) { |
| fprintf(out, "range_transition %s %s : %s ", src->fqn, exec->fqn, DATUM(i1->data)->fqn); |
| cil_levelrange_to_policy(out, trans->range); |
| fprintf(out, ";\n"); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| |
| static void cil_typepermissive_to_policy(FILE *out, struct cil_typepermissive *rule) |
| { |
| fprintf(out, "permissive %s;\n", DATUM(rule->type)->fqn); |
| } |
| |
| struct block_te_rules_extra { |
| FILE *out; |
| enum cil_flavor flavor; |
| uint32_t rule_kind; |
| }; |
| |
| static int __cil_block_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| { |
| struct block_te_rules_extra *args = extra_args; |
| |
| switch (node->flavor) { |
| case CIL_BLOCK: { |
| struct cil_block *blk = node->data; |
| if (blk->is_abstract == CIL_TRUE) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| } |
| break; |
| } |
| case CIL_MACRO: |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| case CIL_BOOLEANIF: |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| case CIL_AVRULE: |
| case CIL_AVRULEX: |
| if (args->flavor == node->flavor) { |
| struct cil_avrule *rule = node->data; |
| if (args->rule_kind == rule->rule_kind) { |
| if (rule->is_extended) { |
| cil_av_rulex_to_policy(args->out, rule); |
| } else { |
| cil_av_rule_to_policy(args->out, rule); |
| } |
| } |
| } |
| break; |
| case CIL_TYPE_RULE: |
| if (args->flavor == node->flavor) { |
| struct cil_type_rule *rule = node->data; |
| if (args->rule_kind == rule->rule_kind) { |
| cil_type_rule_to_policy(args->out, rule); |
| } |
| } |
| |
| break; |
| case CIL_NAMETYPETRANSITION: |
| if (args->flavor == node->flavor) { |
| cil_nametypetransition_to_policy(args->out, node->data); |
| } |
| break; |
| case CIL_RANGETRANSITION: |
| if (args->flavor == node->flavor) { |
| cil_rangetransition_to_policy(args->out, node->data); |
| } |
| |
| break; |
| case CIL_TYPEPERMISSIVE: |
| if (args->flavor == node->flavor) { |
| cil_typepermissive_to_policy(args->out, node->data); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static void cil_block_te_rules_to_policy(FILE *out, struct cil_tree_node *start, int mls) |
| { |
| struct block_te_rules_extra args; |
| |
| args.out = out; |
| |
| args.flavor = CIL_TYPEPERMISSIVE; |
| args.rule_kind = 0; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| |
| args.flavor = CIL_AVRULE; |
| args.rule_kind = CIL_AVRULE_ALLOWED; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_AUDITALLOW; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_DONTAUDIT; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_NEVERALLOW; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| |
| args.flavor = CIL_AVRULEX; |
| args.rule_kind = CIL_AVRULE_ALLOWED; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_AUDITALLOW; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_DONTAUDIT; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_NEVERALLOW; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| |
| args.flavor = CIL_TYPE_RULE; |
| args.rule_kind = CIL_TYPE_TRANSITION; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_TYPE_MEMBER; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_TYPE_CHANGE; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| args.rule_kind = CIL_AVRULE_TYPE; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| |
| args.flavor = CIL_NAMETYPETRANSITION; |
| args.rule_kind = 0; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| |
| if (mls == CIL_TRUE) { |
| args.flavor = CIL_RANGETRANSITION; |
| args.rule_kind = 0; |
| cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); |
| } |
| } |
| |
| struct te_rules_extra { |
| FILE *out; |
| int mls; |
| }; |
| |
| static int __cil_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) |
| { |
| struct te_rules_extra *args = extra_args; |
| |
| switch (node->flavor) { |
| case CIL_BLOCK: { |
| struct cil_block *blk = node->data; |
| if (blk->is_abstract == CIL_TRUE) { |
| *finished = CIL_TREE_SKIP_HEAD; |
| } |
| break; |
| } |
| case CIL_MACRO: |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| case CIL_BOOLEANIF: { |
| struct cil_booleanif *bool = node->data; |
| struct cil_tree_node *n; |
| struct cil_condblock *cb; |
| |
| fprintf(args->out, "if "); |
| cil_cond_expr_to_policy(args->out, bool->datum_expr, CIL_TRUE); |
| fprintf(args->out," {\n"); |
| n = node->cl_head; |
| cb = n != NULL ? n->data : NULL; |
| if (cb && cb->flavor == CIL_CONDTRUE) { |
| cil_block_te_rules_to_policy(args->out, n, args->mls); |
| n = n->next; |
| cb = n != NULL ? n->data : NULL; |
| } |
| if (cb && cb->flavor == CIL_CONDFALSE) { |
| fprintf(args->out,"} else {\n"); |
| cil_block_te_rules_to_policy(args->out, n, args->mls); |
| } |
| fprintf(args->out,"}\n"); |
| *finished = CIL_TREE_SKIP_HEAD; |
| break; |
| } |
| default: |
| break; |
| } |
| |
| return SEPOL_OK; |
| } |
| |
| static void cil_te_rules_to_policy(FILE *out, struct cil_tree_node *head, int mls) |
| { |
| struct te_rules_extra args; |
| |
| args.out = out; |
| args.mls = mls; |
| |
| cil_block_te_rules_to_policy(out, head, mls); |
| cil_tree_walk(head, __cil_te_rules_to_policy_helper, NULL, NULL, &args); |
| } |
| |
| static void cil_roles_to_policy(FILE *out, struct cil_list *rules) |
| { |
| struct cil_list_item *i1; |
| struct cil_role *role; |
| |
| cil_list_for_each(i1, rules) { |
| role = i1->data; |
| if (strcmp(role->datum.fqn,"object_r") == 0) |
| continue; |
| fprintf(out, "role %s;\n", role->datum.fqn); |
| } |
| } |
| |
| static void cil_role_types_to_policy(FILE *out, struct cil_list *roles, struct cil_list *types) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_role *role; |
| struct cil_type *type; |
| int first = CIL_TRUE; |
| |
| cil_list_for_each(i1, roles) { |
| role = i1->data; |
| if (strcmp(role->datum.fqn,"object_r") == 0) |
| continue; |
| if (role->types) { |
| cil_list_for_each(i2, types) { |
| type = i2->data; |
| if (ebitmap_get_bit(role->types, type->value)) { |
| if (first) { |
| fprintf(out, "role %s types { %s", role->datum.fqn, type->datum.fqn); |
| first = CIL_FALSE; |
| } else { |
| fprintf(out, " %s", type->datum.fqn); |
| } |
| } |
| } |
| if (!first) { |
| fprintf(out, " }"); |
| first = CIL_TRUE; |
| } |
| fprintf(out, ";\n"); |
| } |
| } |
| } |
| |
| static void cil_roleattributes_to_policy(FILE *out, struct cil_list *roles, struct cil_list *attributes) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_role *role; |
| struct cil_roleattribute *attribute; |
| int first = CIL_TRUE; |
| |
| cil_list_for_each(i1, roles) { |
| role = i1->data; |
| if (strcmp(role->datum.fqn,"object_r") == 0) |
| continue; |
| cil_list_for_each(i2, attributes) { |
| attribute = i2->data; |
| if (ebitmap_get_bit(attribute->roles, role->value)) { |
| if (first) { |
| fprintf(out, "roleattribute %s %s", role->datum.fqn, attribute->datum.fqn); |
| first = CIL_FALSE; |
| } else { |
| fprintf(out, ", %s", attribute->datum.fqn); |
| } |
| } |
| } |
| if (!first) { |
| fprintf(out, ";\n"); |
| first = CIL_TRUE; |
| } |
| } |
| } |
| |
| static void cil_roleallows_to_policy(FILE *out, struct cil_list *roleallows) |
| { |
| struct cil_list_item *i1; |
| struct cil_roleallow *allow; |
| |
| cil_list_for_each(i1, roleallows) { |
| allow = i1->data; |
| fprintf(out, "allow %s %s;\n", DATUM(allow->src)->fqn, DATUM(allow->tgt)->fqn); |
| } |
| } |
| |
| static void cil_roletransitions_to_policy(FILE *out, struct cil_list *roletransitions) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_list *class_list; |
| struct cil_roletransition *trans; |
| |
| |
| cil_list_for_each(i1, roletransitions) { |
| trans = i1->data; |
| class_list = cil_expand_class(trans->obj); |
| cil_list_for_each(i2, class_list) { |
| fprintf(out, "role_transition %s %s : %s %s;\n", DATUM(trans->src)->fqn, DATUM(trans->tgt)->fqn, DATUM(i2->data)->fqn, DATUM(trans->result)->fqn); |
| } |
| cil_list_destroy(&class_list, CIL_FALSE); |
| } |
| } |
| |
| static void cil_users_to_policy(FILE *out, int mls, struct cil_list *users, struct cil_list *all_roles) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_user *user; |
| struct cil_list *roles = NULL; |
| struct cil_role *role; |
| int num_roles; |
| |
| cil_list_for_each(i1, users) { |
| user = i1->data; |
| num_roles = 0; |
| fprintf(out, "user %s",user->datum.fqn); |
| cil_list_for_each(i2, all_roles) { |
| role = i2->data; |
| if (ebitmap_get_bit(user->roles, role->value)) { |
| if (num_roles == 0) { |
| cil_list_init(&roles, CIL_LIST); |
| } |
| cil_list_append(roles, CIL_ROLE, role); |
| num_roles++; |
| } |
| } |
| if (num_roles > 0) { |
| fprintf(out, " roles"); |
| if (num_roles > 1) { |
| fprintf(out, " {"); |
| } |
| cil_list_for_each(i2, roles) { |
| role = i2->data; |
| fprintf(out, " %s", role->datum.fqn); |
| } |
| if (num_roles > 1) { |
| fprintf(out, " }"); |
| } |
| cil_list_destroy(&roles, CIL_FALSE); |
| } |
| |
| if (mls == CIL_TRUE && user->dftlevel != NULL) { |
| fprintf(out, " level "); |
| cil_level_to_policy(out, user->dftlevel); |
| } |
| |
| if (mls == CIL_TRUE && user->range != NULL) { |
| fprintf(out, " range "); |
| cil_levelrange_to_policy(out, user->range); |
| } |
| |
| fprintf(out,";\n"); |
| } |
| } |
| |
| static void cil_constrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *constrains) |
| { |
| struct cil_list_item *i1, *i2; |
| struct cil_constrain *cons; |
| struct cil_list *classperms_strs; |
| char *cp_str; |
| char *expr_str; |
| |
| cil_list_for_each(i1, constrains) { |
| cons = i1->data; |
| cil_list_init(&classperms_strs, CIL_LIST); |
| cil_classperms_to_strings(cons->classperms, classperms_strs); |
| expr_str = cil_cons_expr_to_string(db, cons->datum_expr); |
| cil_list_for_each(i2, classperms_strs) { |
| cp_str = i2->data; |
| fprintf(out, "constrain %s %s;\n",cp_str, expr_str); |
| free(cp_str); |
| } |
| free(expr_str); |
| cil_list_destroy(&classperms_strs, CIL_FALSE); |
| } |
| } |
| |
| static void cil_sid_contexts_to_policy(FILE *out, struct cil_list *sids, int mls) |
| { |
| struct cil_list_item *i1; |
| struct cil_sid *sid; |
| |
| cil_list_for_each(i1, sids) { |
| sid = i1->data; |
| fprintf(out, "sid %s ", sid->datum.fqn); |
| cil_context_to_policy(out, sid->context, mls); |
| fprintf(out,"\n"); |
| } |
| } |
| |
| static void cil_fsuses_to_policy(FILE *out, struct cil_sort *fsuses, int mls) |
| { |
| unsigned i; |
| struct cil_fsuse *fsuse; |
| |
| for (i=0; i<fsuses->count; i++) { |
| fsuse = fsuses->array[i]; |
| if (fsuse->type == CIL_FSUSE_XATTR) { |
| fprintf(out, "fs_use_xattr %s ", fsuse->fs_str); |
| cil_context_to_policy(out, fsuse->context, mls); |
| fprintf(out,";\n"); |
| } |
| } |
| |
| for (i=0; i<fsuses->count; i++) { |
| fsuse = fsuses->array[i]; |
| if (fsuse->type == CIL_FSUSE_TASK) { |
| fprintf(out, "fs_use_task %s ", fsuse->fs_str); |
| cil_context_to_policy(out, fsuse->context, mls); |
| fprintf(out,";\n"); |
| } |
| } |
| |
| for (i=0; i<fsuses->count; i++) { |
| fsuse = fsuses->array[i]; |
| if (fsuse->type == CIL_FSUSE_TRANS) { |
| fprintf(out, "fs_use_trans %s ", fsuse->fs_str); |
| cil_context_to_policy(out, fsuse->context, mls); |
| fprintf(out,";\n"); |
| } |
| } |
| } |
| |
| static void cil_genfscons_to_policy(FILE *out, struct cil_sort *genfscons, int mls) |
| { |
| unsigned i; |
| struct cil_genfscon *genfscon; |
| |
| for (i=0; i<genfscons->count; i++) { |
| genfscon = genfscons->array[i]; |
| fprintf(out, "genfscon %s %s ", genfscon->fs_str, genfscon->path_str); |
| cil_context_to_policy(out, genfscon->context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_ibpkeycons_to_policy(FILE *out, struct cil_sort *ibpkeycons, int mls) |
| { |
| uint32_t i = 0; |
| |
| for (i = 0; i < ibpkeycons->count; i++) { |
| struct cil_ibpkeycon *ibpkeycon = (struct cil_ibpkeycon *)ibpkeycons->array[i]; |
| |
| fprintf(out, "ibpkeycon %s ", ibpkeycon->subnet_prefix_str); |
| fprintf(out, "%d ", ibpkeycon->pkey_low); |
| fprintf(out, "%d ", ibpkeycon->pkey_high); |
| cil_context_to_policy(out, ibpkeycon->context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_ibendportcons_to_policy(FILE *out, struct cil_sort *ibendportcons, int mls) |
| { |
| uint32_t i; |
| |
| for (i = 0; i < ibendportcons->count; i++) { |
| struct cil_ibendportcon *ibendportcon = (struct cil_ibendportcon *)ibendportcons->array[i]; |
| |
| fprintf(out, "ibendportcon %s ", ibendportcon->dev_name_str); |
| fprintf(out, "%u ", ibendportcon->port); |
| cil_context_to_policy(out, ibendportcon->context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls) |
| { |
| unsigned i; |
| struct cil_portcon *portcon; |
| |
| for (i=0; i<portcons->count; i++) { |
| portcon = portcons->array[i]; |
| fprintf(out, "portcon "); |
| if (portcon->proto == CIL_PROTOCOL_UDP) { |
| fprintf(out, "udp "); |
| } else if (portcon->proto == CIL_PROTOCOL_TCP) { |
| fprintf(out, "tcp "); |
| } else if (portcon->proto == CIL_PROTOCOL_DCCP) { |
| fprintf(out, "dccp "); |
| } else if (portcon->proto == CIL_PROTOCOL_SCTP) { |
| fprintf(out, "sctp "); |
| } |
| if (portcon->port_low == portcon->port_high) { |
| fprintf(out, "%d ", portcon->port_low); |
| } else { |
| fprintf(out, "%d-%d ", portcon->port_low, portcon->port_high); |
| } |
| cil_context_to_policy(out, portcon->context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_netifcons_to_policy(FILE *out, struct cil_sort *netifcons, int mls) |
| { |
| unsigned i; |
| struct cil_netifcon *netifcon; |
| |
| for (i=0; i<netifcons->count; i++) { |
| netifcon = netifcons->array[i]; |
| fprintf(out, "netifcon %s ", netifcon->interface_str); |
| cil_context_to_policy(out, netifcon->if_context, mls); |
| fprintf(out, " "); |
| cil_context_to_policy(out, netifcon->packet_context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_nodecons_to_policy(FILE *out, struct cil_sort *nodecons, int mls) |
| { |
| unsigned i; |
| struct cil_nodecon *nodecon; |
| char *addr, *mask; |
| |
| for (i=0; i<nodecons->count; i++) { |
| nodecon = nodecons->array[i]; |
| fprintf(out, "nodecon "); |
| |
| if (nodecon->addr->family == AF_INET) { |
| errno = 0; |
| addr = cil_malloc(INET_ADDRSTRLEN); |
| inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, addr, INET_ADDRSTRLEN); |
| if (errno == 0) { |
| fprintf(out, "%s ",addr); |
| } else { |
| fprintf(out, "[INVALID] "); |
| } |
| free(addr); |
| |
| errno = 0; |
| mask = cil_malloc(INET_ADDRSTRLEN); |
| inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, mask, INET_ADDRSTRLEN); |
| if (errno == 0) { |
| fprintf(out, "%s ",mask); |
| } else { |
| fprintf(out, "[INVALID] "); |
| } |
| free(mask); |
| } else { |
| errno = 0; |
| addr = cil_malloc(INET6_ADDRSTRLEN); |
| inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, addr, INET6_ADDRSTRLEN); |
| if (errno == 0) { |
| fprintf(out, "%s ",addr); |
| } else { |
| fprintf(out, "[INVALID] "); |
| } |
| free(addr); |
| |
| errno = 0; |
| mask = cil_malloc(INET6_ADDRSTRLEN); |
| inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, mask, INET6_ADDRSTRLEN); |
| if (errno == 0) { |
| fprintf(out, "%s ",mask); |
| } else { |
| fprintf(out, "[INVALID] "); |
| } |
| free(mask); |
| } |
| |
| cil_context_to_policy(out, nodecon->context, mls); |
| fprintf(out, "\n"); |
| } |
| } |
| |
| static void cil_pirqcons_to_policy(FILE *out, struct cil_sort *pirqcons, int mls) |
| { |
| unsigned i; |
| struct cil_pirqcon *pirqcon; |
| |
| for (i = 0; i<pirqcons->count; i++) { |
| pirqcon = pirqcons->array[i]; |
| fprintf(out, "pirqcon %d ", pirqcon->pirq); |
| cil_context_to_policy(out, pirqcon->context, mls); |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_iomemcons_to_policy(FILE *out, struct cil_sort *iomemcons, int mls) |
| { |
| unsigned i; |
| struct cil_iomemcon *iomemcon; |
| |
| for (i = 0; i<iomemcons->count; i++) { |
| iomemcon = iomemcons->array[i]; |
| if (iomemcon->iomem_low == iomemcon->iomem_high) { |
| fprintf(out, "iomemcon %"PRIx64" ", iomemcon->iomem_low); |
| } else { |
| fprintf(out, "iomemcon %"PRIx64"-%"PRIx64" ", iomemcon->iomem_low, iomemcon->iomem_high); |
| } |
| cil_context_to_policy(out, iomemcon->context, mls); |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_ioportcons_to_policy(FILE *out, struct cil_sort *ioportcons, int mls) |
| { |
| unsigned i; |
| struct cil_ioportcon *ioportcon; |
| |
| for (i = 0; i < ioportcons->count; i++) { |
| ioportcon = ioportcons->array[i]; |
| fprintf(out, "ioportcon 0x%x-0x%x ", ioportcon->ioport_low, ioportcon->ioport_high); |
| cil_context_to_policy(out, ioportcon->context, mls); |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_pcidevicecons_to_policy(FILE *out, struct cil_sort *pcidevicecons, int mls) |
| { |
| unsigned i; |
| struct cil_pcidevicecon *pcidevicecon; |
| |
| for (i = 0; i < pcidevicecons->count; i++) { |
| pcidevicecon = pcidevicecons->array[i]; |
| fprintf(out, "pcidevicecon 0x%x ", pcidevicecon->dev); |
| cil_context_to_policy(out, pcidevicecon->context, mls); |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreecons, int mls) |
| { |
| unsigned i; |
| struct cil_devicetreecon *devicetreecon; |
| |
| for (i = 0; i < devicetreecons->count; i++) { |
| devicetreecon = devicetreecons->array[i]; |
| fprintf(out, "devicetreecon %s ", devicetreecon->path); |
| cil_context_to_policy(out, devicetreecon->context, mls); |
| fprintf(out, ";\n"); |
| } |
| } |
| |
| void cil_gen_policy(FILE *out, struct cil_db *db) |
| { |
| unsigned i; |
| struct cil_tree_node *head = db->ast->root; |
| struct cil_list *lists[CIL_LIST_NUM_LISTS]; |
| |
| for (i=0; i<CIL_LIST_NUM_LISTS; i++) { |
| cil_list_init(&lists[i], CIL_LIST); |
| } |
| |
| cil_gather_statements(head, lists); |
| |
| cil_class_decls_to_policy(out, db->classorder); |
| |
| cil_sid_decls_to_policy(out, db->sidorder); |
| |
| cil_commons_to_policy(out, lists[CIL_LIST_COMMON]); |
| cil_classes_to_policy(out, db->classorder); |
| |
| cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_USER], "default_user"); |
| cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_ROLE], "default_role"); |
| cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_TYPE], "default_type"); |
| |
| if (db->mls == CIL_TRUE) { |
| cil_default_ranges_to_policy(out, lists[CIL_LIST_DEFAULT_RANGE]); |
| cil_sensitivities_to_policy(out, db->sensitivityorder, lists[CIL_LIST_SENSALIAS]); |
| cil_dominance_to_policy(out, db->sensitivityorder); |
| cil_categories_to_policy(out, db->catorder, lists[CIL_LIST_CATALIAS]); |
| cil_levels_to_policy(out, db->sensitivityorder); |
| cil_mlsconstrains_to_policy(out, db, lists[CIL_LIST_MLSCONSTRAIN]); |
| cil_validatetrans_to_policy(out, db, lists[CIL_LIST_MLSVALIDATETRANS], CIL_KEY_MLSVALIDATETRANS); |
| } |
| |
| cil_simple_rules_to_policy(out, lists[CIL_LIST_POLICYCAP], CIL_KEY_POLICYCAP); |
| |
| cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPEATTRIBUTE], "attribute"); |
| cil_simple_rules_to_policy(out, lists[CIL_LIST_ROLEATTRIBUTE], "attribute_role"); |
| |
| cil_bools_to_policy(out, lists[CIL_LIST_BOOL]); |
| |
| cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPE], "type"); |
| cil_typealiases_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEALIAS]); |
| cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]); |
| cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]); |
| cil_te_rules_to_policy(out, head, db->mls); |
| |
| cil_roles_to_policy(out, lists[CIL_LIST_ROLE]); |
| cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]); |
| cil_roleattributes_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_ROLEATTRIBUTE]); |
| cil_roleallows_to_policy(out, lists[CIL_LIST_ROLEALLOW]); |
| cil_roletransitions_to_policy(out, lists[CIL_LIST_ROLETRANSITION]); |
| |
| cil_users_to_policy(out, db->mls, lists[CIL_LIST_USER], lists[CIL_LIST_ROLE]); |
| |
| cil_constrains_to_policy(out, db, lists[CIL_LIST_CONSTRAINT]); |
| cil_validatetrans_to_policy(out, db, lists[CIL_LIST_VALIDATETRANS], CIL_KEY_VALIDATETRANS); |
| |
| cil_sid_contexts_to_policy(out, db->sidorder, db->mls); |
| cil_fsuses_to_policy(out, db->fsuse, db->mls); |
| cil_genfscons_to_policy(out, db->genfscon, db->mls); |
| cil_portcons_to_policy(out, db->portcon, db->mls); |
| cil_netifcons_to_policy(out, db->netifcon, db->mls); |
| cil_ibpkeycons_to_policy(out, db->ibpkeycon, db->mls); |
| cil_ibendportcons_to_policy(out, db->ibendportcon, db->mls); |
| cil_nodecons_to_policy(out, db->nodecon, db->mls); |
| cil_pirqcons_to_policy(out, db->pirqcon, db->mls); |
| cil_iomemcons_to_policy(out, db->iomemcon, db->mls); |
| cil_ioportcons_to_policy(out, db->ioportcon, db->mls); |
| cil_pcidevicecons_to_policy(out, db->pcidevicecon, db->mls); |
| cil_devicetreecons_to_policy(out, db->devicetreecon, db->mls); |
| |
| for (i=0; i<CIL_LIST_NUM_LISTS; i++) { |
| cil_list_destroy(&lists[i], CIL_FALSE); |
| } |
| |
| } |