/* Authors: Jason Tang <jtang@tresys.com> * * Functions that manipulate a logical block (conditional, optional, * or global scope) for a policy module. * * Copyright (C) 2005 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <sepol/policydb/policydb.h> #include <sepol/policydb/conditional.h> #include <sepol/policydb/avrule_block.h> #include <assert.h> #include <stdlib.h> /* It is anticipated that there be less declarations within an avrule * block than the global policy. Thus the symbol table sizes are * smaller than those listed in policydb.c */ static unsigned int symtab_sizes[SYM_NUM] = { 2, 4, 8, 32, 16, 4, 2, 2, }; avrule_block_t *avrule_block_create(void) { avrule_block_t *block; if ((block = calloc(1, sizeof(*block))) == NULL) { return NULL; } return block; } avrule_decl_t *avrule_decl_create(uint32_t decl_id) { avrule_decl_t *decl; int i; if ((decl = calloc(1, sizeof(*decl))) == NULL) { return NULL; } decl->decl_id = decl_id; for (i = 0; i < SYM_NUM; i++) { if (symtab_init(&decl->symtab[i], symtab_sizes[i])) { avrule_decl_destroy(decl); return NULL; } } for (i = 0; i < SYM_NUM; i++) { ebitmap_init(&decl->required.scope[i]); ebitmap_init(&decl->declared.scope[i]); } return decl; } /* note that unlike the other destroy functions, this one does /NOT/ * destroy the pointer itself */ static void scope_index_destroy(scope_index_t * scope) { unsigned int i; if (scope == NULL) { return; } for (i = 0; i < SYM_NUM; i++) { ebitmap_destroy(scope->scope + i); } if (scope->class_perms_map) { for (i = 0; i < scope->class_perms_len; i++) { ebitmap_destroy(scope->class_perms_map + i); } } free(scope->class_perms_map); } void avrule_decl_destroy(avrule_decl_t * x) { if (x == NULL) { return; } cond_list_destroy(x->cond_list); avrule_list_destroy(x->avrules); role_trans_rule_list_destroy(x->role_tr_rules); filename_trans_rule_list_destroy(x->filename_trans_rules); role_allow_rule_list_destroy(x->role_allow_rules); range_trans_rule_list_destroy(x->range_tr_rules); scope_index_destroy(&x->required); scope_index_destroy(&x->declared); symtabs_destroy(x->symtab); free(x->module_name); free(x); } void avrule_block_destroy(avrule_block_t * x) { avrule_decl_t *decl; if (x == NULL) { return; } decl = x->branch_list; while (decl != NULL) { avrule_decl_t *next_decl = decl->next; avrule_decl_destroy(decl); decl = next_decl; } free(x); } void avrule_block_list_destroy(avrule_block_t * x) { while (x != NULL) { avrule_block_t *next = x->next; avrule_block_destroy(x); x = next; } } /* Get a conditional node from a avrule_decl with the same expression. * If that expression does not exist then create one. */ cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl, cond_list_t * cond) { cond_list_t *result; int was_created; result = cond_node_find(p, cond, decl->cond_list, &was_created); if (result != NULL && was_created) { result->next = decl->cond_list; decl->cond_list = result; } return result; } /* Look up an identifier in a policy's scoping table. If it is there, * marked as SCOPE_DECL, and any of its declaring block has been enabled, * then return 1. Otherwise return 0. Can only be called after the * decl_val_to_struct index has been created */ int is_id_enabled(char *id, policydb_t * p, int symbol_table) { scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id); avrule_decl_t *decl; uint32_t len = scope->decl_ids_len; if (scope == NULL) { return 0; } if (scope->scope != SCOPE_DECL) { return 0; } if (len < 1) { return 0; } if (symbol_table == SYM_ROLES || symbol_table == SYM_USERS) { uint32_t i; for (i = 0; i < len; i++) { decl = p->decl_val_to_struct[scope->decl_ids[i] - 1]; if (decl != NULL && decl->enabled) { return 1; } } } else { decl = p->decl_val_to_struct[scope->decl_ids[len-1] - 1]; if (decl != NULL && decl->enabled) { return 1; } } return 0; } /* Check if a particular permission is present within the given class, * and that the class is enabled. Returns 1 if both conditions are * true, 0 if neither could be found or if the class id disabled. */ int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p) { class_datum_t *cladatum; perm_datum_t *perm; if (!is_id_enabled(class_id, p, SYM_CLASSES)) { return 0; } cladatum = (class_datum_t *) hashtab_search(p->p_classes.table, class_id); if (cladatum == NULL) { return 0; } perm = hashtab_search(cladatum->permissions.table, perm_id); if (perm == NULL && cladatum->comdatum != 0) { /* permission was not in this class. before giving * up, check the class's parent */ perm = hashtab_search(cladatum->comdatum->permissions.table, perm_id); } if (perm == NULL) { return 0; } return 1; }