16cd6a6acSopenharmony_ci/* Author : Joshua Brindle <jbrindle@tresys.com>
26cd6a6acSopenharmony_ci *	    Karl MacMillan <kmacmillan@tresys.com>
36cd6a6acSopenharmony_ci *          Jason Tang     <jtang@tresys.com>
46cd6a6acSopenharmony_ci *	Added support for binary policy modules
56cd6a6acSopenharmony_ci *
66cd6a6acSopenharmony_ci * Copyright (C) 2004 - 2005 Tresys Technology, LLC
76cd6a6acSopenharmony_ci *	This program is free software; you can redistribute it and/or modify
86cd6a6acSopenharmony_ci *  	it under the terms of the GNU General Public License as published by
96cd6a6acSopenharmony_ci *	the Free Software Foundation, version 2.
106cd6a6acSopenharmony_ci */
116cd6a6acSopenharmony_ci
126cd6a6acSopenharmony_ci#include <assert.h>
136cd6a6acSopenharmony_ci#include <stdarg.h>
146cd6a6acSopenharmony_ci#include <stdlib.h>
156cd6a6acSopenharmony_ci#include <string.h>
166cd6a6acSopenharmony_ci
176cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
186cd6a6acSopenharmony_ci#include <sepol/policydb/avrule_block.h>
196cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h>
206cd6a6acSopenharmony_ci
216cd6a6acSopenharmony_ci#include "queue.h"
226cd6a6acSopenharmony_ci#include "module_compiler.h"
236cd6a6acSopenharmony_ci
246cd6a6acSopenharmony_ciunion stack_item_u {
256cd6a6acSopenharmony_ci	avrule_block_t *avrule;
266cd6a6acSopenharmony_ci	cond_list_t *cond_list;
276cd6a6acSopenharmony_ci};
286cd6a6acSopenharmony_ci
296cd6a6acSopenharmony_citypedef struct scope_stack {
306cd6a6acSopenharmony_ci	union stack_item_u u;
316cd6a6acSopenharmony_ci	int type;		/* for above union: 1 = avrule block, 2 = conditional */
326cd6a6acSopenharmony_ci	avrule_decl_t *decl;	/* if in an avrule block, which
336cd6a6acSopenharmony_ci				 * declaration is current */
346cd6a6acSopenharmony_ci	avrule_t *last_avrule;
356cd6a6acSopenharmony_ci	int in_else;		/* if in an avrule block, within ELSE branch */
366cd6a6acSopenharmony_ci	int require_given;	/* 1 if this block had at least one require */
376cd6a6acSopenharmony_ci	struct scope_stack *parent, *child;
386cd6a6acSopenharmony_ci} scope_stack_t;
396cd6a6acSopenharmony_ci
406cd6a6acSopenharmony_ciextern policydb_t *policydbp;
416cd6a6acSopenharmony_ciextern queue_t id_queue;
426cd6a6acSopenharmony_ciextern int yyerror(const char *msg);
436cd6a6acSopenharmony_ci__attribute__ ((format(printf, 1, 2)))
446cd6a6acSopenharmony_ciextern void yyerror2(const char *fmt, ...);
456cd6a6acSopenharmony_ci
466cd6a6acSopenharmony_cistatic int push_stack(int stack_type, ...);
476cd6a6acSopenharmony_cistatic void pop_stack(void);
486cd6a6acSopenharmony_ci
496cd6a6acSopenharmony_ci/* keep track of the last item added to the stack */
506cd6a6acSopenharmony_cistatic scope_stack_t *stack_top = NULL;
516cd6a6acSopenharmony_cistatic avrule_block_t *last_block;
526cd6a6acSopenharmony_cistatic uint32_t next_decl_id = 1;
536cd6a6acSopenharmony_ci
546cd6a6acSopenharmony_cistatic const char * const flavor_str[SYM_NUM] = {
556cd6a6acSopenharmony_ci	[SYM_COMMONS] = "common",
566cd6a6acSopenharmony_ci	[SYM_CLASSES] = "class",
576cd6a6acSopenharmony_ci	[SYM_ROLES] = "role",
586cd6a6acSopenharmony_ci	[SYM_TYPES] = "type",
596cd6a6acSopenharmony_ci	[SYM_USERS] = "user",
606cd6a6acSopenharmony_ci	[SYM_BOOLS] = "bool",
616cd6a6acSopenharmony_ci	[SYM_LEVELS] = "level",
626cd6a6acSopenharmony_ci	[SYM_CATS] = "cat"
636cd6a6acSopenharmony_ci};
646cd6a6acSopenharmony_ci
656cd6a6acSopenharmony_cistatic void print_error_msg(int ret, uint32_t symbol_type)
666cd6a6acSopenharmony_ci{
676cd6a6acSopenharmony_ci	switch (ret) {
686cd6a6acSopenharmony_ci	case -3:
696cd6a6acSopenharmony_ci		yyerror("Out of memory!");
706cd6a6acSopenharmony_ci		break;
716cd6a6acSopenharmony_ci	case -2:
726cd6a6acSopenharmony_ci		yyerror2("Duplicate declaration of %s", flavor_str[symbol_type]);
736cd6a6acSopenharmony_ci		break;
746cd6a6acSopenharmony_ci	case -1:
756cd6a6acSopenharmony_ci		yyerror2("Could not declare %s here", flavor_str[symbol_type]);
766cd6a6acSopenharmony_ci		break;
776cd6a6acSopenharmony_ci	default:
786cd6a6acSopenharmony_ci		yyerror("Unknown error");
796cd6a6acSopenharmony_ci	}
806cd6a6acSopenharmony_ci}
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_ciint define_policy(int pass, int module_header_given)
836cd6a6acSopenharmony_ci{
846cd6a6acSopenharmony_ci	char *id;
856cd6a6acSopenharmony_ci
866cd6a6acSopenharmony_ci	if (module_header_given) {
876cd6a6acSopenharmony_ci		if (policydbp->policy_type != POLICY_MOD) {
886cd6a6acSopenharmony_ci			yyerror
896cd6a6acSopenharmony_ci			    ("Module specification found while not building a policy module.\n");
906cd6a6acSopenharmony_ci			return -1;
916cd6a6acSopenharmony_ci		}
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_ci		if (pass == 2) {
946cd6a6acSopenharmony_ci			while ((id = queue_remove(id_queue)) != NULL)
956cd6a6acSopenharmony_ci				free(id);
966cd6a6acSopenharmony_ci		} else {
976cd6a6acSopenharmony_ci			id = (char *)queue_remove(id_queue);
986cd6a6acSopenharmony_ci			if (!id) {
996cd6a6acSopenharmony_ci				yyerror("no module name");
1006cd6a6acSopenharmony_ci				return -1;
1016cd6a6acSopenharmony_ci			}
1026cd6a6acSopenharmony_ci			free(policydbp->name);
1036cd6a6acSopenharmony_ci			policydbp->name = id;
1046cd6a6acSopenharmony_ci			if ((policydbp->version =
1056cd6a6acSopenharmony_ci			     queue_remove(id_queue)) == NULL) {
1066cd6a6acSopenharmony_ci				yyerror
1076cd6a6acSopenharmony_ci				    ("Expected a module version but none was found.");
1086cd6a6acSopenharmony_ci				return -1;
1096cd6a6acSopenharmony_ci			}
1106cd6a6acSopenharmony_ci		}
1116cd6a6acSopenharmony_ci	} else {
1126cd6a6acSopenharmony_ci		if (policydbp->policy_type == POLICY_MOD) {
1136cd6a6acSopenharmony_ci			yyerror
1146cd6a6acSopenharmony_ci			    ("Building a policy module, but no module specification found.\n");
1156cd6a6acSopenharmony_ci			return -1;
1166cd6a6acSopenharmony_ci		}
1176cd6a6acSopenharmony_ci	}
1186cd6a6acSopenharmony_ci	/* the first declaration within the global avrule
1196cd6a6acSopenharmony_ci	   block will always have an id of 1 */
1206cd6a6acSopenharmony_ci	next_decl_id = 2;
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci	/* reset the scoping stack */
1236cd6a6acSopenharmony_ci	while (stack_top != NULL) {
1246cd6a6acSopenharmony_ci		pop_stack();
1256cd6a6acSopenharmony_ci	}
1266cd6a6acSopenharmony_ci	if (push_stack(1, policydbp->global, policydbp->global->branch_list) ==
1276cd6a6acSopenharmony_ci	    -1) {
1286cd6a6acSopenharmony_ci		return -1;
1296cd6a6acSopenharmony_ci	}
1306cd6a6acSopenharmony_ci	last_block = policydbp->global;
1316cd6a6acSopenharmony_ci	return 0;
1326cd6a6acSopenharmony_ci}
1336cd6a6acSopenharmony_ci
1346cd6a6acSopenharmony_ci/* Given the current parse stack, returns 1 if a declaration or require would
1356cd6a6acSopenharmony_ci * be allowed here or 0 if not.  For example, declarations and requirements are
1366cd6a6acSopenharmony_ci * not allowed in conditionals, so if there are any conditionals in the
1376cd6a6acSopenharmony_ci * current scope stack then this would return a 0.
1386cd6a6acSopenharmony_ci */
1396cd6a6acSopenharmony_cistatic int is_creation_allowed(void)
1406cd6a6acSopenharmony_ci{
1416cd6a6acSopenharmony_ci	if (stack_top->type != 1 || stack_top->in_else) {
1426cd6a6acSopenharmony_ci		return 0;
1436cd6a6acSopenharmony_ci	}
1446cd6a6acSopenharmony_ci	return 1;
1456cd6a6acSopenharmony_ci}
1466cd6a6acSopenharmony_ci
1476cd6a6acSopenharmony_ci/* Attempt to declare or require a symbol within the current scope.
1486cd6a6acSopenharmony_ci * Returns:
1496cd6a6acSopenharmony_ci *  0: Success - Symbol had not been previously created.
1506cd6a6acSopenharmony_ci *  1: Success - Symbol had already been created and caller must free datum.
1516cd6a6acSopenharmony_ci * -1: Failure - Symbol cannot be created here
1526cd6a6acSopenharmony_ci * -2: Failure - Duplicate declaration or type/attribute mismatch
1536cd6a6acSopenharmony_ci * -3: Failure - Out of memory or some other error
1546cd6a6acSopenharmony_ci */
1556cd6a6acSopenharmony_cistatic int create_symbol(uint32_t symbol_type, hashtab_key_t key, hashtab_datum_t datum,
1566cd6a6acSopenharmony_ci			 uint32_t * dest_value, uint32_t scope)
1576cd6a6acSopenharmony_ci{
1586cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
1596cd6a6acSopenharmony_ci	int ret;
1606cd6a6acSopenharmony_ci
1616cd6a6acSopenharmony_ci	if (!is_creation_allowed()) {
1626cd6a6acSopenharmony_ci		return -1;
1636cd6a6acSopenharmony_ci	}
1646cd6a6acSopenharmony_ci
1656cd6a6acSopenharmony_ci	ret = symtab_insert(policydbp, symbol_type, key, datum, scope,
1666cd6a6acSopenharmony_ci			    decl->decl_id, dest_value);
1676cd6a6acSopenharmony_ci
1686cd6a6acSopenharmony_ci	if (ret == 1 && dest_value) {
1696cd6a6acSopenharmony_ci		hashtab_datum_t s =
1706cd6a6acSopenharmony_ci			hashtab_search(policydbp->symtab[symbol_type].table,
1716cd6a6acSopenharmony_ci				       key);
1726cd6a6acSopenharmony_ci		assert(s != NULL);
1736cd6a6acSopenharmony_ci
1746cd6a6acSopenharmony_ci		if (symbol_type == SYM_LEVELS) {
1756cd6a6acSopenharmony_ci			*dest_value = ((level_datum_t *)s)->level->sens;
1766cd6a6acSopenharmony_ci		} else {
1776cd6a6acSopenharmony_ci			*dest_value = ((symtab_datum_t *)s)->value;
1786cd6a6acSopenharmony_ci		}
1796cd6a6acSopenharmony_ci	} else if (ret == -2) {
1806cd6a6acSopenharmony_ci		return -2;
1816cd6a6acSopenharmony_ci	} else if (ret < 0) {
1826cd6a6acSopenharmony_ci		return -3;
1836cd6a6acSopenharmony_ci	}
1846cd6a6acSopenharmony_ci
1856cd6a6acSopenharmony_ci	return ret;
1866cd6a6acSopenharmony_ci}
1876cd6a6acSopenharmony_ci
1886cd6a6acSopenharmony_ci/* Attempt to declare a symbol within the current declaration.  If
1896cd6a6acSopenharmony_ci * currently within a non-conditional and in a non-else branch then
1906cd6a6acSopenharmony_ci * insert the symbol, return 0 on success if symbol was undeclared.
1916cd6a6acSopenharmony_ci * For roles and users, it is legal to have multiple declarations; as
1926cd6a6acSopenharmony_ci * such return 1 to indicate that caller must free() the datum because
1936cd6a6acSopenharmony_ci * it was not added.  If symbols may not be declared here return -1.
1946cd6a6acSopenharmony_ci * For duplicate declarations return -2.  For all else, including out
1956cd6a6acSopenharmony_ci * of memory, return -3.  Note that dest_value and datum_value might
1966cd6a6acSopenharmony_ci * not be restricted pointers. */
1976cd6a6acSopenharmony_ciint declare_symbol(uint32_t symbol_type,
1986cd6a6acSopenharmony_ci		   hashtab_key_t key, hashtab_datum_t datum,
1996cd6a6acSopenharmony_ci		   uint32_t * dest_value, uint32_t * datum_value)
2006cd6a6acSopenharmony_ci{
2016cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
2026cd6a6acSopenharmony_ci	int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_DECL);
2036cd6a6acSopenharmony_ci
2046cd6a6acSopenharmony_ci	if (ret < 0) {
2056cd6a6acSopenharmony_ci		return ret;
2066cd6a6acSopenharmony_ci	}
2076cd6a6acSopenharmony_ci
2086cd6a6acSopenharmony_ci	if (ebitmap_set_bit(decl->declared.scope + symbol_type,
2096cd6a6acSopenharmony_ci			    *datum_value - 1, 1)) {
2106cd6a6acSopenharmony_ci		return -3;
2116cd6a6acSopenharmony_ci	}
2126cd6a6acSopenharmony_ci
2136cd6a6acSopenharmony_ci	return ret;
2146cd6a6acSopenharmony_ci}
2156cd6a6acSopenharmony_ci
2166cd6a6acSopenharmony_cistatic int role_implicit_bounds(hashtab_t roles_tab,
2176cd6a6acSopenharmony_ci				char *role_id, role_datum_t *role)
2186cd6a6acSopenharmony_ci{
2196cd6a6acSopenharmony_ci	role_datum_t *bounds;
2206cd6a6acSopenharmony_ci	char *bounds_id, *delim;
2216cd6a6acSopenharmony_ci
2226cd6a6acSopenharmony_ci	delim = strrchr(role_id, '.');
2236cd6a6acSopenharmony_ci	if (!delim)
2246cd6a6acSopenharmony_ci		return 0;	/* no implicit boundary */
2256cd6a6acSopenharmony_ci
2266cd6a6acSopenharmony_ci	bounds_id = strdup(role_id);
2276cd6a6acSopenharmony_ci	if (!bounds_id) {
2286cd6a6acSopenharmony_ci		yyerror("out of memory");
2296cd6a6acSopenharmony_ci		return -1;
2306cd6a6acSopenharmony_ci	}
2316cd6a6acSopenharmony_ci	bounds_id[(size_t)(delim - role_id)] = '\0';
2326cd6a6acSopenharmony_ci
2336cd6a6acSopenharmony_ci	bounds = hashtab_search(roles_tab, bounds_id);
2346cd6a6acSopenharmony_ci	if (!bounds) {
2356cd6a6acSopenharmony_ci		yyerror2("role %s doesn't exist, is implicit bounds of %s",
2366cd6a6acSopenharmony_ci			 bounds_id, role_id);
2376cd6a6acSopenharmony_ci		return -1;
2386cd6a6acSopenharmony_ci	}
2396cd6a6acSopenharmony_ci
2406cd6a6acSopenharmony_ci	if (!role->bounds)
2416cd6a6acSopenharmony_ci		role->bounds = bounds->s.value;
2426cd6a6acSopenharmony_ci	else if (role->bounds != bounds->s.value) {
2436cd6a6acSopenharmony_ci		yyerror2("role %s has inconsistent bounds %s/%s",
2446cd6a6acSopenharmony_ci			 role_id, bounds_id,
2456cd6a6acSopenharmony_ci			 policydbp->p_role_val_to_name[role->bounds - 1]);
2466cd6a6acSopenharmony_ci		return -1;
2476cd6a6acSopenharmony_ci	}
2486cd6a6acSopenharmony_ci	free(bounds_id);
2496cd6a6acSopenharmony_ci
2506cd6a6acSopenharmony_ci	return 0;
2516cd6a6acSopenharmony_ci}
2526cd6a6acSopenharmony_ci
2536cd6a6acSopenharmony_cistatic int create_role(uint32_t scope, unsigned char isattr, role_datum_t **role, char **key)
2546cd6a6acSopenharmony_ci{
2556cd6a6acSopenharmony_ci	char *id = queue_remove(id_queue);
2566cd6a6acSopenharmony_ci	role_datum_t *datum = NULL;
2576cd6a6acSopenharmony_ci	int ret;
2586cd6a6acSopenharmony_ci	uint32_t value;
2596cd6a6acSopenharmony_ci
2606cd6a6acSopenharmony_ci	*role = NULL;
2616cd6a6acSopenharmony_ci	*key = NULL;
2626cd6a6acSopenharmony_ci	isattr = isattr ? ROLE_ATTRIB : ROLE_ROLE;
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ci	if (id == NULL) {
2656cd6a6acSopenharmony_ci		yyerror("no role name");
2666cd6a6acSopenharmony_ci		return -1;
2676cd6a6acSopenharmony_ci	}
2686cd6a6acSopenharmony_ci
2696cd6a6acSopenharmony_ci	datum = malloc(sizeof(*datum));
2706cd6a6acSopenharmony_ci	if (datum == NULL) {
2716cd6a6acSopenharmony_ci		yyerror("Out of memory!");
2726cd6a6acSopenharmony_ci		free(id);
2736cd6a6acSopenharmony_ci		return -1;
2746cd6a6acSopenharmony_ci	}
2756cd6a6acSopenharmony_ci
2766cd6a6acSopenharmony_ci	role_datum_init(datum);
2776cd6a6acSopenharmony_ci	datum->flavor = isattr;
2786cd6a6acSopenharmony_ci
2796cd6a6acSopenharmony_ci	if (scope == SCOPE_DECL) {
2806cd6a6acSopenharmony_ci		ret = declare_symbol(SYM_ROLES, id, datum, &value, &value);
2816cd6a6acSopenharmony_ci	} else {
2826cd6a6acSopenharmony_ci		ret = require_symbol(SYM_ROLES, id, datum, &value, &value);
2836cd6a6acSopenharmony_ci	}
2846cd6a6acSopenharmony_ci
2856cd6a6acSopenharmony_ci	datum->s.value = value;
2866cd6a6acSopenharmony_ci
2876cd6a6acSopenharmony_ci	if (ret == 0) {
2886cd6a6acSopenharmony_ci		*role = datum;
2896cd6a6acSopenharmony_ci		*key = strdup(id);
2906cd6a6acSopenharmony_ci		if (*key == NULL) {
2916cd6a6acSopenharmony_ci			yyerror("Out of memory!");
2926cd6a6acSopenharmony_ci			return -1;
2936cd6a6acSopenharmony_ci		}
2946cd6a6acSopenharmony_ci	} else if (ret == 1) {
2956cd6a6acSopenharmony_ci		*role = hashtab_search(policydbp->symtab[SYM_ROLES].table, id);
2966cd6a6acSopenharmony_ci		if (*role && (isattr != (*role)->flavor)) {
2976cd6a6acSopenharmony_ci			yyerror2("Identifier %s used as both an attribute and a role",
2986cd6a6acSopenharmony_ci				 id);
2996cd6a6acSopenharmony_ci			free(id);
3006cd6a6acSopenharmony_ci			role_datum_destroy(datum);
3016cd6a6acSopenharmony_ci			free(datum);
3026cd6a6acSopenharmony_ci			return -1;
3036cd6a6acSopenharmony_ci		}
3046cd6a6acSopenharmony_ci		*role = datum;
3056cd6a6acSopenharmony_ci		*key = id;
3066cd6a6acSopenharmony_ci	} else {
3076cd6a6acSopenharmony_ci		print_error_msg(ret, SYM_ROLES);
3086cd6a6acSopenharmony_ci		free(id);
3096cd6a6acSopenharmony_ci		role_datum_destroy(datum);
3106cd6a6acSopenharmony_ci		free(datum);
3116cd6a6acSopenharmony_ci	}
3126cd6a6acSopenharmony_ci
3136cd6a6acSopenharmony_ci	return ret;
3146cd6a6acSopenharmony_ci}
3156cd6a6acSopenharmony_ci
3166cd6a6acSopenharmony_cirole_datum_t *declare_role(unsigned char isattr)
3176cd6a6acSopenharmony_ci{
3186cd6a6acSopenharmony_ci	char *key = NULL;
3196cd6a6acSopenharmony_ci	role_datum_t *role = NULL;
3206cd6a6acSopenharmony_ci	role_datum_t *dest_role = NULL;
3216cd6a6acSopenharmony_ci	hashtab_t roles_tab;
3226cd6a6acSopenharmony_ci	int ret, ret2;
3236cd6a6acSopenharmony_ci
3246cd6a6acSopenharmony_ci	ret = create_role(SCOPE_DECL, isattr, &role, &key);
3256cd6a6acSopenharmony_ci	if (ret < 0) {
3266cd6a6acSopenharmony_ci		return NULL;
3276cd6a6acSopenharmony_ci	}
3286cd6a6acSopenharmony_ci
3296cd6a6acSopenharmony_ci	/* create a new role_datum_t for this decl, if necessary */
3306cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
3316cd6a6acSopenharmony_ci
3326cd6a6acSopenharmony_ci	if (stack_top->parent == NULL) {
3336cd6a6acSopenharmony_ci		/* in parent, so use global symbol table */
3346cd6a6acSopenharmony_ci		roles_tab = policydbp->p_roles.table;
3356cd6a6acSopenharmony_ci	} else {
3366cd6a6acSopenharmony_ci		roles_tab = stack_top->decl->p_roles.table;
3376cd6a6acSopenharmony_ci	}
3386cd6a6acSopenharmony_ci
3396cd6a6acSopenharmony_ci	dest_role = hashtab_search(roles_tab, key);
3406cd6a6acSopenharmony_ci	if (dest_role == NULL) {
3416cd6a6acSopenharmony_ci		if (ret == 0) {
3426cd6a6acSopenharmony_ci			dest_role = malloc(sizeof(*dest_role));
3436cd6a6acSopenharmony_ci			if (dest_role == NULL) {
3446cd6a6acSopenharmony_ci				yyerror("Out of memory!");
3456cd6a6acSopenharmony_ci				free(key);
3466cd6a6acSopenharmony_ci				return NULL;
3476cd6a6acSopenharmony_ci			}
3486cd6a6acSopenharmony_ci			role_datum_init(dest_role);
3496cd6a6acSopenharmony_ci			dest_role->s.value = role->s.value;
3506cd6a6acSopenharmony_ci			dest_role->flavor = role->flavor;
3516cd6a6acSopenharmony_ci		} else {
3526cd6a6acSopenharmony_ci			dest_role = role;
3536cd6a6acSopenharmony_ci		}
3546cd6a6acSopenharmony_ci		ret2 = role_implicit_bounds(roles_tab, key, dest_role);
3556cd6a6acSopenharmony_ci		if (ret2 != 0) {
3566cd6a6acSopenharmony_ci			free(key);
3576cd6a6acSopenharmony_ci			role_datum_destroy(dest_role);
3586cd6a6acSopenharmony_ci			free(dest_role);
3596cd6a6acSopenharmony_ci			return NULL;
3606cd6a6acSopenharmony_ci		}
3616cd6a6acSopenharmony_ci		ret2 = hashtab_insert(roles_tab, key, dest_role);
3626cd6a6acSopenharmony_ci		if (ret2 != 0) {
3636cd6a6acSopenharmony_ci			yyerror("Out of memory!");
3646cd6a6acSopenharmony_ci			free(key);
3656cd6a6acSopenharmony_ci			role_datum_destroy(dest_role);
3666cd6a6acSopenharmony_ci			free(dest_role);
3676cd6a6acSopenharmony_ci			return NULL;
3686cd6a6acSopenharmony_ci		}
3696cd6a6acSopenharmony_ci	} else {
3706cd6a6acSopenharmony_ci		free(key);
3716cd6a6acSopenharmony_ci		if (ret == 1) {
3726cd6a6acSopenharmony_ci			role_datum_destroy(role);
3736cd6a6acSopenharmony_ci			free(role);
3746cd6a6acSopenharmony_ci		}
3756cd6a6acSopenharmony_ci	}
3766cd6a6acSopenharmony_ci
3776cd6a6acSopenharmony_ci	if (ret == 0) {
3786cd6a6acSopenharmony_ci		ret2 = ebitmap_set_bit(&dest_role->dominates, dest_role->s.value - 1, 1);
3796cd6a6acSopenharmony_ci		if (ret2 != 0) {
3806cd6a6acSopenharmony_ci			yyerror("out of memory");
3816cd6a6acSopenharmony_ci			return NULL;
3826cd6a6acSopenharmony_ci		}
3836cd6a6acSopenharmony_ci	}
3846cd6a6acSopenharmony_ci
3856cd6a6acSopenharmony_ci	return dest_role;
3866cd6a6acSopenharmony_ci}
3876cd6a6acSopenharmony_ci
3886cd6a6acSopenharmony_cistatic int create_type(uint32_t scope, unsigned char isattr, type_datum_t **type)
3896cd6a6acSopenharmony_ci{
3906cd6a6acSopenharmony_ci	char *id;
3916cd6a6acSopenharmony_ci	type_datum_t *datum;
3926cd6a6acSopenharmony_ci	int ret;
3936cd6a6acSopenharmony_ci	uint32_t value = 0;
3946cd6a6acSopenharmony_ci
3956cd6a6acSopenharmony_ci	*type = NULL;
3966cd6a6acSopenharmony_ci	isattr = isattr ? TYPE_ATTRIB : TYPE_TYPE;
3976cd6a6acSopenharmony_ci
3986cd6a6acSopenharmony_ci	id = (char *)queue_remove(id_queue);
3996cd6a6acSopenharmony_ci	if (!id) {
4006cd6a6acSopenharmony_ci		yyerror("no type/attribute name?");
4016cd6a6acSopenharmony_ci		return -1;
4026cd6a6acSopenharmony_ci	}
4036cd6a6acSopenharmony_ci	if (strcmp(id, "self") == 0) {
4046cd6a6acSopenharmony_ci		yyerror("\"self\" is a reserved type name.");
4056cd6a6acSopenharmony_ci		free(id);
4066cd6a6acSopenharmony_ci		return -1;
4076cd6a6acSopenharmony_ci	}
4086cd6a6acSopenharmony_ci
4096cd6a6acSopenharmony_ci	datum = malloc(sizeof(*datum));
4106cd6a6acSopenharmony_ci	if (!datum) {
4116cd6a6acSopenharmony_ci		yyerror("Out of memory!");
4126cd6a6acSopenharmony_ci		free(id);
4136cd6a6acSopenharmony_ci		return -1;
4146cd6a6acSopenharmony_ci	}
4156cd6a6acSopenharmony_ci	type_datum_init(datum);
4166cd6a6acSopenharmony_ci	datum->primary = 1;
4176cd6a6acSopenharmony_ci	datum->flavor = isattr;
4186cd6a6acSopenharmony_ci
4196cd6a6acSopenharmony_ci	if (scope == SCOPE_DECL) {
4206cd6a6acSopenharmony_ci		ret = declare_symbol(SYM_TYPES, id, datum, &value, &value);
4216cd6a6acSopenharmony_ci	} else {
4226cd6a6acSopenharmony_ci		ret = require_symbol(SYM_TYPES, id, datum, &value, &value);
4236cd6a6acSopenharmony_ci	}
4246cd6a6acSopenharmony_ci
4256cd6a6acSopenharmony_ci	if (ret == 0) {
4266cd6a6acSopenharmony_ci		datum->s.value = value;
4276cd6a6acSopenharmony_ci		*type = datum;
4286cd6a6acSopenharmony_ci	} else if (ret == 1) {
4296cd6a6acSopenharmony_ci		type_datum_destroy(datum);
4306cd6a6acSopenharmony_ci		free(datum);
4316cd6a6acSopenharmony_ci		*type = hashtab_search(policydbp->symtab[SYM_TYPES].table, id);
4326cd6a6acSopenharmony_ci		if (*type && (isattr != (*type)->flavor)) {
4336cd6a6acSopenharmony_ci			yyerror2("Identifier %s used as both an attribute and a type",
4346cd6a6acSopenharmony_ci				 id);
4356cd6a6acSopenharmony_ci			free(id);
4366cd6a6acSopenharmony_ci			return -1;
4376cd6a6acSopenharmony_ci		}
4386cd6a6acSopenharmony_ci		free(id);
4396cd6a6acSopenharmony_ci	} else {
4406cd6a6acSopenharmony_ci		print_error_msg(ret, SYM_TYPES);
4416cd6a6acSopenharmony_ci		free(id);
4426cd6a6acSopenharmony_ci		type_datum_destroy(datum);
4436cd6a6acSopenharmony_ci		free(datum);
4446cd6a6acSopenharmony_ci	}
4456cd6a6acSopenharmony_ci
4466cd6a6acSopenharmony_ci	return ret;
4476cd6a6acSopenharmony_ci}
4486cd6a6acSopenharmony_ci
4496cd6a6acSopenharmony_citype_datum_t *declare_type(unsigned char primary, unsigned char isattr)
4506cd6a6acSopenharmony_ci{
4516cd6a6acSopenharmony_ci	type_datum_t *type = NULL;
4526cd6a6acSopenharmony_ci	int ret = create_type(SCOPE_DECL, isattr, &type);
4536cd6a6acSopenharmony_ci
4546cd6a6acSopenharmony_ci	if (ret == 0) {
4556cd6a6acSopenharmony_ci		type->primary = primary;
4566cd6a6acSopenharmony_ci	}
4576cd6a6acSopenharmony_ci
4586cd6a6acSopenharmony_ci	return type;
4596cd6a6acSopenharmony_ci}
4606cd6a6acSopenharmony_ci
4616cd6a6acSopenharmony_cistatic int user_implicit_bounds(hashtab_t users_tab,
4626cd6a6acSopenharmony_ci				char *user_id, user_datum_t *user)
4636cd6a6acSopenharmony_ci{
4646cd6a6acSopenharmony_ci	user_datum_t *bounds;
4656cd6a6acSopenharmony_ci	char *bounds_id, *delim;
4666cd6a6acSopenharmony_ci
4676cd6a6acSopenharmony_ci	delim = strrchr(user_id, '.');
4686cd6a6acSopenharmony_ci	if (!delim)
4696cd6a6acSopenharmony_ci		return 0;	/* no implicit boundary */
4706cd6a6acSopenharmony_ci
4716cd6a6acSopenharmony_ci	bounds_id = strdup(user_id);
4726cd6a6acSopenharmony_ci	if (!bounds_id) {
4736cd6a6acSopenharmony_ci		yyerror("out of memory");
4746cd6a6acSopenharmony_ci		return -1;
4756cd6a6acSopenharmony_ci	}
4766cd6a6acSopenharmony_ci	bounds_id[(size_t)(delim - user_id)] = '\0';
4776cd6a6acSopenharmony_ci
4786cd6a6acSopenharmony_ci	bounds = hashtab_search(users_tab, bounds_id);
4796cd6a6acSopenharmony_ci	if (!bounds) {
4806cd6a6acSopenharmony_ci		yyerror2("user %s doesn't exist, is implicit bounds of %s",
4816cd6a6acSopenharmony_ci			 bounds_id, user_id);
4826cd6a6acSopenharmony_ci		return -1;
4836cd6a6acSopenharmony_ci	}
4846cd6a6acSopenharmony_ci
4856cd6a6acSopenharmony_ci	if (!user->bounds)
4866cd6a6acSopenharmony_ci		user->bounds = bounds->s.value;
4876cd6a6acSopenharmony_ci	else if (user->bounds != bounds->s.value) {
4886cd6a6acSopenharmony_ci		yyerror2("user %s has inconsistent bounds %s/%s",
4896cd6a6acSopenharmony_ci			 user_id, bounds_id,
4906cd6a6acSopenharmony_ci			 policydbp->p_role_val_to_name[user->bounds - 1]);
4916cd6a6acSopenharmony_ci		return -1;
4926cd6a6acSopenharmony_ci	}
4936cd6a6acSopenharmony_ci	free(bounds_id);
4946cd6a6acSopenharmony_ci
4956cd6a6acSopenharmony_ci	return 0;
4966cd6a6acSopenharmony_ci}
4976cd6a6acSopenharmony_ci
4986cd6a6acSopenharmony_cistatic int create_user(uint32_t scope, user_datum_t **user, char **key)
4996cd6a6acSopenharmony_ci{
5006cd6a6acSopenharmony_ci	char *id = queue_remove(id_queue);
5016cd6a6acSopenharmony_ci	user_datum_t *datum = NULL;
5026cd6a6acSopenharmony_ci	int ret;
5036cd6a6acSopenharmony_ci	uint32_t value;
5046cd6a6acSopenharmony_ci
5056cd6a6acSopenharmony_ci	*user = NULL;
5066cd6a6acSopenharmony_ci	*key = NULL;
5076cd6a6acSopenharmony_ci
5086cd6a6acSopenharmony_ci	if (id == NULL) {
5096cd6a6acSopenharmony_ci		yyerror("no user name");
5106cd6a6acSopenharmony_ci		return -1;
5116cd6a6acSopenharmony_ci	}
5126cd6a6acSopenharmony_ci
5136cd6a6acSopenharmony_ci	datum = malloc(sizeof(*datum));
5146cd6a6acSopenharmony_ci	if (datum == NULL) {
5156cd6a6acSopenharmony_ci		yyerror("Out of memory!");
5166cd6a6acSopenharmony_ci		free(id);
5176cd6a6acSopenharmony_ci		return -1;
5186cd6a6acSopenharmony_ci	}
5196cd6a6acSopenharmony_ci
5206cd6a6acSopenharmony_ci	user_datum_init(datum);
5216cd6a6acSopenharmony_ci
5226cd6a6acSopenharmony_ci	if (scope == SCOPE_DECL) {
5236cd6a6acSopenharmony_ci		ret = declare_symbol(SYM_USERS, id, datum, &value, &value);
5246cd6a6acSopenharmony_ci	} else {
5256cd6a6acSopenharmony_ci		ret = require_symbol(SYM_USERS, id, datum, &value, &value);
5266cd6a6acSopenharmony_ci	}
5276cd6a6acSopenharmony_ci
5286cd6a6acSopenharmony_ci	datum->s.value = value;
5296cd6a6acSopenharmony_ci
5306cd6a6acSopenharmony_ci	if (ret == 0) {
5316cd6a6acSopenharmony_ci		*user = datum;
5326cd6a6acSopenharmony_ci		*key = strdup(id);
5336cd6a6acSopenharmony_ci		if (*key == NULL) {
5346cd6a6acSopenharmony_ci			yyerror("Out of memory!");
5356cd6a6acSopenharmony_ci			return -1;
5366cd6a6acSopenharmony_ci		}
5376cd6a6acSopenharmony_ci	} else if (ret == 1) {
5386cd6a6acSopenharmony_ci		*user = datum;
5396cd6a6acSopenharmony_ci		*key = id;
5406cd6a6acSopenharmony_ci	} else {
5416cd6a6acSopenharmony_ci		print_error_msg(ret, SYM_USERS);
5426cd6a6acSopenharmony_ci		free(id);
5436cd6a6acSopenharmony_ci		user_datum_destroy(datum);
5446cd6a6acSopenharmony_ci		free(datum);
5456cd6a6acSopenharmony_ci	}
5466cd6a6acSopenharmony_ci
5476cd6a6acSopenharmony_ci	return ret;
5486cd6a6acSopenharmony_ci}
5496cd6a6acSopenharmony_ci
5506cd6a6acSopenharmony_ciuser_datum_t *declare_user(void)
5516cd6a6acSopenharmony_ci{
5526cd6a6acSopenharmony_ci	char *key = NULL;
5536cd6a6acSopenharmony_ci	user_datum_t *user = NULL;
5546cd6a6acSopenharmony_ci	user_datum_t *dest_user = NULL;
5556cd6a6acSopenharmony_ci	hashtab_t users_tab;
5566cd6a6acSopenharmony_ci	int ret, ret2;
5576cd6a6acSopenharmony_ci
5586cd6a6acSopenharmony_ci	ret = create_user(SCOPE_DECL, &user, &key);
5596cd6a6acSopenharmony_ci	if (ret < 0) {
5606cd6a6acSopenharmony_ci		return NULL;
5616cd6a6acSopenharmony_ci	}
5626cd6a6acSopenharmony_ci
5636cd6a6acSopenharmony_ci	/* create a new user_datum_t for this decl, if necessary */
5646cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
5656cd6a6acSopenharmony_ci
5666cd6a6acSopenharmony_ci	if (stack_top->parent == NULL) {
5676cd6a6acSopenharmony_ci		/* in parent, so use global symbol table */
5686cd6a6acSopenharmony_ci		users_tab = policydbp->p_users.table;
5696cd6a6acSopenharmony_ci	} else {
5706cd6a6acSopenharmony_ci		users_tab = stack_top->decl->p_users.table;
5716cd6a6acSopenharmony_ci	}
5726cd6a6acSopenharmony_ci
5736cd6a6acSopenharmony_ci	dest_user = hashtab_search(users_tab, key);
5746cd6a6acSopenharmony_ci	if (dest_user == NULL) {
5756cd6a6acSopenharmony_ci		if (ret == 0) {
5766cd6a6acSopenharmony_ci			dest_user = malloc(sizeof(*dest_user));
5776cd6a6acSopenharmony_ci			if (dest_user == NULL) {
5786cd6a6acSopenharmony_ci				yyerror("Out of memory!");
5796cd6a6acSopenharmony_ci				free(key);
5806cd6a6acSopenharmony_ci				return NULL;
5816cd6a6acSopenharmony_ci			}
5826cd6a6acSopenharmony_ci			user_datum_init(dest_user);
5836cd6a6acSopenharmony_ci			dest_user->s.value = user->s.value;
5846cd6a6acSopenharmony_ci		} else {
5856cd6a6acSopenharmony_ci			dest_user = user;
5866cd6a6acSopenharmony_ci		}
5876cd6a6acSopenharmony_ci		ret2 = user_implicit_bounds(users_tab, key, dest_user);
5886cd6a6acSopenharmony_ci		if (ret2 != 0) {
5896cd6a6acSopenharmony_ci			free(key);
5906cd6a6acSopenharmony_ci			user_datum_destroy(dest_user);
5916cd6a6acSopenharmony_ci			free(dest_user);
5926cd6a6acSopenharmony_ci			return NULL;
5936cd6a6acSopenharmony_ci		}
5946cd6a6acSopenharmony_ci		ret2 = hashtab_insert(users_tab, key, dest_user);
5956cd6a6acSopenharmony_ci		if (ret2 != 0) {
5966cd6a6acSopenharmony_ci			yyerror("Out of memory!");
5976cd6a6acSopenharmony_ci			free(key);
5986cd6a6acSopenharmony_ci			user_datum_destroy(dest_user);
5996cd6a6acSopenharmony_ci			free(dest_user);
6006cd6a6acSopenharmony_ci			return NULL;
6016cd6a6acSopenharmony_ci		}
6026cd6a6acSopenharmony_ci	} else {
6036cd6a6acSopenharmony_ci		free(key);
6046cd6a6acSopenharmony_ci		if (ret == 1) {
6056cd6a6acSopenharmony_ci			user_datum_destroy(user);
6066cd6a6acSopenharmony_ci			free(user);
6076cd6a6acSopenharmony_ci		}
6086cd6a6acSopenharmony_ci	}
6096cd6a6acSopenharmony_ci
6106cd6a6acSopenharmony_ci	return dest_user;
6116cd6a6acSopenharmony_ci}
6126cd6a6acSopenharmony_ci
6136cd6a6acSopenharmony_ci/* Return a type_datum_t for the local avrule_decl with the given ID.
6146cd6a6acSopenharmony_ci * If it does not exist, create one with the same value as 'value'.
6156cd6a6acSopenharmony_ci * This function assumes that the ID is within scope.  c.f.,
6166cd6a6acSopenharmony_ci * is_id_in_scope().
6176cd6a6acSopenharmony_ci *
6186cd6a6acSopenharmony_ci * NOTE: this function usurps ownership of id afterwards.  The caller
6196cd6a6acSopenharmony_ci * shall not reference it nor free() it afterwards.
6206cd6a6acSopenharmony_ci */
6216cd6a6acSopenharmony_citype_datum_t *get_local_type(char *id, uint32_t value, unsigned char isattr)
6226cd6a6acSopenharmony_ci{
6236cd6a6acSopenharmony_ci	type_datum_t *dest_typdatum;
6246cd6a6acSopenharmony_ci	hashtab_t types_tab;
6256cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
6266cd6a6acSopenharmony_ci	if (stack_top->parent == NULL) {
6276cd6a6acSopenharmony_ci		/* in global, so use global symbol table */
6286cd6a6acSopenharmony_ci		types_tab = policydbp->p_types.table;
6296cd6a6acSopenharmony_ci	} else {
6306cd6a6acSopenharmony_ci		types_tab = stack_top->decl->p_types.table;
6316cd6a6acSopenharmony_ci	}
6326cd6a6acSopenharmony_ci	dest_typdatum = hashtab_search(types_tab, id);
6336cd6a6acSopenharmony_ci	if (!dest_typdatum) {
6346cd6a6acSopenharmony_ci		dest_typdatum = (type_datum_t *) malloc(sizeof(type_datum_t));
6356cd6a6acSopenharmony_ci		if (dest_typdatum == NULL) {
6366cd6a6acSopenharmony_ci			free(id);
6376cd6a6acSopenharmony_ci			return NULL;
6386cd6a6acSopenharmony_ci		}
6396cd6a6acSopenharmony_ci		type_datum_init(dest_typdatum);
6406cd6a6acSopenharmony_ci		dest_typdatum->s.value = value;
6416cd6a6acSopenharmony_ci		dest_typdatum->flavor = isattr ? TYPE_ATTRIB : TYPE_TYPE;
6426cd6a6acSopenharmony_ci		dest_typdatum->primary = 1;
6436cd6a6acSopenharmony_ci		if (hashtab_insert(types_tab, id, dest_typdatum)) {
6446cd6a6acSopenharmony_ci			free(id);
6456cd6a6acSopenharmony_ci			type_datum_destroy(dest_typdatum);
6466cd6a6acSopenharmony_ci			free(dest_typdatum);
6476cd6a6acSopenharmony_ci			return NULL;
6486cd6a6acSopenharmony_ci		}
6496cd6a6acSopenharmony_ci
6506cd6a6acSopenharmony_ci	} else {
6516cd6a6acSopenharmony_ci		free(id);
6526cd6a6acSopenharmony_ci		if (dest_typdatum->flavor != isattr ? TYPE_ATTRIB : TYPE_TYPE) {
6536cd6a6acSopenharmony_ci			return NULL;
6546cd6a6acSopenharmony_ci		}
6556cd6a6acSopenharmony_ci	}
6566cd6a6acSopenharmony_ci	return dest_typdatum;
6576cd6a6acSopenharmony_ci}
6586cd6a6acSopenharmony_ci
6596cd6a6acSopenharmony_ci/* Return a role_datum_t for the local avrule_decl with the given ID.
6606cd6a6acSopenharmony_ci * If it does not exist, create one with the same value as 'value'.
6616cd6a6acSopenharmony_ci * This function assumes that the ID is within scope.  c.f.,
6626cd6a6acSopenharmony_ci * is_id_in_scope().
6636cd6a6acSopenharmony_ci *
6646cd6a6acSopenharmony_ci * NOTE: this function usurps ownership of id afterwards.  The caller
6656cd6a6acSopenharmony_ci * shall not reference it nor free() it afterwards.
6666cd6a6acSopenharmony_ci */
6676cd6a6acSopenharmony_cirole_datum_t *get_local_role(char *id, uint32_t value, unsigned char isattr)
6686cd6a6acSopenharmony_ci{
6696cd6a6acSopenharmony_ci	role_datum_t *dest_roledatum;
6706cd6a6acSopenharmony_ci	hashtab_t roles_tab;
6716cd6a6acSopenharmony_ci
6726cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
6736cd6a6acSopenharmony_ci
6746cd6a6acSopenharmony_ci	if (stack_top->parent == NULL) {
6756cd6a6acSopenharmony_ci		/* in global, so use global symbol table */
6766cd6a6acSopenharmony_ci		roles_tab = policydbp->p_roles.table;
6776cd6a6acSopenharmony_ci	} else {
6786cd6a6acSopenharmony_ci		roles_tab = stack_top->decl->p_roles.table;
6796cd6a6acSopenharmony_ci	}
6806cd6a6acSopenharmony_ci
6816cd6a6acSopenharmony_ci	dest_roledatum = hashtab_search(roles_tab, id);
6826cd6a6acSopenharmony_ci	if (!dest_roledatum) {
6836cd6a6acSopenharmony_ci		dest_roledatum = (role_datum_t *)malloc(sizeof(role_datum_t));
6846cd6a6acSopenharmony_ci		if (dest_roledatum == NULL) {
6856cd6a6acSopenharmony_ci			free(id);
6866cd6a6acSopenharmony_ci			return NULL;
6876cd6a6acSopenharmony_ci		}
6886cd6a6acSopenharmony_ci
6896cd6a6acSopenharmony_ci		role_datum_init(dest_roledatum);
6906cd6a6acSopenharmony_ci		dest_roledatum->s.value = value;
6916cd6a6acSopenharmony_ci		dest_roledatum->flavor = isattr ? ROLE_ATTRIB : ROLE_ROLE;
6926cd6a6acSopenharmony_ci
6936cd6a6acSopenharmony_ci		if (hashtab_insert(roles_tab, id, dest_roledatum)) {
6946cd6a6acSopenharmony_ci			free(id);
6956cd6a6acSopenharmony_ci			role_datum_destroy(dest_roledatum);
6966cd6a6acSopenharmony_ci			free(dest_roledatum);
6976cd6a6acSopenharmony_ci			return NULL;
6986cd6a6acSopenharmony_ci		}
6996cd6a6acSopenharmony_ci	} else {
7006cd6a6acSopenharmony_ci		free(id);
7016cd6a6acSopenharmony_ci		if (dest_roledatum->flavor != isattr ? ROLE_ATTRIB : ROLE_ROLE)
7026cd6a6acSopenharmony_ci			return NULL;
7036cd6a6acSopenharmony_ci	}
7046cd6a6acSopenharmony_ci
7056cd6a6acSopenharmony_ci	return dest_roledatum;
7066cd6a6acSopenharmony_ci}
7076cd6a6acSopenharmony_ci
7086cd6a6acSopenharmony_ci/* Attempt to require a symbol within the current scope.  If currently
7096cd6a6acSopenharmony_ci * within an optional (and not its else branch), add the symbol to the
7106cd6a6acSopenharmony_ci * required list.  Return 0 on success, 1 if caller needs to free()
7116cd6a6acSopenharmony_ci * datum.  If symbols may not be declared here return -1.  For duplicate
7126cd6a6acSopenharmony_ci * declarations return -2.  For all else, including out of memory,
7136cd6a6acSopenharmony_ci * return -3..  Note that dest_value and datum_value might not be
7146cd6a6acSopenharmony_ci * restricted pointers.
7156cd6a6acSopenharmony_ci */
7166cd6a6acSopenharmony_ciint require_symbol(uint32_t symbol_type,
7176cd6a6acSopenharmony_ci		   hashtab_key_t key, hashtab_datum_t datum,
7186cd6a6acSopenharmony_ci		   uint32_t * dest_value, uint32_t * datum_value)
7196cd6a6acSopenharmony_ci{
7206cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
7216cd6a6acSopenharmony_ci	int ret = create_symbol(symbol_type, key, datum, dest_value, SCOPE_REQ);
7226cd6a6acSopenharmony_ci
7236cd6a6acSopenharmony_ci	if (ret < 0) {
7246cd6a6acSopenharmony_ci		return ret;
7256cd6a6acSopenharmony_ci	}
7266cd6a6acSopenharmony_ci
7276cd6a6acSopenharmony_ci	if (ebitmap_set_bit(decl->required.scope + symbol_type,
7286cd6a6acSopenharmony_ci			    *datum_value - 1, 1)) {
7296cd6a6acSopenharmony_ci		return -3;
7306cd6a6acSopenharmony_ci	}
7316cd6a6acSopenharmony_ci
7326cd6a6acSopenharmony_ci	stack_top->require_given = 1;
7336cd6a6acSopenharmony_ci	return ret;
7346cd6a6acSopenharmony_ci}
7356cd6a6acSopenharmony_ci
7366cd6a6acSopenharmony_ciint add_perm_to_class(uint32_t perm_value, uint32_t class_value)
7376cd6a6acSopenharmony_ci{
7386cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
7396cd6a6acSopenharmony_ci	scope_index_t *scope;
7406cd6a6acSopenharmony_ci
7416cd6a6acSopenharmony_ci	assert(perm_value >= 1);
7426cd6a6acSopenharmony_ci	assert(class_value >= 1);
7436cd6a6acSopenharmony_ci	scope = &decl->required;
7446cd6a6acSopenharmony_ci	if (class_value > scope->class_perms_len) {
7456cd6a6acSopenharmony_ci		uint32_t i;
7466cd6a6acSopenharmony_ci		ebitmap_t *new_map = realloc(scope->class_perms_map,
7476cd6a6acSopenharmony_ci					     class_value * sizeof(*new_map));
7486cd6a6acSopenharmony_ci		if (new_map == NULL) {
7496cd6a6acSopenharmony_ci			return -1;
7506cd6a6acSopenharmony_ci		}
7516cd6a6acSopenharmony_ci		scope->class_perms_map = new_map;
7526cd6a6acSopenharmony_ci		for (i = scope->class_perms_len; i < class_value; i++) {
7536cd6a6acSopenharmony_ci			ebitmap_init(scope->class_perms_map + i);
7546cd6a6acSopenharmony_ci		}
7556cd6a6acSopenharmony_ci		scope->class_perms_len = class_value;
7566cd6a6acSopenharmony_ci	}
7576cd6a6acSopenharmony_ci	if (ebitmap_set_bit(scope->class_perms_map + class_value - 1,
7586cd6a6acSopenharmony_ci			    perm_value - 1, 1)) {
7596cd6a6acSopenharmony_ci		return -1;
7606cd6a6acSopenharmony_ci	}
7616cd6a6acSopenharmony_ci	return 0;
7626cd6a6acSopenharmony_ci}
7636cd6a6acSopenharmony_ci
7646cd6a6acSopenharmony_cistatic int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
7656cd6a6acSopenharmony_ci			__attribute__ ((unused)))
7666cd6a6acSopenharmony_ci{
7676cd6a6acSopenharmony_ci	if (key)
7686cd6a6acSopenharmony_ci		free(key);
7696cd6a6acSopenharmony_ci	free(datum);
7706cd6a6acSopenharmony_ci	return 0;
7716cd6a6acSopenharmony_ci}
7726cd6a6acSopenharmony_ci
7736cd6a6acSopenharmony_cistatic void class_datum_destroy(class_datum_t * cladatum)
7746cd6a6acSopenharmony_ci{
7756cd6a6acSopenharmony_ci	if (cladatum != NULL) {
7766cd6a6acSopenharmony_ci		hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
7776cd6a6acSopenharmony_ci		hashtab_destroy(cladatum->permissions.table);
7786cd6a6acSopenharmony_ci		free(cladatum);
7796cd6a6acSopenharmony_ci	}
7806cd6a6acSopenharmony_ci}
7816cd6a6acSopenharmony_ci
7826cd6a6acSopenharmony_ciint require_class(int pass)
7836cd6a6acSopenharmony_ci{
7846cd6a6acSopenharmony_ci	char *class_id = queue_remove(id_queue);
7856cd6a6acSopenharmony_ci	char *perm_id = NULL;
7866cd6a6acSopenharmony_ci	class_datum_t *datum = NULL;
7876cd6a6acSopenharmony_ci	perm_datum_t *perm = NULL;
7886cd6a6acSopenharmony_ci	int ret;
7896cd6a6acSopenharmony_ci
7906cd6a6acSopenharmony_ci	if (pass == 2) {
7916cd6a6acSopenharmony_ci		free(class_id);
7926cd6a6acSopenharmony_ci		while ((perm_id = queue_remove(id_queue)) != NULL)
7936cd6a6acSopenharmony_ci			free(perm_id);
7946cd6a6acSopenharmony_ci		return 0;
7956cd6a6acSopenharmony_ci	}
7966cd6a6acSopenharmony_ci
7976cd6a6acSopenharmony_ci	/* first add the class if it is not already there */
7986cd6a6acSopenharmony_ci	if (class_id == NULL) {
7996cd6a6acSopenharmony_ci		yyerror("no class name for class definition?");
8006cd6a6acSopenharmony_ci		return -1;
8016cd6a6acSopenharmony_ci	}
8026cd6a6acSopenharmony_ci
8036cd6a6acSopenharmony_ci	if ((datum = calloc(1, sizeof(*datum))) == NULL ||
8046cd6a6acSopenharmony_ci	    symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) {
8056cd6a6acSopenharmony_ci		yyerror("Out of memory!");
8066cd6a6acSopenharmony_ci		class_datum_destroy(datum);
8076cd6a6acSopenharmony_ci		return -1;
8086cd6a6acSopenharmony_ci	}
8096cd6a6acSopenharmony_ci	ret =
8106cd6a6acSopenharmony_ci	    require_symbol(SYM_CLASSES, class_id, datum, &datum->s.value,
8116cd6a6acSopenharmony_ci			   &datum->s.value);
8126cd6a6acSopenharmony_ci	if (ret < 0) {
8136cd6a6acSopenharmony_ci		print_error_msg(ret, SYM_CLASSES);
8146cd6a6acSopenharmony_ci		free(class_id);
8156cd6a6acSopenharmony_ci		class_datum_destroy(datum);
8166cd6a6acSopenharmony_ci		return -1;
8176cd6a6acSopenharmony_ci	}
8186cd6a6acSopenharmony_ci
8196cd6a6acSopenharmony_ci	if (ret == 0) {
8206cd6a6acSopenharmony_ci		/* a new class was added; reindex everything */
8216cd6a6acSopenharmony_ci		if (policydb_index_classes(policydbp)) {
8226cd6a6acSopenharmony_ci			yyerror("Out of memory!");
8236cd6a6acSopenharmony_ci			return -1;
8246cd6a6acSopenharmony_ci		}
8256cd6a6acSopenharmony_ci	} else {
8266cd6a6acSopenharmony_ci		class_datum_destroy(datum);
8276cd6a6acSopenharmony_ci		datum = hashtab_search(policydbp->p_classes.table, class_id);
8286cd6a6acSopenharmony_ci		assert(datum);	/* the class datum should have existed */
8296cd6a6acSopenharmony_ci		free(class_id);
8306cd6a6acSopenharmony_ci	}
8316cd6a6acSopenharmony_ci
8326cd6a6acSopenharmony_ci	/* now add each of the permissions to this class's requirements */
8336cd6a6acSopenharmony_ci	while ((perm_id = queue_remove(id_queue)) != NULL) {
8346cd6a6acSopenharmony_ci		int allocated = 0;
8356cd6a6acSopenharmony_ci
8366cd6a6acSopenharmony_ci		/* Is the permission already in the table? */
8376cd6a6acSopenharmony_ci		perm = hashtab_search(datum->permissions.table, perm_id);
8386cd6a6acSopenharmony_ci		if (!perm && datum->comdatum)
8396cd6a6acSopenharmony_ci			perm =
8406cd6a6acSopenharmony_ci			    hashtab_search(datum->comdatum->permissions.table,
8416cd6a6acSopenharmony_ci					   perm_id);
8426cd6a6acSopenharmony_ci		if (perm) {
8436cd6a6acSopenharmony_ci			/* Yes, drop the name. */
8446cd6a6acSopenharmony_ci			free(perm_id);
8456cd6a6acSopenharmony_ci		} else {
8466cd6a6acSopenharmony_ci			/* No - allocate and insert an entry for it. */
8476cd6a6acSopenharmony_ci			if (policydbp->policy_type == POLICY_BASE) {
8486cd6a6acSopenharmony_ci				yyerror2
8496cd6a6acSopenharmony_ci				    ("Base policy - require of permission %s without prior declaration.",
8506cd6a6acSopenharmony_ci				     perm_id);
8516cd6a6acSopenharmony_ci				free(perm_id);
8526cd6a6acSopenharmony_ci				return -1;
8536cd6a6acSopenharmony_ci			}
8546cd6a6acSopenharmony_ci			if (datum->permissions.nprim >= PERM_SYMTAB_SIZE) {
8556cd6a6acSopenharmony_ci				yyerror2("Class %s would have too many permissions "
8566cd6a6acSopenharmony_ci					 "to fit in an access vector with permission %s",
8576cd6a6acSopenharmony_ci					 policydbp->p_class_val_to_name[datum->s.value - 1],
8586cd6a6acSopenharmony_ci					 perm_id);
8596cd6a6acSopenharmony_ci				free(perm_id);
8606cd6a6acSopenharmony_ci				return -1;
8616cd6a6acSopenharmony_ci			}
8626cd6a6acSopenharmony_ci			allocated = 1;
8636cd6a6acSopenharmony_ci			if ((perm = malloc(sizeof(*perm))) == NULL) {
8646cd6a6acSopenharmony_ci				yyerror("Out of memory!");
8656cd6a6acSopenharmony_ci				free(perm_id);
8666cd6a6acSopenharmony_ci				return -1;
8676cd6a6acSopenharmony_ci			}
8686cd6a6acSopenharmony_ci			memset(perm, 0, sizeof(*perm));
8696cd6a6acSopenharmony_ci			ret =
8706cd6a6acSopenharmony_ci			    hashtab_insert(datum->permissions.table, perm_id,
8716cd6a6acSopenharmony_ci					   perm);
8726cd6a6acSopenharmony_ci			if (ret) {
8736cd6a6acSopenharmony_ci				yyerror("Out of memory!");
8746cd6a6acSopenharmony_ci				free(perm_id);
8756cd6a6acSopenharmony_ci				free(perm);
8766cd6a6acSopenharmony_ci				return -1;
8776cd6a6acSopenharmony_ci			}
8786cd6a6acSopenharmony_ci			perm->s.value = datum->permissions.nprim + 1;
8796cd6a6acSopenharmony_ci		}
8806cd6a6acSopenharmony_ci
8816cd6a6acSopenharmony_ci		if (add_perm_to_class(perm->s.value, datum->s.value) == -1) {
8826cd6a6acSopenharmony_ci			yyerror("Out of memory!");
8836cd6a6acSopenharmony_ci			return -1;
8846cd6a6acSopenharmony_ci		}
8856cd6a6acSopenharmony_ci
8866cd6a6acSopenharmony_ci		/* Update number of primitives if we allocated one. */
8876cd6a6acSopenharmony_ci		if (allocated)
8886cd6a6acSopenharmony_ci			datum->permissions.nprim++;
8896cd6a6acSopenharmony_ci	}
8906cd6a6acSopenharmony_ci	return 0;
8916cd6a6acSopenharmony_ci}
8926cd6a6acSopenharmony_ci
8936cd6a6acSopenharmony_cistatic int require_role_or_attribute(int pass, unsigned char isattr)
8946cd6a6acSopenharmony_ci{
8956cd6a6acSopenharmony_ci	char *key = NULL;
8966cd6a6acSopenharmony_ci	role_datum_t *role = NULL;
8976cd6a6acSopenharmony_ci	int ret;
8986cd6a6acSopenharmony_ci
8996cd6a6acSopenharmony_ci	if (pass == 2) {
9006cd6a6acSopenharmony_ci		free(queue_remove(id_queue));
9016cd6a6acSopenharmony_ci		return 0;
9026cd6a6acSopenharmony_ci	}
9036cd6a6acSopenharmony_ci
9046cd6a6acSopenharmony_ci	ret = create_role(SCOPE_REQ, isattr, &role, &key);
9056cd6a6acSopenharmony_ci	if (ret < 0) {
9066cd6a6acSopenharmony_ci		return -1;
9076cd6a6acSopenharmony_ci	}
9086cd6a6acSopenharmony_ci
9096cd6a6acSopenharmony_ci	free(key);
9106cd6a6acSopenharmony_ci
9116cd6a6acSopenharmony_ci	if (ret == 0) {
9126cd6a6acSopenharmony_ci		ret = ebitmap_set_bit(&role->dominates, role->s.value - 1, 1);
9136cd6a6acSopenharmony_ci		if (ret != 0) {
9146cd6a6acSopenharmony_ci			yyerror("Out of memory");
9156cd6a6acSopenharmony_ci			return -1;
9166cd6a6acSopenharmony_ci		}
9176cd6a6acSopenharmony_ci	} else {
9186cd6a6acSopenharmony_ci		role_datum_destroy(role);
9196cd6a6acSopenharmony_ci		free(role);
9206cd6a6acSopenharmony_ci	}
9216cd6a6acSopenharmony_ci
9226cd6a6acSopenharmony_ci	return 0;
9236cd6a6acSopenharmony_ci}
9246cd6a6acSopenharmony_ci
9256cd6a6acSopenharmony_ciint require_role(int pass)
9266cd6a6acSopenharmony_ci{
9276cd6a6acSopenharmony_ci	return require_role_or_attribute(pass, 0);
9286cd6a6acSopenharmony_ci}
9296cd6a6acSopenharmony_ci
9306cd6a6acSopenharmony_ciint require_attribute_role(int pass)
9316cd6a6acSopenharmony_ci{
9326cd6a6acSopenharmony_ci	return require_role_or_attribute(pass, 1);
9336cd6a6acSopenharmony_ci}
9346cd6a6acSopenharmony_ci
9356cd6a6acSopenharmony_cistatic int require_type_or_attribute(int pass, unsigned char isattr)
9366cd6a6acSopenharmony_ci{
9376cd6a6acSopenharmony_ci	type_datum_t *type = NULL;
9386cd6a6acSopenharmony_ci	int ret;
9396cd6a6acSopenharmony_ci
9406cd6a6acSopenharmony_ci	if (pass == 2) {
9416cd6a6acSopenharmony_ci		free(queue_remove(id_queue));
9426cd6a6acSopenharmony_ci		return 0;
9436cd6a6acSopenharmony_ci	}
9446cd6a6acSopenharmony_ci
9456cd6a6acSopenharmony_ci	ret = create_type(SCOPE_REQ, isattr, &type);
9466cd6a6acSopenharmony_ci
9476cd6a6acSopenharmony_ci	if (ret < 0) {
9486cd6a6acSopenharmony_ci		return -1;
9496cd6a6acSopenharmony_ci	}
9506cd6a6acSopenharmony_ci
9516cd6a6acSopenharmony_ci	return 0;
9526cd6a6acSopenharmony_ci}
9536cd6a6acSopenharmony_ci
9546cd6a6acSopenharmony_ciint require_type(int pass)
9556cd6a6acSopenharmony_ci{
9566cd6a6acSopenharmony_ci	return require_type_or_attribute(pass, 0);
9576cd6a6acSopenharmony_ci}
9586cd6a6acSopenharmony_ci
9596cd6a6acSopenharmony_ciint require_attribute(int pass)
9606cd6a6acSopenharmony_ci{
9616cd6a6acSopenharmony_ci	return require_type_or_attribute(pass, 1);
9626cd6a6acSopenharmony_ci}
9636cd6a6acSopenharmony_ci
9646cd6a6acSopenharmony_ciint require_user(int pass)
9656cd6a6acSopenharmony_ci{
9666cd6a6acSopenharmony_ci	char *key = NULL;
9676cd6a6acSopenharmony_ci	user_datum_t *user = NULL;
9686cd6a6acSopenharmony_ci	int ret;
9696cd6a6acSopenharmony_ci
9706cd6a6acSopenharmony_ci	if (pass == 1) {
9716cd6a6acSopenharmony_ci		free(queue_remove(id_queue));
9726cd6a6acSopenharmony_ci		return 0;
9736cd6a6acSopenharmony_ci	}
9746cd6a6acSopenharmony_ci
9756cd6a6acSopenharmony_ci	ret = create_user(SCOPE_REQ, &user, &key);
9766cd6a6acSopenharmony_ci	if (ret < 0) {
9776cd6a6acSopenharmony_ci		return -1;
9786cd6a6acSopenharmony_ci	}
9796cd6a6acSopenharmony_ci
9806cd6a6acSopenharmony_ci	free(key);
9816cd6a6acSopenharmony_ci
9826cd6a6acSopenharmony_ci	if (ret == 1) {
9836cd6a6acSopenharmony_ci		user_datum_destroy(user);
9846cd6a6acSopenharmony_ci		free(user);
9856cd6a6acSopenharmony_ci	}
9866cd6a6acSopenharmony_ci
9876cd6a6acSopenharmony_ci	return 0;
9886cd6a6acSopenharmony_ci}
9896cd6a6acSopenharmony_ci
9906cd6a6acSopenharmony_cistatic int require_bool_tunable(int pass, int is_tunable)
9916cd6a6acSopenharmony_ci{
9926cd6a6acSopenharmony_ci	char *id = queue_remove(id_queue);
9936cd6a6acSopenharmony_ci	cond_bool_datum_t *booldatum = NULL;
9946cd6a6acSopenharmony_ci	int retval;
9956cd6a6acSopenharmony_ci	if (pass == 2) {
9966cd6a6acSopenharmony_ci		free(id);
9976cd6a6acSopenharmony_ci		return 0;
9986cd6a6acSopenharmony_ci	}
9996cd6a6acSopenharmony_ci	if (id == NULL) {
10006cd6a6acSopenharmony_ci		yyerror("no boolean name");
10016cd6a6acSopenharmony_ci		return -1;
10026cd6a6acSopenharmony_ci	}
10036cd6a6acSopenharmony_ci	if ((booldatum = calloc(1, sizeof(*booldatum))) == NULL) {
10046cd6a6acSopenharmony_ci		cond_destroy_bool(id, booldatum, NULL);
10056cd6a6acSopenharmony_ci		yyerror("Out of memory!");
10066cd6a6acSopenharmony_ci		return -1;
10076cd6a6acSopenharmony_ci	}
10086cd6a6acSopenharmony_ci	if (is_tunable)
10096cd6a6acSopenharmony_ci		booldatum->flags |= COND_BOOL_FLAGS_TUNABLE;
10106cd6a6acSopenharmony_ci	retval =
10116cd6a6acSopenharmony_ci	    require_symbol(SYM_BOOLS, id, booldatum,
10126cd6a6acSopenharmony_ci			   &booldatum->s.value, &booldatum->s.value);
10136cd6a6acSopenharmony_ci	if (retval != 0) {
10146cd6a6acSopenharmony_ci		cond_destroy_bool(id, booldatum, NULL);
10156cd6a6acSopenharmony_ci		if (retval < 0) {
10166cd6a6acSopenharmony_ci			print_error_msg(retval, SYM_BOOLS);
10176cd6a6acSopenharmony_ci			return -1;
10186cd6a6acSopenharmony_ci		}
10196cd6a6acSopenharmony_ci	}
10206cd6a6acSopenharmony_ci
10216cd6a6acSopenharmony_ci	return 0;
10226cd6a6acSopenharmony_ci}
10236cd6a6acSopenharmony_ci
10246cd6a6acSopenharmony_ciint require_bool(int pass)
10256cd6a6acSopenharmony_ci{
10266cd6a6acSopenharmony_ci	return require_bool_tunable(pass, 0);
10276cd6a6acSopenharmony_ci}
10286cd6a6acSopenharmony_ci
10296cd6a6acSopenharmony_ciint require_tunable(int pass)
10306cd6a6acSopenharmony_ci{
10316cd6a6acSopenharmony_ci	return require_bool_tunable(pass, 1);
10326cd6a6acSopenharmony_ci}
10336cd6a6acSopenharmony_ci
10346cd6a6acSopenharmony_ciint require_sens(int pass)
10356cd6a6acSopenharmony_ci{
10366cd6a6acSopenharmony_ci	char *id = queue_remove(id_queue);
10376cd6a6acSopenharmony_ci	level_datum_t *level = NULL;
10386cd6a6acSopenharmony_ci	int retval;
10396cd6a6acSopenharmony_ci	if (pass == 2) {
10406cd6a6acSopenharmony_ci		free(id);
10416cd6a6acSopenharmony_ci		return 0;
10426cd6a6acSopenharmony_ci	}
10436cd6a6acSopenharmony_ci	if (!id) {
10446cd6a6acSopenharmony_ci		yyerror("no sensitivity name");
10456cd6a6acSopenharmony_ci		return -1;
10466cd6a6acSopenharmony_ci	}
10476cd6a6acSopenharmony_ci	level = malloc(sizeof(level_datum_t));
10486cd6a6acSopenharmony_ci	if (!level) {
10496cd6a6acSopenharmony_ci		free(id);
10506cd6a6acSopenharmony_ci		yyerror("Out of memory!");
10516cd6a6acSopenharmony_ci		return -1;
10526cd6a6acSopenharmony_ci	}
10536cd6a6acSopenharmony_ci	level_datum_init(level);
10546cd6a6acSopenharmony_ci	level->level = malloc(sizeof(mls_level_t));
10556cd6a6acSopenharmony_ci	if (!level->level) {
10566cd6a6acSopenharmony_ci		free(id);
10576cd6a6acSopenharmony_ci		level_datum_destroy(level);
10586cd6a6acSopenharmony_ci		free(level);
10596cd6a6acSopenharmony_ci		yyerror("Out of memory!");
10606cd6a6acSopenharmony_ci		return -1;
10616cd6a6acSopenharmony_ci	}
10626cd6a6acSopenharmony_ci	mls_level_init(level->level);
10636cd6a6acSopenharmony_ci	retval = require_symbol(SYM_LEVELS, id, level,
10646cd6a6acSopenharmony_ci				&level->level->sens, &level->level->sens);
10656cd6a6acSopenharmony_ci	if (retval != 0) {
10666cd6a6acSopenharmony_ci		free(id);
10676cd6a6acSopenharmony_ci		mls_level_destroy(level->level);
10686cd6a6acSopenharmony_ci		free(level->level);
10696cd6a6acSopenharmony_ci		level_datum_destroy(level);
10706cd6a6acSopenharmony_ci		free(level);
10716cd6a6acSopenharmony_ci		if (retval < 0) {
10726cd6a6acSopenharmony_ci			print_error_msg(retval, SYM_LEVELS);
10736cd6a6acSopenharmony_ci			return -1;
10746cd6a6acSopenharmony_ci		}
10756cd6a6acSopenharmony_ci	}
10766cd6a6acSopenharmony_ci
10776cd6a6acSopenharmony_ci	return 0;
10786cd6a6acSopenharmony_ci}
10796cd6a6acSopenharmony_ci
10806cd6a6acSopenharmony_ciint require_cat(int pass)
10816cd6a6acSopenharmony_ci{
10826cd6a6acSopenharmony_ci	char *id = queue_remove(id_queue);
10836cd6a6acSopenharmony_ci	cat_datum_t *cat = NULL;
10846cd6a6acSopenharmony_ci	int retval;
10856cd6a6acSopenharmony_ci	if (pass == 2) {
10866cd6a6acSopenharmony_ci		free(id);
10876cd6a6acSopenharmony_ci		return 0;
10886cd6a6acSopenharmony_ci	}
10896cd6a6acSopenharmony_ci	if (!id) {
10906cd6a6acSopenharmony_ci		yyerror("no category name");
10916cd6a6acSopenharmony_ci		return -1;
10926cd6a6acSopenharmony_ci	}
10936cd6a6acSopenharmony_ci	cat = malloc(sizeof(cat_datum_t));
10946cd6a6acSopenharmony_ci	if (!cat) {
10956cd6a6acSopenharmony_ci		free(id);
10966cd6a6acSopenharmony_ci		yyerror("Out of memory!");
10976cd6a6acSopenharmony_ci		return -1;
10986cd6a6acSopenharmony_ci	}
10996cd6a6acSopenharmony_ci	cat_datum_init(cat);
11006cd6a6acSopenharmony_ci
11016cd6a6acSopenharmony_ci	retval = require_symbol(SYM_CATS, id, cat,
11026cd6a6acSopenharmony_ci				&cat->s.value, &cat->s.value);
11036cd6a6acSopenharmony_ci	if (retval != 0) {
11046cd6a6acSopenharmony_ci		free(id);
11056cd6a6acSopenharmony_ci		cat_datum_destroy(cat);
11066cd6a6acSopenharmony_ci		free(cat);
11076cd6a6acSopenharmony_ci		if (retval < 0) {
11086cd6a6acSopenharmony_ci			print_error_msg(retval, SYM_CATS);
11096cd6a6acSopenharmony_ci			return -1;
11106cd6a6acSopenharmony_ci		}
11116cd6a6acSopenharmony_ci	}
11126cd6a6acSopenharmony_ci
11136cd6a6acSopenharmony_ci	return 0;
11146cd6a6acSopenharmony_ci}
11156cd6a6acSopenharmony_ci
11166cd6a6acSopenharmony_cistatic int is_scope_in_stack(const scope_datum_t * scope, const scope_stack_t * stack)
11176cd6a6acSopenharmony_ci{
11186cd6a6acSopenharmony_ci	uint32_t i;
11196cd6a6acSopenharmony_ci	if (stack == NULL) {
11206cd6a6acSopenharmony_ci		return 0;	/* no matching scope found */
11216cd6a6acSopenharmony_ci	}
11226cd6a6acSopenharmony_ci	if (stack->type == 1) {
11236cd6a6acSopenharmony_ci		const avrule_decl_t *decl = stack->decl;
11246cd6a6acSopenharmony_ci		for (i = 0; i < scope->decl_ids_len; i++) {
11256cd6a6acSopenharmony_ci			if (scope->decl_ids[i] == decl->decl_id) {
11266cd6a6acSopenharmony_ci				return 1;
11276cd6a6acSopenharmony_ci			}
11286cd6a6acSopenharmony_ci		}
11296cd6a6acSopenharmony_ci	} else {
11306cd6a6acSopenharmony_ci		/* note that conditionals can't declare or require
11316cd6a6acSopenharmony_ci		 * symbols, so skip this level */
11326cd6a6acSopenharmony_ci	}
11336cd6a6acSopenharmony_ci
11346cd6a6acSopenharmony_ci	/* not within scope of this stack, so try its parent */
11356cd6a6acSopenharmony_ci	return is_scope_in_stack(scope, stack->parent);
11366cd6a6acSopenharmony_ci}
11376cd6a6acSopenharmony_ci
11386cd6a6acSopenharmony_ciint is_id_in_scope(uint32_t symbol_type, const_hashtab_key_t id)
11396cd6a6acSopenharmony_ci{
11406cd6a6acSopenharmony_ci	const scope_datum_t *scope =
11416cd6a6acSopenharmony_ci	    (scope_datum_t *) hashtab_search(policydbp->scope[symbol_type].
11426cd6a6acSopenharmony_ci					     table, id);
11436cd6a6acSopenharmony_ci	if (scope == NULL) {
11446cd6a6acSopenharmony_ci		return 1;	/* id is not known, so return success */
11456cd6a6acSopenharmony_ci	}
11466cd6a6acSopenharmony_ci	return is_scope_in_stack(scope, stack_top);
11476cd6a6acSopenharmony_ci}
11486cd6a6acSopenharmony_ci
11496cd6a6acSopenharmony_cistatic int is_perm_in_scope_index(uint32_t perm_value, uint32_t class_value,
11506cd6a6acSopenharmony_ci				  const scope_index_t * scope)
11516cd6a6acSopenharmony_ci{
11526cd6a6acSopenharmony_ci	if (class_value > scope->class_perms_len) {
11536cd6a6acSopenharmony_ci		return 1;
11546cd6a6acSopenharmony_ci	}
11556cd6a6acSopenharmony_ci	if (ebitmap_get_bit(scope->class_perms_map + class_value - 1,
11566cd6a6acSopenharmony_ci			    perm_value - 1)) {
11576cd6a6acSopenharmony_ci		return 1;
11586cd6a6acSopenharmony_ci	}
11596cd6a6acSopenharmony_ci	return 0;
11606cd6a6acSopenharmony_ci}
11616cd6a6acSopenharmony_ci
11626cd6a6acSopenharmony_cistatic int is_perm_in_stack(uint32_t perm_value, uint32_t class_value,
11636cd6a6acSopenharmony_ci			    const scope_stack_t * stack)
11646cd6a6acSopenharmony_ci{
11656cd6a6acSopenharmony_ci	if (stack == NULL) {
11666cd6a6acSopenharmony_ci		return 0;	/* no matching scope found */
11676cd6a6acSopenharmony_ci	}
11686cd6a6acSopenharmony_ci	if (stack->type == 1) {
11696cd6a6acSopenharmony_ci		avrule_decl_t *decl = stack->decl;
11706cd6a6acSopenharmony_ci		if (is_perm_in_scope_index
11716cd6a6acSopenharmony_ci		    (perm_value, class_value, &decl->required)
11726cd6a6acSopenharmony_ci		    || is_perm_in_scope_index(perm_value, class_value,
11736cd6a6acSopenharmony_ci					      &decl->declared)) {
11746cd6a6acSopenharmony_ci			return 1;
11756cd6a6acSopenharmony_ci		}
11766cd6a6acSopenharmony_ci	} else {
11776cd6a6acSopenharmony_ci		/* note that conditionals can't declare or require
11786cd6a6acSopenharmony_ci		 * symbols, so skip this level */
11796cd6a6acSopenharmony_ci	}
11806cd6a6acSopenharmony_ci
11816cd6a6acSopenharmony_ci	/* not within scope of this stack, so try its parent */
11826cd6a6acSopenharmony_ci	return is_perm_in_stack(perm_value, class_value, stack->parent);
11836cd6a6acSopenharmony_ci}
11846cd6a6acSopenharmony_ci
11856cd6a6acSopenharmony_ciint is_perm_in_scope(const_hashtab_key_t perm_id, const_hashtab_key_t class_id)
11866cd6a6acSopenharmony_ci{
11876cd6a6acSopenharmony_ci	const class_datum_t *cladatum =
11886cd6a6acSopenharmony_ci	    (class_datum_t *) hashtab_search(policydbp->p_classes.table,
11896cd6a6acSopenharmony_ci					     class_id);
11906cd6a6acSopenharmony_ci	const perm_datum_t *perdatum;
11916cd6a6acSopenharmony_ci	if (cladatum == NULL) {
11926cd6a6acSopenharmony_ci		return 1;
11936cd6a6acSopenharmony_ci	}
11946cd6a6acSopenharmony_ci	perdatum = (perm_datum_t *) hashtab_search(cladatum->permissions.table,
11956cd6a6acSopenharmony_ci						   perm_id);
11966cd6a6acSopenharmony_ci	if (perdatum == NULL) {
11976cd6a6acSopenharmony_ci		return 1;
11986cd6a6acSopenharmony_ci	}
11996cd6a6acSopenharmony_ci	return is_perm_in_stack(perdatum->s.value, cladatum->s.value,
12006cd6a6acSopenharmony_ci				stack_top);
12016cd6a6acSopenharmony_ci}
12026cd6a6acSopenharmony_ci
12036cd6a6acSopenharmony_cicond_list_t *get_current_cond_list(cond_list_t * cond)
12046cd6a6acSopenharmony_ci{
12056cd6a6acSopenharmony_ci	/* FIX ME: do something different here if in a nested
12066cd6a6acSopenharmony_ci	 * conditional? */
12076cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12086cd6a6acSopenharmony_ci	return get_decl_cond_list(policydbp, decl, cond);
12096cd6a6acSopenharmony_ci}
12106cd6a6acSopenharmony_ci
12116cd6a6acSopenharmony_ci/* Append the new conditional node to the existing ones.  During
12126cd6a6acSopenharmony_ci * expansion the list will be reversed -- i.e., the last AV rule will
12136cd6a6acSopenharmony_ci * be the first one listed in the policy.  This matches the behavior
12146cd6a6acSopenharmony_ci * of the upstream compiler. */
12156cd6a6acSopenharmony_civoid append_cond_list(cond_list_t * cond)
12166cd6a6acSopenharmony_ci{
12176cd6a6acSopenharmony_ci	cond_list_t *old_cond = get_current_cond_list(cond);
12186cd6a6acSopenharmony_ci	avrule_t *tmp;
12196cd6a6acSopenharmony_ci	assert(old_cond != NULL);	/* probably out of memory */
12206cd6a6acSopenharmony_ci	if (old_cond->avtrue_list == NULL) {
12216cd6a6acSopenharmony_ci		old_cond->avtrue_list = cond->avtrue_list;
12226cd6a6acSopenharmony_ci	} else {
12236cd6a6acSopenharmony_ci		for (tmp = old_cond->avtrue_list; tmp->next != NULL;
12246cd6a6acSopenharmony_ci		     tmp = tmp->next) ;
12256cd6a6acSopenharmony_ci		tmp->next = cond->avtrue_list;
12266cd6a6acSopenharmony_ci	}
12276cd6a6acSopenharmony_ci	if (old_cond->avfalse_list == NULL) {
12286cd6a6acSopenharmony_ci		old_cond->avfalse_list = cond->avfalse_list;
12296cd6a6acSopenharmony_ci	} else {
12306cd6a6acSopenharmony_ci		for (tmp = old_cond->avfalse_list; tmp->next != NULL;
12316cd6a6acSopenharmony_ci		     tmp = tmp->next) ;
12326cd6a6acSopenharmony_ci		tmp->next = cond->avfalse_list;
12336cd6a6acSopenharmony_ci	}
12346cd6a6acSopenharmony_ci
12356cd6a6acSopenharmony_ci	old_cond->flags |= cond->flags;
12366cd6a6acSopenharmony_ci}
12376cd6a6acSopenharmony_ci
12386cd6a6acSopenharmony_civoid append_avrule(avrule_t * avrule)
12396cd6a6acSopenharmony_ci{
12406cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12416cd6a6acSopenharmony_ci
12426cd6a6acSopenharmony_ci	/* currently avrules follow a completely different code path
12436cd6a6acSopenharmony_ci	 * for handling avrules and compute types
12446cd6a6acSopenharmony_ci	 * (define_cond_avrule_te_avtab, define_cond_compute_type);
12456cd6a6acSopenharmony_ci	 * therefore there ought never be a conditional on top of the
12466cd6a6acSopenharmony_ci	 * scope stack */
12476cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
12486cd6a6acSopenharmony_ci
12496cd6a6acSopenharmony_ci	if (stack_top->last_avrule == NULL) {
12506cd6a6acSopenharmony_ci		decl->avrules = avrule;
12516cd6a6acSopenharmony_ci	} else {
12526cd6a6acSopenharmony_ci		stack_top->last_avrule->next = avrule;
12536cd6a6acSopenharmony_ci	}
12546cd6a6acSopenharmony_ci	stack_top->last_avrule = avrule;
12556cd6a6acSopenharmony_ci}
12566cd6a6acSopenharmony_ci
12576cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */
12586cd6a6acSopenharmony_civoid append_role_trans(role_trans_rule_t * role_tr_rules)
12596cd6a6acSopenharmony_ci{
12606cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12616cd6a6acSopenharmony_ci
12626cd6a6acSopenharmony_ci	/* role transitions are not allowed within conditionals */
12636cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
12646cd6a6acSopenharmony_ci
12656cd6a6acSopenharmony_ci	role_tr_rules->next = decl->role_tr_rules;
12666cd6a6acSopenharmony_ci	decl->role_tr_rules = role_tr_rules;
12676cd6a6acSopenharmony_ci}
12686cd6a6acSopenharmony_ci
12696cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */
12706cd6a6acSopenharmony_civoid append_role_allow(role_allow_rule_t * role_allow_rules)
12716cd6a6acSopenharmony_ci{
12726cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12736cd6a6acSopenharmony_ci
12746cd6a6acSopenharmony_ci	/* role allows are not allowed within conditionals */
12756cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
12766cd6a6acSopenharmony_ci
12776cd6a6acSopenharmony_ci	role_allow_rules->next = decl->role_allow_rules;
12786cd6a6acSopenharmony_ci	decl->role_allow_rules = role_allow_rules;
12796cd6a6acSopenharmony_ci}
12806cd6a6acSopenharmony_ci
12816cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */
12826cd6a6acSopenharmony_civoid append_filename_trans(filename_trans_rule_t * filename_trans_rules)
12836cd6a6acSopenharmony_ci{
12846cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12856cd6a6acSopenharmony_ci
12866cd6a6acSopenharmony_ci	/* filename transitions are not allowed within conditionals */
12876cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
12886cd6a6acSopenharmony_ci
12896cd6a6acSopenharmony_ci	filename_trans_rules->next = decl->filename_trans_rules;
12906cd6a6acSopenharmony_ci	decl->filename_trans_rules = filename_trans_rules;
12916cd6a6acSopenharmony_ci}
12926cd6a6acSopenharmony_ci
12936cd6a6acSopenharmony_ci/* this doesn't actually append, but really prepends it */
12946cd6a6acSopenharmony_civoid append_range_trans(range_trans_rule_t * range_tr_rules)
12956cd6a6acSopenharmony_ci{
12966cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
12976cd6a6acSopenharmony_ci
12986cd6a6acSopenharmony_ci	/* range transitions are not allowed within conditionals */
12996cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
13006cd6a6acSopenharmony_ci
13016cd6a6acSopenharmony_ci	range_tr_rules->next = decl->range_tr_rules;
13026cd6a6acSopenharmony_ci	decl->range_tr_rules = range_tr_rules;
13036cd6a6acSopenharmony_ci}
13046cd6a6acSopenharmony_ci
13056cd6a6acSopenharmony_ciint begin_optional(int pass)
13066cd6a6acSopenharmony_ci{
13076cd6a6acSopenharmony_ci	avrule_block_t *block = NULL;
13086cd6a6acSopenharmony_ci	avrule_decl_t *decl;
13096cd6a6acSopenharmony_ci	if (pass == 1) {
13106cd6a6acSopenharmony_ci		/* allocate a new avrule block for this optional block */
13116cd6a6acSopenharmony_ci		if ((block = avrule_block_create()) == NULL ||
13126cd6a6acSopenharmony_ci		    (decl = avrule_decl_create(next_decl_id)) == NULL) {
13136cd6a6acSopenharmony_ci			goto cleanup;
13146cd6a6acSopenharmony_ci		}
13156cd6a6acSopenharmony_ci		block->flags |= AVRULE_OPTIONAL;
13166cd6a6acSopenharmony_ci		block->branch_list = decl;
13176cd6a6acSopenharmony_ci		last_block->next = block;
13186cd6a6acSopenharmony_ci	} else {
13196cd6a6acSopenharmony_ci		/* select the next block from the chain built during pass 1 */
13206cd6a6acSopenharmony_ci		block = last_block->next;
13216cd6a6acSopenharmony_ci		assert(block != NULL &&
13226cd6a6acSopenharmony_ci		       block->branch_list != NULL &&
13236cd6a6acSopenharmony_ci		       block->branch_list->decl_id == next_decl_id);
13246cd6a6acSopenharmony_ci		decl = block->branch_list;
13256cd6a6acSopenharmony_ci	}
13266cd6a6acSopenharmony_ci	if (push_stack(1, block, decl) == -1) {
13276cd6a6acSopenharmony_ci		goto cleanup;
13286cd6a6acSopenharmony_ci	}
13296cd6a6acSopenharmony_ci	stack_top->last_avrule = NULL;
13306cd6a6acSopenharmony_ci	last_block = block;
13316cd6a6acSopenharmony_ci	next_decl_id++;
13326cd6a6acSopenharmony_ci	return 0;
13336cd6a6acSopenharmony_ci      cleanup:
13346cd6a6acSopenharmony_ci	yyerror("Out of memory!");
13356cd6a6acSopenharmony_ci	avrule_block_destroy(block);
13366cd6a6acSopenharmony_ci	return -1;
13376cd6a6acSopenharmony_ci}
13386cd6a6acSopenharmony_ci
13396cd6a6acSopenharmony_ciint end_optional(int pass __attribute__ ((unused)))
13406cd6a6acSopenharmony_ci{
13416cd6a6acSopenharmony_ci	/* once nested conditionals are allowed, do the stack unfolding here */
13426cd6a6acSopenharmony_ci	pop_stack();
13436cd6a6acSopenharmony_ci	return 0;
13446cd6a6acSopenharmony_ci}
13456cd6a6acSopenharmony_ci
13466cd6a6acSopenharmony_ciint begin_optional_else(int pass)
13476cd6a6acSopenharmony_ci{
13486cd6a6acSopenharmony_ci	avrule_decl_t *decl;
13496cd6a6acSopenharmony_ci	assert(stack_top->type == 1 && stack_top->in_else == 0);
13506cd6a6acSopenharmony_ci	if (pass == 1) {
13516cd6a6acSopenharmony_ci		/* allocate a new declaration and add it to the
13526cd6a6acSopenharmony_ci		 * current chain */
13536cd6a6acSopenharmony_ci		if ((decl = avrule_decl_create(next_decl_id)) == NULL) {
13546cd6a6acSopenharmony_ci			yyerror("Out of memory!");
13556cd6a6acSopenharmony_ci			return -1;
13566cd6a6acSopenharmony_ci		}
13576cd6a6acSopenharmony_ci		stack_top->decl->next = decl;
13586cd6a6acSopenharmony_ci	} else {
13596cd6a6acSopenharmony_ci		/* pick the (hopefully last) declaration of this
13606cd6a6acSopenharmony_ci		   avrule block, built from pass 1 */
13616cd6a6acSopenharmony_ci		decl = stack_top->decl->next;
13626cd6a6acSopenharmony_ci		assert(decl != NULL &&
13636cd6a6acSopenharmony_ci		       decl->next == NULL && decl->decl_id == next_decl_id);
13646cd6a6acSopenharmony_ci	}
13656cd6a6acSopenharmony_ci	stack_top->in_else = 1;
13666cd6a6acSopenharmony_ci	stack_top->decl = decl;
13676cd6a6acSopenharmony_ci	stack_top->last_avrule = NULL;
13686cd6a6acSopenharmony_ci	stack_top->require_given = 0;
13696cd6a6acSopenharmony_ci	next_decl_id++;
13706cd6a6acSopenharmony_ci	return 0;
13716cd6a6acSopenharmony_ci}
13726cd6a6acSopenharmony_ci
13736cd6a6acSopenharmony_cistatic int copy_requirements(avrule_decl_t * dest, const scope_stack_t * stack)
13746cd6a6acSopenharmony_ci{
13756cd6a6acSopenharmony_ci	uint32_t i;
13766cd6a6acSopenharmony_ci	if (stack == NULL) {
13776cd6a6acSopenharmony_ci		return 0;
13786cd6a6acSopenharmony_ci	}
13796cd6a6acSopenharmony_ci	if (stack->type == 1) {
13806cd6a6acSopenharmony_ci		const scope_index_t *src_scope = &stack->decl->required;
13816cd6a6acSopenharmony_ci		scope_index_t *dest_scope = &dest->required;
13826cd6a6acSopenharmony_ci		for (i = 0; i < SYM_NUM; i++) {
13836cd6a6acSopenharmony_ci			const ebitmap_t *src_bitmap = &src_scope->scope[i];
13846cd6a6acSopenharmony_ci			ebitmap_t *dest_bitmap = &dest_scope->scope[i];
13856cd6a6acSopenharmony_ci			if (ebitmap_union(dest_bitmap, src_bitmap)) {
13866cd6a6acSopenharmony_ci				yyerror("Out of memory!");
13876cd6a6acSopenharmony_ci				return -1;
13886cd6a6acSopenharmony_ci			}
13896cd6a6acSopenharmony_ci		}
13906cd6a6acSopenharmony_ci		/* now copy class permissions */
13916cd6a6acSopenharmony_ci		if (src_scope->class_perms_len > dest_scope->class_perms_len) {
13926cd6a6acSopenharmony_ci			ebitmap_t *new_map =
13936cd6a6acSopenharmony_ci			    realloc(dest_scope->class_perms_map,
13946cd6a6acSopenharmony_ci				    src_scope->class_perms_len *
13956cd6a6acSopenharmony_ci				    sizeof(*new_map));
13966cd6a6acSopenharmony_ci			if (new_map == NULL) {
13976cd6a6acSopenharmony_ci				yyerror("Out of memory!");
13986cd6a6acSopenharmony_ci				return -1;
13996cd6a6acSopenharmony_ci			}
14006cd6a6acSopenharmony_ci			dest_scope->class_perms_map = new_map;
14016cd6a6acSopenharmony_ci			for (i = dest_scope->class_perms_len;
14026cd6a6acSopenharmony_ci			     i < src_scope->class_perms_len; i++) {
14036cd6a6acSopenharmony_ci				ebitmap_init(dest_scope->class_perms_map + i);
14046cd6a6acSopenharmony_ci			}
14056cd6a6acSopenharmony_ci			dest_scope->class_perms_len =
14066cd6a6acSopenharmony_ci			    src_scope->class_perms_len;
14076cd6a6acSopenharmony_ci		}
14086cd6a6acSopenharmony_ci		for (i = 0; i < src_scope->class_perms_len; i++) {
14096cd6a6acSopenharmony_ci			const ebitmap_t *src_bitmap = &src_scope->class_perms_map[i];
14106cd6a6acSopenharmony_ci			ebitmap_t *dest_bitmap =
14116cd6a6acSopenharmony_ci			    &dest_scope->class_perms_map[i];
14126cd6a6acSopenharmony_ci			if (ebitmap_union(dest_bitmap, src_bitmap)) {
14136cd6a6acSopenharmony_ci				yyerror("Out of memory!");
14146cd6a6acSopenharmony_ci				return -1;
14156cd6a6acSopenharmony_ci			}
14166cd6a6acSopenharmony_ci		}
14176cd6a6acSopenharmony_ci	}
14186cd6a6acSopenharmony_ci	return copy_requirements(dest, stack->parent);
14196cd6a6acSopenharmony_ci}
14206cd6a6acSopenharmony_ci
14216cd6a6acSopenharmony_ci/* During pass 1, check that at least one thing was required within
14226cd6a6acSopenharmony_ci * this block, for those places where a REQUIRED is necessary.  During
14236cd6a6acSopenharmony_ci * pass 2, have this block inherit its parents' requirements.  Return
14246cd6a6acSopenharmony_ci * 0 on success, -1 on failure. */
14256cd6a6acSopenharmony_ciint end_avrule_block(int pass)
14266cd6a6acSopenharmony_ci{
14276cd6a6acSopenharmony_ci	avrule_decl_t *decl = stack_top->decl;
14286cd6a6acSopenharmony_ci	assert(stack_top->type == 1);
14296cd6a6acSopenharmony_ci	if (pass == 2) {
14306cd6a6acSopenharmony_ci		/* this avrule_decl inherits all of its parents'
14316cd6a6acSopenharmony_ci		 * requirements */
14326cd6a6acSopenharmony_ci		if (copy_requirements(decl, stack_top->parent) == -1) {
14336cd6a6acSopenharmony_ci			return -1;
14346cd6a6acSopenharmony_ci		}
14356cd6a6acSopenharmony_ci		return 0;
14366cd6a6acSopenharmony_ci	}
14376cd6a6acSopenharmony_ci	if (!stack_top->in_else && !stack_top->require_given) {
14386cd6a6acSopenharmony_ci		if (policydbp->policy_type == POLICY_BASE
14396cd6a6acSopenharmony_ci		    && stack_top->parent != NULL) {
14406cd6a6acSopenharmony_ci			/* if this is base no require should be in the global block */
14416cd6a6acSopenharmony_ci			return 0;
14426cd6a6acSopenharmony_ci		} else {
14436cd6a6acSopenharmony_ci			/* non-ELSE branches must have at least one thing required */
14446cd6a6acSopenharmony_ci			yyerror("This block has no require section.");
14456cd6a6acSopenharmony_ci			return -1;
14466cd6a6acSopenharmony_ci		}
14476cd6a6acSopenharmony_ci	}
14486cd6a6acSopenharmony_ci	return 0;
14496cd6a6acSopenharmony_ci}
14506cd6a6acSopenharmony_ci
14516cd6a6acSopenharmony_ci/* Push a new scope on to the stack and update the 'last' pointer.
14526cd6a6acSopenharmony_ci * Return 0 on success, -1 if out * of memory. */
14536cd6a6acSopenharmony_cistatic int push_stack(int stack_type, ...)
14546cd6a6acSopenharmony_ci{
14556cd6a6acSopenharmony_ci	scope_stack_t *s = calloc(1, sizeof(*s));
14566cd6a6acSopenharmony_ci	va_list ap;
14576cd6a6acSopenharmony_ci	if (s == NULL) {
14586cd6a6acSopenharmony_ci		return -1;
14596cd6a6acSopenharmony_ci	}
14606cd6a6acSopenharmony_ci	va_start(ap, stack_type);
14616cd6a6acSopenharmony_ci	switch (s->type = stack_type) {
14626cd6a6acSopenharmony_ci	case 1:{
14636cd6a6acSopenharmony_ci			s->u.avrule = va_arg(ap, avrule_block_t *);
14646cd6a6acSopenharmony_ci			s->decl = va_arg(ap, avrule_decl_t *);
14656cd6a6acSopenharmony_ci			break;
14666cd6a6acSopenharmony_ci		}
14676cd6a6acSopenharmony_ci	case 2:{
14686cd6a6acSopenharmony_ci			s->u.cond_list = va_arg(ap, cond_list_t *);
14696cd6a6acSopenharmony_ci			break;
14706cd6a6acSopenharmony_ci		}
14716cd6a6acSopenharmony_ci	default:
14726cd6a6acSopenharmony_ci		/* invalid stack type given */
14736cd6a6acSopenharmony_ci		assert(0);
14746cd6a6acSopenharmony_ci	}
14756cd6a6acSopenharmony_ci	va_end(ap);
14766cd6a6acSopenharmony_ci	s->parent = stack_top;
14776cd6a6acSopenharmony_ci	s->child = NULL;
14786cd6a6acSopenharmony_ci	stack_top = s;
14796cd6a6acSopenharmony_ci	return 0;
14806cd6a6acSopenharmony_ci}
14816cd6a6acSopenharmony_ci
14826cd6a6acSopenharmony_ci/* Pop off the most recently added from the stack.  Update the 'last'
14836cd6a6acSopenharmony_ci * pointer. */
14846cd6a6acSopenharmony_cistatic void pop_stack(void)
14856cd6a6acSopenharmony_ci{
14866cd6a6acSopenharmony_ci	scope_stack_t *parent;
14876cd6a6acSopenharmony_ci	assert(stack_top != NULL);
14886cd6a6acSopenharmony_ci	parent = stack_top->parent;
14896cd6a6acSopenharmony_ci	if (parent != NULL) {
14906cd6a6acSopenharmony_ci		parent->child = NULL;
14916cd6a6acSopenharmony_ci	}
14926cd6a6acSopenharmony_ci	free(stack_top);
14936cd6a6acSopenharmony_ci	stack_top = parent;
14946cd6a6acSopenharmony_ci}
1495