1/* Authors: Jason Tang <jtang@tresys.com>
2 *
3 * Functions that manipulate a logical block (conditional, optional,
4 * or global scope) for a policy module.
5 *
6 * Copyright (C) 2005 Tresys Technology, LLC
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU Lesser General Public
10 *  License as published by the Free Software Foundation; either
11 *  version 2.1 of the License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  Lesser General Public License for more details.
17 *
18 *  You should have received a copy of the GNU Lesser General Public
19 *  License along with this library; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 */
22
23#include <sepol/policydb/policydb.h>
24#include <sepol/policydb/conditional.h>
25#include <sepol/policydb/avrule_block.h>
26
27#include <assert.h>
28#include <stdlib.h>
29
30/* It is anticipated that there be less declarations within an avrule
31 * block than the global policy.  Thus the symbol table sizes are
32 * smaller than those listed in policydb.c */
33static unsigned int symtab_sizes[SYM_NUM] = {
34	2,
35	4,
36	8,
37	32,
38	16,
39	4,
40	2,
41	2,
42};
43
44avrule_block_t *avrule_block_create(void)
45{
46	avrule_block_t *block;
47	if ((block = calloc(1, sizeof(*block))) == NULL) {
48		return NULL;
49	}
50	return block;
51}
52
53avrule_decl_t *avrule_decl_create(uint32_t decl_id)
54{
55	avrule_decl_t *decl;
56	int i;
57	if ((decl = calloc(1, sizeof(*decl))) == NULL) {
58		return NULL;
59	}
60	decl->decl_id = decl_id;
61	for (i = 0; i < SYM_NUM; i++) {
62		if (symtab_init(&decl->symtab[i], symtab_sizes[i])) {
63			avrule_decl_destroy(decl);
64			free(decl);
65			return NULL;
66		}
67	}
68
69	for (i = 0; i < SYM_NUM; i++) {
70		ebitmap_init(&decl->required.scope[i]);
71		ebitmap_init(&decl->declared.scope[i]);
72	}
73	return decl;
74}
75
76/* note that unlike the other destroy functions, this one does /NOT/
77 * destroy the pointer itself */
78static void scope_index_destroy(scope_index_t * scope)
79{
80	unsigned int i;
81	if (scope == NULL) {
82		return;
83	}
84	for (i = 0; i < SYM_NUM; i++) {
85		ebitmap_destroy(scope->scope + i);
86	}
87	for (i = 0; i < scope->class_perms_len; i++) {
88		ebitmap_destroy(scope->class_perms_map + i);
89	}
90	free(scope->class_perms_map);
91}
92
93void avrule_decl_destroy(avrule_decl_t * x)
94{
95	if (x == NULL) {
96		return;
97	}
98	cond_list_destroy(x->cond_list);
99	avrule_list_destroy(x->avrules);
100	role_trans_rule_list_destroy(x->role_tr_rules);
101	filename_trans_rule_list_destroy(x->filename_trans_rules);
102	role_allow_rule_list_destroy(x->role_allow_rules);
103	range_trans_rule_list_destroy(x->range_tr_rules);
104	scope_index_destroy(&x->required);
105	scope_index_destroy(&x->declared);
106	symtabs_destroy(x->symtab);
107	free(x->module_name);
108	free(x);
109}
110
111void avrule_block_destroy(avrule_block_t * x)
112{
113	avrule_decl_t *decl;
114	if (x == NULL) {
115		return;
116	}
117	decl = x->branch_list;
118	while (decl != NULL) {
119		avrule_decl_t *next_decl = decl->next;
120		avrule_decl_destroy(decl);
121		decl = next_decl;
122	}
123	free(x);
124}
125
126void avrule_block_list_destroy(avrule_block_t * x)
127{
128	while (x != NULL) {
129		avrule_block_t *next = x->next;
130		avrule_block_destroy(x);
131		x = next;
132	}
133}
134
135/* Get a conditional node from a avrule_decl with the same expression.
136 * If that expression does not exist then create one. */
137cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl,
138				cond_list_t * cond)
139{
140	cond_list_t *result;
141	int was_created;
142	result = cond_node_find(p, cond, decl->cond_list, &was_created);
143	if (result != NULL && was_created) {
144		result->next = decl->cond_list;
145		decl->cond_list = result;
146	}
147	return result;
148}
149
150/* Look up an identifier in a policy's scoping table.  If it is there,
151 * marked as SCOPE_DECL, and any of its declaring block has been enabled,
152 * then return 1.  Otherwise return 0. Can only be called after the
153 * decl_val_to_struct index has been created */
154int is_id_enabled(char *id, policydb_t * p, int symbol_table)
155{
156	scope_datum_t *scope =
157	    (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id);
158	uint32_t i;
159	if (scope == NULL) {
160		return 0;
161	}
162	if (scope->scope != SCOPE_DECL) {
163		return 0;
164	}
165	for (i = 0; i < scope->decl_ids_len; i++) {
166		avrule_decl_t *decl =
167		    p->decl_val_to_struct[scope->decl_ids[i] - 1];
168		if (decl != NULL && decl->enabled) {
169			return 1;
170		}
171	}
172	return 0;
173}
174
175/* Check if a particular permission is present within the given class,
176 * and that the class is enabled.  Returns 1 if both conditions are
177 * true, 0 if neither could be found or if the class id disabled. */
178int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p)
179{
180	class_datum_t *cladatum;
181	perm_datum_t *perm;
182	if (!is_id_enabled(class_id, p, SYM_CLASSES)) {
183		return 0;
184	}
185	cladatum =
186	    (class_datum_t *) hashtab_search(p->p_classes.table, class_id);
187	if (cladatum == NULL) {
188		return 0;
189	}
190	perm = hashtab_search(cladatum->permissions.table, perm_id);
191	if (perm == NULL && cladatum->comdatum != 0) {
192		/* permission was not in this class.  before giving
193		 * up, check the class's parent */
194		perm =
195		    hashtab_search(cladatum->comdatum->permissions.table,
196				   perm_id);
197	}
198	if (perm == NULL) {
199		return 0;
200	}
201	return 1;
202}
203