16cd6a6acSopenharmony_ci/* Authors: Jason Tang <jtang@tresys.com>
26cd6a6acSopenharmony_ci *
36cd6a6acSopenharmony_ci * Functions that manipulate a logical block (conditional, optional,
46cd6a6acSopenharmony_ci * or global scope) for a policy module.
56cd6a6acSopenharmony_ci *
66cd6a6acSopenharmony_ci * Copyright (C) 2005 Tresys Technology, LLC
76cd6a6acSopenharmony_ci *
86cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
96cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
106cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
116cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
126cd6a6acSopenharmony_ci *
136cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
146cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
156cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
166cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
176cd6a6acSopenharmony_ci *
186cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
196cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
206cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
216cd6a6acSopenharmony_ci */
226cd6a6acSopenharmony_ci
236cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
246cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h>
256cd6a6acSopenharmony_ci#include <sepol/policydb/avrule_block.h>
266cd6a6acSopenharmony_ci
276cd6a6acSopenharmony_ci#include <assert.h>
286cd6a6acSopenharmony_ci#include <stdlib.h>
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci/* It is anticipated that there be less declarations within an avrule
316cd6a6acSopenharmony_ci * block than the global policy.  Thus the symbol table sizes are
326cd6a6acSopenharmony_ci * smaller than those listed in policydb.c */
336cd6a6acSopenharmony_cistatic const unsigned int symtab_sizes[SYM_NUM] = {
346cd6a6acSopenharmony_ci	2,
356cd6a6acSopenharmony_ci	4,
366cd6a6acSopenharmony_ci	8,
376cd6a6acSopenharmony_ci	32,
386cd6a6acSopenharmony_ci	16,
396cd6a6acSopenharmony_ci	4,
406cd6a6acSopenharmony_ci	2,
416cd6a6acSopenharmony_ci	2,
426cd6a6acSopenharmony_ci};
436cd6a6acSopenharmony_ci
446cd6a6acSopenharmony_ciavrule_block_t *avrule_block_create(void)
456cd6a6acSopenharmony_ci{
466cd6a6acSopenharmony_ci	avrule_block_t *block;
476cd6a6acSopenharmony_ci	if ((block = calloc(1, sizeof(*block))) == NULL) {
486cd6a6acSopenharmony_ci		return NULL;
496cd6a6acSopenharmony_ci	}
506cd6a6acSopenharmony_ci	return block;
516cd6a6acSopenharmony_ci}
526cd6a6acSopenharmony_ci
536cd6a6acSopenharmony_ciavrule_decl_t *avrule_decl_create(uint32_t decl_id)
546cd6a6acSopenharmony_ci{
556cd6a6acSopenharmony_ci	avrule_decl_t *decl;
566cd6a6acSopenharmony_ci	int i;
576cd6a6acSopenharmony_ci	if ((decl = calloc(1, sizeof(*decl))) == NULL) {
586cd6a6acSopenharmony_ci		return NULL;
596cd6a6acSopenharmony_ci	}
606cd6a6acSopenharmony_ci	decl->decl_id = decl_id;
616cd6a6acSopenharmony_ci	for (i = 0; i < SYM_NUM; i++) {
626cd6a6acSopenharmony_ci		if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
636cd6a6acSopenharmony_ci			avrule_decl_destroy(decl);
646cd6a6acSopenharmony_ci			return NULL;
656cd6a6acSopenharmony_ci		}
666cd6a6acSopenharmony_ci	}
676cd6a6acSopenharmony_ci
686cd6a6acSopenharmony_ci	for (i = 0; i < SYM_NUM; i++) {
696cd6a6acSopenharmony_ci		ebitmap_init(&decl->required.scope[i]);
706cd6a6acSopenharmony_ci		ebitmap_init(&decl->declared.scope[i]);
716cd6a6acSopenharmony_ci	}
726cd6a6acSopenharmony_ci	return decl;
736cd6a6acSopenharmony_ci}
746cd6a6acSopenharmony_ci
756cd6a6acSopenharmony_ci/* note that unlike the other destroy functions, this one does /NOT/
766cd6a6acSopenharmony_ci * destroy the pointer itself */
776cd6a6acSopenharmony_cistatic void scope_index_destroy(scope_index_t * scope)
786cd6a6acSopenharmony_ci{
796cd6a6acSopenharmony_ci	unsigned int i;
806cd6a6acSopenharmony_ci	if (scope == NULL) {
816cd6a6acSopenharmony_ci		return;
826cd6a6acSopenharmony_ci	}
836cd6a6acSopenharmony_ci	for (i = 0; i < SYM_NUM; i++) {
846cd6a6acSopenharmony_ci		ebitmap_destroy(scope->scope + i);
856cd6a6acSopenharmony_ci	}
866cd6a6acSopenharmony_ci	if (scope->class_perms_map) {
876cd6a6acSopenharmony_ci		for (i = 0; i < scope->class_perms_len; i++) {
886cd6a6acSopenharmony_ci			ebitmap_destroy(scope->class_perms_map + i);
896cd6a6acSopenharmony_ci		}
906cd6a6acSopenharmony_ci	}
916cd6a6acSopenharmony_ci	free(scope->class_perms_map);
926cd6a6acSopenharmony_ci}
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_civoid avrule_decl_destroy(avrule_decl_t * x)
956cd6a6acSopenharmony_ci{
966cd6a6acSopenharmony_ci	if (x == NULL) {
976cd6a6acSopenharmony_ci		return;
986cd6a6acSopenharmony_ci	}
996cd6a6acSopenharmony_ci	cond_list_destroy(x->cond_list);
1006cd6a6acSopenharmony_ci	avrule_list_destroy(x->avrules);
1016cd6a6acSopenharmony_ci	role_trans_rule_list_destroy(x->role_tr_rules);
1026cd6a6acSopenharmony_ci	filename_trans_rule_list_destroy(x->filename_trans_rules);
1036cd6a6acSopenharmony_ci	role_allow_rule_list_destroy(x->role_allow_rules);
1046cd6a6acSopenharmony_ci	range_trans_rule_list_destroy(x->range_tr_rules);
1056cd6a6acSopenharmony_ci	scope_index_destroy(&x->required);
1066cd6a6acSopenharmony_ci	scope_index_destroy(&x->declared);
1076cd6a6acSopenharmony_ci	symtabs_destroy(x->symtab);
1086cd6a6acSopenharmony_ci	free(x->module_name);
1096cd6a6acSopenharmony_ci	free(x);
1106cd6a6acSopenharmony_ci}
1116cd6a6acSopenharmony_ci
1126cd6a6acSopenharmony_civoid avrule_block_destroy(avrule_block_t * x)
1136cd6a6acSopenharmony_ci{
1146cd6a6acSopenharmony_ci	avrule_decl_t *decl;
1156cd6a6acSopenharmony_ci	if (x == NULL) {
1166cd6a6acSopenharmony_ci		return;
1176cd6a6acSopenharmony_ci	}
1186cd6a6acSopenharmony_ci	decl = x->branch_list;
1196cd6a6acSopenharmony_ci	while (decl != NULL) {
1206cd6a6acSopenharmony_ci		avrule_decl_t *next_decl = decl->next;
1216cd6a6acSopenharmony_ci		avrule_decl_destroy(decl);
1226cd6a6acSopenharmony_ci		decl = next_decl;
1236cd6a6acSopenharmony_ci	}
1246cd6a6acSopenharmony_ci	free(x);
1256cd6a6acSopenharmony_ci}
1266cd6a6acSopenharmony_ci
1276cd6a6acSopenharmony_civoid avrule_block_list_destroy(avrule_block_t * x)
1286cd6a6acSopenharmony_ci{
1296cd6a6acSopenharmony_ci	while (x != NULL) {
1306cd6a6acSopenharmony_ci		avrule_block_t *next = x->next;
1316cd6a6acSopenharmony_ci		avrule_block_destroy(x);
1326cd6a6acSopenharmony_ci		x = next;
1336cd6a6acSopenharmony_ci	}
1346cd6a6acSopenharmony_ci}
1356cd6a6acSopenharmony_ci
1366cd6a6acSopenharmony_ci/* Get a conditional node from a avrule_decl with the same expression.
1376cd6a6acSopenharmony_ci * If that expression does not exist then create one. */
1386cd6a6acSopenharmony_cicond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl,
1396cd6a6acSopenharmony_ci				cond_list_t * cond)
1406cd6a6acSopenharmony_ci{
1416cd6a6acSopenharmony_ci	cond_list_t *result;
1426cd6a6acSopenharmony_ci	int was_created;
1436cd6a6acSopenharmony_ci	result = cond_node_find(p, cond, decl->cond_list, &was_created);
1446cd6a6acSopenharmony_ci	if (result != NULL && was_created) {
1456cd6a6acSopenharmony_ci		result->next = decl->cond_list;
1466cd6a6acSopenharmony_ci		decl->cond_list = result;
1476cd6a6acSopenharmony_ci	}
1486cd6a6acSopenharmony_ci	return result;
1496cd6a6acSopenharmony_ci}
1506cd6a6acSopenharmony_ci
1516cd6a6acSopenharmony_ci/* Look up an identifier in a policy's scoping table.  If it is there,
1526cd6a6acSopenharmony_ci * marked as SCOPE_DECL, and any of its declaring block has been enabled,
1536cd6a6acSopenharmony_ci * then return 1.  Otherwise return 0. Can only be called after the
1546cd6a6acSopenharmony_ci * decl_val_to_struct index has been created */
1556cd6a6acSopenharmony_ciint is_id_enabled(char *id, policydb_t * p, int symbol_table)
1566cd6a6acSopenharmony_ci{
1576cd6a6acSopenharmony_ci	scope_datum_t *scope =
1586cd6a6acSopenharmony_ci	    (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id);
1596cd6a6acSopenharmony_ci	avrule_decl_t *decl;
1606cd6a6acSopenharmony_ci	uint32_t len;
1616cd6a6acSopenharmony_ci
1626cd6a6acSopenharmony_ci	if (scope == NULL) {
1636cd6a6acSopenharmony_ci		return 0;
1646cd6a6acSopenharmony_ci	}
1656cd6a6acSopenharmony_ci	if (scope->scope != SCOPE_DECL) {
1666cd6a6acSopenharmony_ci		return 0;
1676cd6a6acSopenharmony_ci	}
1686cd6a6acSopenharmony_ci
1696cd6a6acSopenharmony_ci	len = scope->decl_ids_len;
1706cd6a6acSopenharmony_ci	if (len < 1) {
1716cd6a6acSopenharmony_ci		return 0;
1726cd6a6acSopenharmony_ci	}
1736cd6a6acSopenharmony_ci
1746cd6a6acSopenharmony_ci	if (symbol_table == SYM_ROLES || symbol_table == SYM_USERS) {
1756cd6a6acSopenharmony_ci		uint32_t i;
1766cd6a6acSopenharmony_ci		for (i = 0; i < len; i++) {
1776cd6a6acSopenharmony_ci			decl = p->decl_val_to_struct[scope->decl_ids[i] - 1];
1786cd6a6acSopenharmony_ci			if (decl != NULL && decl->enabled) {
1796cd6a6acSopenharmony_ci				return 1;
1806cd6a6acSopenharmony_ci			}
1816cd6a6acSopenharmony_ci		}
1826cd6a6acSopenharmony_ci	} else {
1836cd6a6acSopenharmony_ci		decl = p->decl_val_to_struct[scope->decl_ids[len-1] - 1];
1846cd6a6acSopenharmony_ci		if (decl != NULL && decl->enabled) {
1856cd6a6acSopenharmony_ci			return 1;
1866cd6a6acSopenharmony_ci		}
1876cd6a6acSopenharmony_ci	}
1886cd6a6acSopenharmony_ci
1896cd6a6acSopenharmony_ci	return 0;
1906cd6a6acSopenharmony_ci}
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci/* Check if a particular permission is present within the given class,
1936cd6a6acSopenharmony_ci * and that the class is enabled.  Returns 1 if both conditions are
1946cd6a6acSopenharmony_ci * true, 0 if neither could be found or if the class id disabled. */
1956cd6a6acSopenharmony_ciint is_perm_enabled(char *class_id, char *perm_id, policydb_t * p)
1966cd6a6acSopenharmony_ci{
1976cd6a6acSopenharmony_ci	class_datum_t *cladatum;
1986cd6a6acSopenharmony_ci	perm_datum_t *perm;
1996cd6a6acSopenharmony_ci	if (!is_id_enabled(class_id, p, SYM_CLASSES)) {
2006cd6a6acSopenharmony_ci		return 0;
2016cd6a6acSopenharmony_ci	}
2026cd6a6acSopenharmony_ci	cladatum =
2036cd6a6acSopenharmony_ci	    (class_datum_t *) hashtab_search(p->p_classes.table, class_id);
2046cd6a6acSopenharmony_ci	if (cladatum == NULL) {
2056cd6a6acSopenharmony_ci		return 0;
2066cd6a6acSopenharmony_ci	}
2076cd6a6acSopenharmony_ci	perm = hashtab_search(cladatum->permissions.table, perm_id);
2086cd6a6acSopenharmony_ci	if (perm == NULL && cladatum->comdatum != 0) {
2096cd6a6acSopenharmony_ci		/* permission was not in this class.  before giving
2106cd6a6acSopenharmony_ci		 * up, check the class's parent */
2116cd6a6acSopenharmony_ci		perm =
2126cd6a6acSopenharmony_ci		    hashtab_search(cladatum->comdatum->permissions.table,
2136cd6a6acSopenharmony_ci				   perm_id);
2146cd6a6acSopenharmony_ci	}
2156cd6a6acSopenharmony_ci	if (perm == NULL) {
2166cd6a6acSopenharmony_ci		return 0;
2176cd6a6acSopenharmony_ci	}
2186cd6a6acSopenharmony_ci	return 1;
2196cd6a6acSopenharmony_ci}
220