blob: 15058734ef698ac4f4ae45afb3b889ab75bfe1c3 [file] [log] [blame] [edit]
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sepol/policydb/conditional.h>
#include "cil_internal.h"
#include "cil_flavor.h"
#include "cil_log.h"
#include "cil_mem.h"
#include "cil_tree.h"
#include "cil_list.h"
#include "cil_parser.h"
#include "cil_build_ast.h"
#include "cil_copy_ast.h"
#include "cil_verify.h"
#include "cil_strpool.h"
struct cil_args_build {
struct cil_tree_node *ast;
struct cil_db *db;
struct cil_tree_node *macro;
struct cil_tree_node *boolif;
struct cil_tree_node *tunif;
struct cil_tree_node *in;
};
int cil_fill_list(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **list)
{
int rc = SEPOL_ERR;
struct cil_tree_node *curr;
enum cil_syntax syntax[] = {
CIL_SYN_N_STRINGS,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
rc = __cil_verify_syntax(current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_init(list, flavor);
for (curr = current; curr != NULL; curr = curr->next) {
cil_list_append(*list, CIL_STRING, curr->data);
}
return SEPOL_OK;
exit:
return rc;
}
int cil_gen_node(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor)
{
int rc = SEPOL_ERR;
symtab_t *symtab = NULL;
rc = __cil_verify_name((const char*)key);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_get_symtab(ast_node->parent, &symtab, sflavor);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = datum;
ast_node->flavor = nflavor;
if (symtab != NULL) {
rc = cil_symtab_insert(symtab, (hashtab_key_t)key, datum, ast_node);
if (rc == SEPOL_EEXIST) {
cil_log(CIL_ERR, "Re-declaration of %s %s\n",
cil_node_to_string(ast_node), key);
if (cil_symtab_get_datum(symtab, key, &datum) == SEPOL_OK) {
if (sflavor == CIL_SYM_BLOCKS) {
struct cil_tree_node *node = datum->nodes->head->data;
cil_tree_log(node, CIL_ERR, "Previous declaration");
}
}
goto exit;
}
}
if (ast_node->flavor >= CIL_MIN_DECLARATIVE && ast_node->parent->flavor == CIL_MACRO) {
struct cil_list_item *item;
struct cil_list *param_list = ((struct cil_macro*)ast_node->parent->data)->params;
if (param_list != NULL) {
cil_list_for_each(item, param_list) {
struct cil_param *param = item->data;
if (param->flavor == ast_node->flavor) {
if (param->str == key) {
cil_log(CIL_ERR, "%s %s shadows a macro parameter in macro declaration\n", cil_node_to_string(ast_node), key);
rc = SEPOL_ERR;
goto exit;
}
}
}
}
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Failed to create node\n");
return rc;
}
void cil_clear_node(struct cil_tree_node *ast_node)
{
if (ast_node == NULL) {
return;
}
ast_node->data = NULL;
ast_node->flavor = CIL_NONE;
}
int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_N_LISTS | CIL_SYN_END,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_block *block = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_block_init(&block);
block->is_abstract = is_abstract;
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)block, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_BLOCK);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad block declaration");
cil_destroy_block(block);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_block(struct cil_block *block)
{
if (block == NULL) {
return;
}
cil_symtab_datum_destroy(&block->datum);
cil_symtab_array_destroy(block->symtab);
cil_list_destroy(&block->bi_nodes, CIL_FALSE);
free(block);
}
int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_blockinherit *inherit = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_blockinherit_init(&inherit);
inherit->block_str = parse_current->next->data;
ast_node->data = inherit;
ast_node->flavor = CIL_BLOCKINHERIT;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad blockinherit declaration");
cil_destroy_blockinherit(inherit);
return rc;
}
void cil_destroy_blockinherit(struct cil_blockinherit *inherit)
{
if (inherit == NULL) {
return;
}
free(inherit);
}
int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_blockabstract *abstract = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_blockabstract_init(&abstract);
abstract->block_str = parse_current->next->data;
ast_node->data = abstract;
ast_node->flavor = CIL_BLOCKABSTRACT;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad blockabstract declaration");
cil_destroy_blockabstract(abstract);
return rc;
}
void cil_destroy_blockabstract(struct cil_blockabstract *abstract)
{
if (abstract == NULL) {
return;
}
free(abstract);
}
int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_N_LISTS,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
int rc = SEPOL_ERR;
struct cil_in *in = NULL;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_in_init(&in);
in->block_str = parse_current->next->data;
ast_node->data = in;
ast_node->flavor = CIL_IN;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad in statement");
cil_destroy_in(in);
return rc;
}
void cil_destroy_in(struct cil_in *in)
{
if (in == NULL) {
return;
}
cil_symtab_array_destroy(in->symtab);
free(in);
}
int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_class *class = NULL;
struct cil_tree_node *perms = NULL;
int rc = SEPOL_ERR;
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_class_init(&class);
key = parse_current->next->data;
if (key == CIL_KEY_UNORDERED) {
cil_log(CIL_ERR, "'unordered' keyword is reserved and not a valid class name.\n");
rc = SEPOL_ERR;
goto exit;
}
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)class, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_CLASS);
if (rc != SEPOL_OK) {
goto exit;
}
if (parse_current->next->next != NULL) {
perms = parse_current->next->next->cl_head;
rc = cil_gen_perm_nodes(db, perms, ast_node, CIL_PERM, &class->num_perms);
if (rc != SEPOL_OK) {
goto exit;
}
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad class declaration");
cil_destroy_class(class);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_class(struct cil_class *class)
{
if (class == NULL) {
return;
}
cil_symtab_datum_destroy(&class->datum);
cil_symtab_destroy(&class->perms);
free(class);
}
int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_classorder *classorder = NULL;
struct cil_list_item *curr = NULL;
struct cil_list_item *head = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classorder_init(&classorder);
rc = cil_fill_list(parse_current->next->cl_head, CIL_CLASSORDER, &classorder->class_list_str);
if (rc != SEPOL_OK) {
goto exit;
}
head = classorder->class_list_str->head;
cil_list_for_each(curr, classorder->class_list_str) {
if (curr->data == CIL_KEY_UNORDERED) {
if (curr == head && curr->next == NULL) {
cil_log(CIL_ERR, "Classorder 'unordered' keyword must be followed by one or more class.\n");
rc = SEPOL_ERR;
goto exit;
} else if (curr != head) {
cil_log(CIL_ERR, "Classorder can only use 'unordered' keyword as the first item in the list.\n");
rc = SEPOL_ERR;
goto exit;
}
}
}
ast_node->data = classorder;
ast_node->flavor = CIL_CLASSORDER;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad classorder declaration");
cil_destroy_classorder(classorder);
return rc;
}
void cil_destroy_classorder(struct cil_classorder *classorder)
{
if (classorder == NULL) {
return;
}
if (classorder->class_list_str != NULL) {
cil_list_destroy(&classorder->class_list_str, 1);
}
free(classorder);
}
int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
{
char *key = NULL;
struct cil_perm *perm = NULL;
int rc = SEPOL_ERR;
cil_perm_init(&perm);
key = parse_current->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)perm, (hashtab_key_t)key, CIL_SYM_PERMS, flavor);
if (rc != SEPOL_OK) {
goto exit;
}
perm->value = *num_perms;
(*num_perms)++;
return SEPOL_OK;
exit:
cil_destroy_perm(perm);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_perm(struct cil_perm *perm)
{
if (perm == NULL) {
return;
}
cil_symtab_datum_destroy(&perm->datum);
cil_list_destroy(&perm->classperms, CIL_FALSE);
free(perm);
}
int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms)
{
int rc = SEPOL_ERR;
struct cil_tree_node *new_ast = NULL;
while(current_perm != NULL) {
if (current_perm->cl_head != NULL) {
rc = SEPOL_ERR;
goto exit;
}
cil_tree_node_init(&new_ast);
new_ast->parent = ast_node;
new_ast->line = current_perm->line;
new_ast->hll_line = current_perm->hll_line;
rc = cil_gen_perm(db, current_perm, new_ast, flavor, num_perms);
if (rc != SEPOL_OK) {
goto exit;
}
if (ast_node->cl_head == NULL) {
ast_node->cl_head = new_ast;
} else {
ast_node->cl_tail->next = new_ast;
}
ast_node->cl_tail = new_ast;
current_perm = current_perm->next;
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Bad permissions\n");
return rc;
}
int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perms)
{
int rc = SEPOL_ERR;
enum cil_syntax syntax[] = {
CIL_SYN_N_STRINGS | CIL_SYN_N_LISTS,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
rc = __cil_verify_syntax(start_perm->cl_head, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_gen_expr(start_perm, CIL_PERM, perms);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Bad permission list or expression\n");
return rc;
}
int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp)
{
int rc = SEPOL_ERR;
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classperms_init(cp);
(*cp)->class_str = parse_current->data;
rc = cil_fill_perms(parse_current->next, &(*cp)->perm_strs);
if (rc != SEPOL_OK) {
cil_destroy_classperms(*cp);
goto exit;
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Bad class-permissions\n");
*cp = NULL;
return rc;
}
void cil_destroy_classperms(struct cil_classperms *cp)
{
if (cp == NULL) {
return;
}
cil_list_destroy(&cp->perm_strs, CIL_TRUE);
cil_list_destroy(&cp->perms, CIL_FALSE);
free(cp);
}
void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set)
{
cil_classperms_set_init(cp_set);
(*cp_set)->set_str = parse_current->data;
}
void cil_destroy_classperms_set(struct cil_classperms_set *cp_set)
{
if (cp_set == NULL) {
return;
}
free(cp_set);
}
int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **cp_list)
{
int rc = SEPOL_ERR;
struct cil_tree_node *curr;
enum cil_syntax syntax[] = {
CIL_SYN_STRING | CIL_SYN_LIST,
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
if (parse_current == NULL || cp_list == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_init(cp_list, CIL_CLASSPERMS);
curr = parse_current->cl_head;
if (curr == NULL) {
/* Class-perms form: SET1 */
struct cil_classperms_set *new_cp_set;
cil_fill_classperms_set(parse_current, &new_cp_set);
cil_list_append(*cp_list, CIL_CLASSPERMS_SET, new_cp_set);
} else if (curr->cl_head == NULL) {
/* Class-perms form: (CLASS1 (PERM1 ...)) */
struct cil_classperms *new_cp;
rc = cil_fill_classperms(curr, &new_cp);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_append(*cp_list, CIL_CLASSPERMS, new_cp);
} else {
cil_log(CIL_ERR, "Bad class-permissions list syntax\n");
rc = SEPOL_ERR;
goto exit;
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Problem filling class-permissions list\n");
cil_list_destroy(cp_list, CIL_TRUE);
return rc;
}
void cil_destroy_classperms_list(struct cil_list **cp_list)
{
struct cil_list_item *curr;
if (cp_list == NULL || *cp_list == NULL) {
return;
}
cil_list_for_each(curr, *cp_list) {
if (curr->flavor == CIL_CLASSPERMS) {
cil_destroy_classperms(curr->data);
} else {
cil_destroy_classperms_set(curr->data);
}
}
cil_list_destroy(cp_list, CIL_FALSE);
}
int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
int rc = SEPOL_ERR;
char *key = NULL;
struct cil_classpermission *cp = NULL;
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classpermission_init(&cp);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)cp, (hashtab_key_t)key, CIL_SYM_CLASSPERMSETS, CIL_CLASSPERMISSION);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad classpermission declaration");
cil_destroy_classpermission(cp);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_classpermission(struct cil_classpermission *cp)
{
if (cp == NULL) {
return;
}
if (cp->datum.name != NULL) {
cil_list_destroy(&cp->classperms, CIL_FALSE);
} else {
/* anonymous classpermission from call */
cil_destroy_classperms_list(&cp->classperms);
}
cil_symtab_datum_destroy(&cp->datum);
free(cp);
}
int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
int rc = SEPOL_ERR;
struct cil_classpermissionset *cps = NULL;
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classpermissionset_init(&cps);
cps->set_str = parse_current->next->data;
rc = cil_fill_classperms_list(parse_current->next->next, &cps->classperms);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = cps;
ast_node->flavor = CIL_CLASSPERMISSIONSET;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad classpermissionset");
cil_destroy_classpermissionset(cps);
return rc;
}
void cil_destroy_classpermissionset(struct cil_classpermissionset *cps)
{
if (cps == NULL) {
return;
}
cil_destroy_classperms_list(&cps->classperms);
free(cps);
}
int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_class *map = NULL;
int rc = SEPOL_ERR;
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_class_init(&map);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)map, (hashtab_key_t)key, CIL_SYM_CLASSES, CIL_MAP_CLASS);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_MAP_PERM, &map->num_perms);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad map class declaration");
cil_destroy_class(map);
cil_clear_node(ast_node);
return rc;
}
int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
int rc = SEPOL_ERR;
struct cil_classmapping *mapping = NULL;
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classmapping_init(&mapping);
mapping->map_class_str = parse_current->next->data;
mapping->map_perm_str = parse_current->next->next->data;
rc = cil_fill_classperms_list(parse_current->next->next->next, &mapping->classperms);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = mapping;
ast_node->flavor = CIL_CLASSMAPPING;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad classmapping declaration");
cil_destroy_classmapping(mapping);
return rc;
}
void cil_destroy_classmapping(struct cil_classmapping *mapping)
{
if (mapping == NULL) {
return;
}
cil_destroy_classperms_list(&mapping->classperms);
free(mapping);
}
// TODO try to merge some of this with cil_gen_class (helper function for both)
int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_class *common = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_class_init(&common);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)common, (hashtab_key_t)key, CIL_SYM_COMMONS, CIL_COMMON);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_gen_perm_nodes(db, parse_current->next->next->cl_head, ast_node, CIL_PERM, &common->num_perms);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad common declaration");
cil_destroy_class(common);
cil_clear_node(ast_node);
return rc;
}
int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_classcommon *clscom = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_classcommon_init(&clscom);
clscom->class_str = parse_current->next->data;
clscom->common_str = parse_current->next->next->data;
ast_node->data = clscom;
ast_node->flavor = CIL_CLASSCOMMON;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad classcommon declaration");
cil_destroy_classcommon(clscom);
return rc;
}
void cil_destroy_classcommon(struct cil_classcommon *clscom)
{
if (clscom == NULL) {
return;
}
free(clscom);
}
int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_sid *sid = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_sid_init(&sid);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)sid, (hashtab_key_t)key, CIL_SYM_SIDS, CIL_SID);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad sid declaration");
cil_destroy_sid(sid);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_sid(struct cil_sid *sid)
{
if (sid == NULL) {
return;
}
cil_symtab_datum_destroy(&sid->datum);
free(sid);
}
int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_sidcontext *sidcon = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_sidcontext_init(&sidcon);
sidcon->sid_str = parse_current->next->data;
if (parse_current->next->next->cl_head == NULL) {
sidcon->context_str = parse_current->next->next->data;
} else {
cil_context_init(&sidcon->context);
rc = cil_fill_context(parse_current->next->next->cl_head, sidcon->context);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = sidcon;
ast_node->flavor = CIL_SIDCONTEXT;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad sidcontext declaration");
cil_destroy_sidcontext(sidcon);
return rc;
}
void cil_destroy_sidcontext(struct cil_sidcontext *sidcon)
{
if (sidcon == NULL) {
return;
}
if (sidcon->context_str == NULL && sidcon->context != NULL) {
cil_destroy_context(sidcon->context);
}
free(sidcon);
}
int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_sidorder *sidorder = NULL;
struct cil_list_item *curr = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_sidorder_init(&sidorder);
rc = cil_fill_list(parse_current->next->cl_head, CIL_SIDORDER, &sidorder->sid_list_str);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_for_each(curr, sidorder->sid_list_str) {
if (curr->data == CIL_KEY_UNORDERED) {
cil_log(CIL_ERR, "Sidorder cannot be unordered.\n");
rc = SEPOL_ERR;
goto exit;
}
}
ast_node->data = sidorder;
ast_node->flavor = CIL_SIDORDER;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad sidorder declaration");
cil_destroy_sidorder(sidorder);
return rc;
}
void cil_destroy_sidorder(struct cil_sidorder *sidorder)
{
if (sidorder == NULL) {
return;
}
if (sidorder->sid_list_str != NULL) {
cil_list_destroy(&sidorder->sid_list_str, 1);
}
free(sidorder);
}
int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_user *user = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_user_init(&user);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)user, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USER);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad user declaration");
cil_destroy_user(user);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_user(struct cil_user *user)
{
if (user == NULL) {
return;
}
cil_symtab_datum_destroy(&user->datum);
ebitmap_destroy(user->roles);
free(user->roles);
free(user);
}
int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_userattribute *attr = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userattribute_init(&attr);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USERATTRIBUTE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userattribute declaration");
cil_destroy_userattribute(attr);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_userattribute(struct cil_userattribute *attr)
{
struct cil_list_item *expr = NULL;
struct cil_list_item *next = NULL;
if (attr == NULL) {
return;
}
if (attr->expr_list != NULL) {
/* we don't want to destroy the expression stacks (cil_list) inside
* this list cil_list_destroy destroys sublists, so we need to do it
* manually */
expr = attr->expr_list->head;
while (expr != NULL) {
next = expr->next;
cil_list_item_destroy(&expr, CIL_FALSE);
expr = next;
}
free(attr->expr_list);
attr->expr_list = NULL;
}
cil_symtab_datum_destroy(&attr->datum);
ebitmap_destroy(attr->users);
free(attr->users);
free(attr);
}
int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_userattributeset *attrset = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userattributeset_init(&attrset);
attrset->attr_str = parse_current->next->data;
rc = cil_gen_expr(parse_current->next->next, CIL_USER, &attrset->str_expr);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = attrset;
ast_node->flavor = CIL_USERATTRIBUTESET;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userattributeset declaration");
cil_destroy_userattributeset(attrset);
return rc;
}
void cil_destroy_userattributeset(struct cil_userattributeset *attrset)
{
if (attrset == NULL) {
return;
}
cil_list_destroy(&attrset->str_expr, CIL_TRUE);
cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
free(attrset);
}
int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_userlevel *usrlvl = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userlevel_init(&usrlvl);
usrlvl->user_str = parse_current->next->data;
if (parse_current->next->next->cl_head == NULL) {
usrlvl->level_str = parse_current->next->next->data;
} else {
cil_level_init(&usrlvl->level);
rc = cil_fill_level(parse_current->next->next->cl_head, usrlvl->level);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = usrlvl;
ast_node->flavor = CIL_USERLEVEL;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userlevel declaration");
cil_destroy_userlevel(usrlvl);
return rc;
}
void cil_destroy_userlevel(struct cil_userlevel *usrlvl)
{
if (usrlvl == NULL) {
return;
}
if (usrlvl->level_str == NULL && usrlvl->level != NULL) {
cil_destroy_level(usrlvl->level);
}
free(usrlvl);
}
int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_userrange *userrange = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userrange_init(&userrange);
userrange->user_str = parse_current->next->data;
if (parse_current->next->next->cl_head == NULL) {
userrange->range_str = parse_current->next->next->data;
} else {
cil_levelrange_init(&userrange->range);
rc = cil_fill_levelrange(parse_current->next->next->cl_head, userrange->range);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = userrange;
ast_node->flavor = CIL_USERRANGE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userrange declaration");
cil_destroy_userrange(userrange);
return rc;
}
void cil_destroy_userrange(struct cil_userrange *userrange)
{
if (userrange == NULL) {
return;
}
if (userrange->range_str == NULL && userrange->range != NULL) {
cil_destroy_levelrange(userrange->range);
}
free(userrange);
}
int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_userprefix *userprefix = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userprefix_init(&userprefix);
userprefix->user_str = parse_current->next->data;
userprefix->prefix_str = parse_current->next->next->data;
ast_node->data = userprefix;
ast_node->flavor = CIL_USERPREFIX;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userprefix declaration");
cil_destroy_userprefix(userprefix);
return rc;
}
void cil_destroy_userprefix(struct cil_userprefix *userprefix)
{
if (userprefix == NULL) {
return;
}
free(userprefix);
}
int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_selinuxuser *selinuxuser = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_selinuxuser_init(&selinuxuser);
selinuxuser->name_str = parse_current->next->data;
selinuxuser->user_str = parse_current->next->next->data;
if (parse_current->next->next->next->cl_head == NULL) {
selinuxuser->range_str = parse_current->next->next->next->data;
} else {
cil_levelrange_init(&selinuxuser->range);
rc = cil_fill_levelrange(parse_current->next->next->next->cl_head, selinuxuser->range);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = selinuxuser;
ast_node->flavor = CIL_SELINUXUSER;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuser declaration");
cil_destroy_selinuxuser(selinuxuser);
return rc;
}
int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_selinuxuser *selinuxuser = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_selinuxuser_init(&selinuxuser);
selinuxuser->name_str = cil_strpool_add("__default__");
selinuxuser->user_str = parse_current->next->data;
if (parse_current->next->next->cl_head == NULL) {
selinuxuser->range_str = parse_current->next->next->data;
} else {
cil_levelrange_init(&selinuxuser->range);
rc = cil_fill_levelrange(parse_current->next->next->cl_head, selinuxuser->range);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = selinuxuser;
ast_node->flavor = CIL_SELINUXUSERDEFAULT;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad selinuxuserdefault declaration");
cil_destroy_selinuxuser(selinuxuser);
return rc;
}
void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser)
{
if (selinuxuser == NULL) {
return;
}
if (selinuxuser->range_str == NULL && selinuxuser->range != NULL) {
cil_destroy_levelrange(selinuxuser->range);
}
free(selinuxuser);
}
int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_role *role = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_role_init(&role);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)role, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad role declaration");
cil_destroy_role(role);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_role(struct cil_role *role)
{
if (role == NULL) {
return;
}
cil_symtab_datum_destroy(&role->datum);
ebitmap_destroy(role->types);
free(role->types);
free(role);
}
int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_roletype *roletype = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_roletype_init(&roletype);
roletype->role_str = parse_current->next->data;
roletype->type_str = parse_current->next->next->data;
ast_node->data = roletype;
ast_node->flavor = CIL_ROLETYPE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad roletype declaration");
cil_destroy_roletype(roletype);
return rc;
}
void cil_destroy_roletype(struct cil_roletype *roletype)
{
if (roletype == NULL) {
return;
}
free(roletype);
}
int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_userrole *userrole = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_userrole_init(&userrole);
userrole->user_str = parse_current->next->data;
userrole->role_str = parse_current->next->next->data;
ast_node->data = userrole;
ast_node->flavor = CIL_USERROLE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad userrole declaration");
cil_destroy_userrole(userrole);
return rc;
}
void cil_destroy_userrole(struct cil_userrole *userrole)
{
if (userrole == NULL) {
return;
}
free(userrole);
}
int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_roletransition *roletrans = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_roletransition_init(&roletrans);
roletrans->src_str = parse_current->next->data;
roletrans->tgt_str = parse_current->next->next->data;
roletrans->obj_str = parse_current->next->next->next->data;
roletrans->result_str = parse_current->next->next->next->next->data;
ast_node->data = roletrans;
ast_node->flavor = CIL_ROLETRANSITION;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad roletransition rule");
cil_destroy_roletransition(roletrans);
return rc;
}
void cil_destroy_roletransition(struct cil_roletransition *roletrans)
{
if (roletrans == NULL) {
return;
}
free(roletrans);
}
int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_roleallow *roleallow = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_roleallow_init(&roleallow);
roleallow->src_str = parse_current->next->data;
roleallow->tgt_str = parse_current->next->next->data;
ast_node->data = roleallow;
ast_node->flavor = CIL_ROLEALLOW;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad roleallow rule");
cil_destroy_roleallow(roleallow);
return rc;
}
void cil_destroy_roleallow(struct cil_roleallow *roleallow)
{
if (roleallow == NULL) {
return;
}
free(roleallow);
}
int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_roleattribute *attr = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (parse_current->next->data == CIL_KEY_SELF) {
cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
rc = SEPOL_ERR;
goto exit;
}
cil_roleattribute_init(&attr);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_ROLES, CIL_ROLEATTRIBUTE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad roleattribute declaration");
cil_destroy_roleattribute(attr);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_roleattribute(struct cil_roleattribute *attr)
{
if (attr == NULL) {
return;
}
if (attr->expr_list != NULL) {
/* we don't want to destroy the expression stacks (cil_list) inside
* this list cil_list_destroy destroys sublists, so we need to do it
* manually */
struct cil_list_item *expr = attr->expr_list->head;
while (expr != NULL) {
struct cil_list_item *next = expr->next;
cil_list_item_destroy(&expr, CIL_FALSE);
expr = next;
}
free(attr->expr_list);
attr->expr_list = NULL;
}
cil_symtab_datum_destroy(&attr->datum);
ebitmap_destroy(attr->roles);
free(attr->roles);
free(attr);
}
int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_roleattributeset *attrset = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_roleattributeset_init(&attrset);
attrset->attr_str = parse_current->next->data;
rc = cil_gen_expr(parse_current->next->next, CIL_ROLE, &attrset->str_expr);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = attrset;
ast_node->flavor = CIL_ROLEATTRIBUTESET;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad roleattributeset declaration");
cil_destroy_roleattributeset(attrset);
return rc;
}
void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset)
{
if (attrset == NULL) {
return;
}
cil_list_destroy(&attrset->str_expr, CIL_TRUE);
cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
free(attrset);
}
int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_avrule *rule = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_avrule_init(&rule);
rule->is_extended = 0;
rule->rule_kind = rule_kind;
rule->src_str = parse_current->next->data;
rule->tgt_str = parse_current->next->next->data;
rc = cil_fill_classperms_list(parse_current->next->next->next, &rule->perms.classperms);
if (rc != SEPOL_OK) {
goto exit;
}
ast_node->data = rule;
ast_node->flavor = CIL_AVRULE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad allow rule");
cil_destroy_avrule(rule);
return rc;
}
void cil_destroy_avrule(struct cil_avrule *rule)
{
if (rule == NULL) {
return;
}
if (!rule->is_extended) {
cil_destroy_classperms_list(&rule->perms.classperms);
} else {
if (rule->perms.x.permx_str == NULL && rule->perms.x.permx != NULL) {
cil_destroy_permissionx(rule->perms.x.permx);
}
}
free(rule);
}
int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
int rc = SEPOL_ERR;
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (parse_current->data == CIL_KEY_IOCTL) {
permx->kind = CIL_PERMX_KIND_IOCTL;
} else {
cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data);
rc = SEPOL_ERR;
goto exit;
}
permx->obj_str = parse_current->next->data;
rc = cil_gen_expr(parse_current->next->next, CIL_PERMISSIONX, &permx->expr_str);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad permissionx content");
return rc;
}
int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_permissionx *permx = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_permissionx_init(&permx);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)permx, (hashtab_key_t)key, CIL_SYM_PERMX, CIL_PERMISSIONX);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_fill_permissionx(parse_current->next->next->cl_head, permx);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad permissionx statement");
cil_destroy_permissionx(permx);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_permissionx(struct cil_permissionx *permx)
{
if (permx == NULL) {
return;
}
cil_symtab_datum_destroy(&permx->datum);
cil_list_destroy(&permx->expr_str, CIL_TRUE);
ebitmap_destroy(permx->perms);
free(permx->perms);
free(permx);
}
int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_avrule *rule = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_avrule_init(&rule);
rule->is_extended = 1;
rule->rule_kind = rule_kind;
rule->src_str = parse_current->next->data;
rule->tgt_str = parse_current->next->next->data;
if (parse_current->next->next->next->cl_head == NULL) {
rule->perms.x.permx_str = parse_current->next->next->next->data;
} else {
cil_permissionx_init(&rule->perms.x.permx);
rc = cil_fill_permissionx(parse_current->next->next->next->cl_head, rule->perms.x.permx);
if (rc != SEPOL_OK) {
goto exit;
}
}
ast_node->data = rule;
ast_node->flavor = CIL_AVRULEX;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad allowx rule");
cil_destroy_avrule(rule);
return rc;
}
int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_type_rule *rule = NULL;
int rc = SEPOL_ERR;
if (parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_type_rule_init(&rule);
rule->rule_kind = rule_kind;
rule->src_str = parse_current->next->data;
rule->tgt_str = parse_current->next->next->data;
rule->obj_str = parse_current->next->next->next->data;
rule->result_str = parse_current->next->next->next->next->data;
ast_node->data = rule;
ast_node->flavor = CIL_TYPE_RULE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad type rule");
cil_destroy_type_rule(rule);
return rc;
}
void cil_destroy_type_rule(struct cil_type_rule *rule)
{
if (rule == NULL) {
return;
}
free(rule);
}
int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_type *type = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (parse_current->next->data == CIL_KEY_SELF) {
cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
rc = SEPOL_ERR;
goto exit;
}
cil_type_init(&type);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)type, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad type declaration");
cil_destroy_type(type);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_type(struct cil_type *type)
{
if (type == NULL) {
return;
}
cil_symtab_datum_destroy(&type->datum);
free(type);
}
int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_typeattribute *attr = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (parse_current->next->data == CIL_KEY_SELF) {
cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
rc = SEPOL_ERR;
goto exit;
}
cil_typeattribute_init(&attr);
key = parse_current->next->data;
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_TYPES, CIL_TYPEATTRIBUTE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad typeattribute declaration");
cil_destroy_typeattribute(attr);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_typeattribute(struct cil_typeattribute *attr)
{
if (attr == NULL) {
return;
}
cil_symtab_datum_destroy(&attr->datum);
if (attr->expr_list != NULL) {
/* we don't want to destroy the expression stacks (cil_list) inside
* this list cil_list_destroy destroys sublists, so we need to do it
* manually */
struct cil_list_item *expr = attr->expr_list->head;
while (expr != NULL) {
struct cil_list_item *next = expr->next;
cil_list_item_destroy(&expr, CIL_FALSE);
expr = next;
}
free(attr->expr_list);
attr->expr_list = NULL;
}
ebitmap_destroy(attr->types);
free(attr->types);
free(attr);
}
int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_bool *boolean = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_bool_init(&boolean);
key = parse_current->next->data;
if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
boolean->value = CIL_TRUE;
} else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
boolean->value = CIL_FALSE;
} else {
cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
rc = SEPOL_ERR;
goto exit;
}
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)boolean, (hashtab_key_t)key, CIL_SYM_BOOLS, CIL_BOOL);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
if (tunableif) {
cil_tree_log(parse_current, CIL_ERR, "Bad tunable (treated as a boolean due to preserve-tunables) declaration");
} else {
cil_tree_log(parse_current, CIL_ERR, "Bad boolean declaration");
}
cil_destroy_bool(boolean);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_bool(struct cil_bool *boolean)
{
if (boolean == NULL) {
return;
}
cil_symtab_datum_destroy(&boolean->datum);
free(boolean);
}
int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_tunable *tunable = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_tunable_init(&tunable);
key = parse_current->next->data;
if (parse_current->next->next->data == CIL_KEY_CONDTRUE) {
tunable->value = CIL_TRUE;
} else if (parse_current->next->next->data == CIL_KEY_CONDFALSE) {
tunable->value = CIL_FALSE;
} else {
cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
rc = SEPOL_ERR;
goto exit;
}
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)tunable, (hashtab_key_t)key, CIL_SYM_TUNABLES, CIL_TUNABLE);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad tunable declaration");
cil_destroy_tunable(tunable);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_tunable(struct cil_tunable *tunable)
{
if (tunable == NULL) {
return;
}
cil_symtab_datum_destroy(&tunable->datum);
free(tunable);
}
static enum cil_flavor __cil_get_expr_operator_flavor(const char *op)
{
if (op == NULL) return CIL_NONE;
else if (op == CIL_KEY_AND) return CIL_AND;
else if (op == CIL_KEY_OR) return CIL_OR;
else if (op == CIL_KEY_NOT) return CIL_NOT;
else if (op == CIL_KEY_EQ) return CIL_EQ; /* Only conditional */
else if (op == CIL_KEY_NEQ) return CIL_NEQ; /* Only conditional */
else if (op == CIL_KEY_XOR) return CIL_XOR;
else if (op == CIL_KEY_ALL) return CIL_ALL; /* Only set and permissionx */
else if (op == CIL_KEY_RANGE) return CIL_RANGE; /* Only catset and permissionx */
else return CIL_NONE;
}
static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth);
static int __cil_fill_expr_helper(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
{
int rc = SEPOL_ERR;
enum cil_flavor op;
if (flavor == CIL_BOOL && *depth > COND_EXPR_MAXDEPTH) {
cil_log(CIL_ERR, "Max depth of %d exceeded for boolean expression\n", COND_EXPR_MAXDEPTH);
goto exit;
}
op = __cil_get_expr_operator_flavor(current->data);
rc = cil_verify_expr_syntax(current, op, flavor);
if (rc != SEPOL_OK) {
goto exit;
}
if (op != CIL_NONE) {
cil_list_append(expr, CIL_OP, (void *)op);
current = current->next;
}
if (op == CIL_NONE || op == CIL_ALL) {
(*depth)++;
}
for (;current != NULL; current = current->next) {
rc = __cil_fill_expr(current, flavor, expr, depth);
if (rc != SEPOL_OK) {
goto exit;
}
}
(*depth)--;
return SEPOL_OK;
exit:
return rc;
}
static int __cil_fill_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list *expr, int *depth)
{
int rc = SEPOL_ERR;
if (current->cl_head == NULL) {
enum cil_flavor op = __cil_get_expr_operator_flavor(current->data);
if (op != CIL_NONE) {
cil_log(CIL_ERR, "Operator (%s) not in an expression\n", (char*)current->data);
goto exit;
}
cil_list_append(expr, CIL_STRING, current->data);
} else {
struct cil_list *sub_expr;
cil_list_init(&sub_expr, flavor);
rc = __cil_fill_expr_helper(current->cl_head, flavor, sub_expr, depth);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_append(expr, CIL_LIST, sub_expr);
}
return SEPOL_OK;
exit:
return rc;
}
int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
{
int rc = SEPOL_ERR;
int depth = 0;
cil_list_init(expr, flavor);
if (current->cl_head == NULL) {
rc = __cil_fill_expr(current, flavor, *expr, &depth);
} else {
rc = __cil_fill_expr_helper(current->cl_head, flavor, *expr, &depth);
}
if (rc != SEPOL_OK) {
cil_list_destroy(expr, CIL_TRUE);
cil_log(CIL_ERR, "Bad expression\n");
}
return rc;
}
static enum cil_flavor __cil_get_constraint_operator_flavor(const char *op)
{
if (op == CIL_KEY_AND) return CIL_AND;
else if (op == CIL_KEY_OR) return CIL_OR;
else if (op == CIL_KEY_NOT) return CIL_NOT;
else if (op == CIL_KEY_EQ) return CIL_EQ;
else if (op == CIL_KEY_NEQ) return CIL_NEQ;
else if (op == CIL_KEY_CONS_DOM) return CIL_CONS_DOM;
else if (op == CIL_KEY_CONS_DOMBY) return CIL_CONS_DOMBY;
else if (op == CIL_KEY_CONS_INCOMP) return CIL_CONS_INCOMP;
else return CIL_NONE;
}
static enum cil_flavor __cil_get_constraint_operand_flavor(const char *operand)
{
if (operand == NULL) return CIL_LIST;
else if (operand == CIL_KEY_CONS_T1) return CIL_CONS_T1;
else if (operand == CIL_KEY_CONS_T2) return CIL_CONS_T2;
else if (operand == CIL_KEY_CONS_T3) return CIL_CONS_T3;
else if (operand == CIL_KEY_CONS_R1) return CIL_CONS_R1;
else if (operand == CIL_KEY_CONS_R2) return CIL_CONS_R2;
else if (operand == CIL_KEY_CONS_R3) return CIL_CONS_R3;
else if (operand == CIL_KEY_CONS_U1) return CIL_CONS_U1;
else if (operand == CIL_KEY_CONS_U2) return CIL_CONS_U2;
else if (operand == CIL_KEY_CONS_U3) return CIL_CONS_U3;
else if (operand == CIL_KEY_CONS_L1) return CIL_CONS_L1;
else if (operand == CIL_KEY_CONS_L2) return CIL_CONS_L2;
else if (operand == CIL_KEY_CONS_H1) return CIL_CONS_H1;
else if (operand == CIL_KEY_CONS_H2) return CIL_CONS_H2;
else return CIL_STRING;
}
static int __cil_fill_constraint_leaf_expr(struct cil_tree_node *current, enum cil_flavor expr_flavor, enum cil_flavor op, struct cil_list **leaf_expr)
{
int rc = SEPOL_ERR;
enum cil_flavor leaf_expr_flavor = CIL_NONE;
enum cil_flavor l_flavor = CIL_NONE;
enum cil_flavor r_flavor = CIL_NONE;
l_flavor = __cil_get_constraint_operand_flavor(current->next->data);
r_flavor = __cil_get_constraint_operand_flavor(current->next->next->data);
switch (l_flavor) {
case CIL_CONS_U1:
case CIL_CONS_U2:
case CIL_CONS_U3:
leaf_expr_flavor = CIL_USER;
break;
case CIL_CONS_R1:
case CIL_CONS_R2:
case CIL_CONS_R3:
leaf_expr_flavor = CIL_ROLE;
break;
case CIL_CONS_T1:
case CIL_CONS_T2:
case CIL_CONS_T3:
leaf_expr_flavor = CIL_TYPE;
break;
case CIL_CONS_L1:
case CIL_CONS_L2:
case CIL_CONS_H1:
case CIL_CONS_H2:
leaf_expr_flavor = CIL_LEVEL;
break;
default:
cil_log(CIL_ERR, "Invalid left operand (%s)\n", (char*)current->next->data);
goto exit;
}
rc = cil_verify_constraint_leaf_expr_syntax(l_flavor, r_flavor, op, expr_flavor);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_init(leaf_expr, leaf_expr_flavor);
cil_list_append(*leaf_expr, CIL_OP, (void *)op);
cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)l_flavor);
if (r_flavor == CIL_STRING) {
cil_list_append(*leaf_expr, CIL_STRING, current->next->next->data);
} else if (r_flavor == CIL_LIST) {
struct cil_list *sub_list;
cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list);
cil_list_append(*leaf_expr, CIL_LIST, &sub_list);
} else {
cil_list_append(*leaf_expr, CIL_CONS_OPERAND, (void *)r_flavor);
}
return SEPOL_OK;
exit:
return SEPOL_ERR;
}
static int __cil_fill_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr, int *depth)
{
int rc = SEPOL_ERR;
enum cil_flavor op;
struct cil_list *lexpr;
struct cil_list *rexpr;
if (current->data == NULL || current->cl_head != NULL) {
cil_log(CIL_ERR, "Expected a string at the start of the constraint expression\n");
goto exit;
}
if (*depth > CEXPR_MAXDEPTH) {
cil_log(CIL_ERR, "Max depth of %d exceeded for constraint expression\n", CEXPR_MAXDEPTH);
rc = SEPOL_ERR;
goto exit;
}
op = __cil_get_constraint_operator_flavor(current->data);
rc = cil_verify_constraint_expr_syntax(current, op);
if (rc != SEPOL_OK) {
goto exit;
}
switch (op) {
case CIL_EQ:
case CIL_NEQ:
case CIL_CONS_DOM:
case CIL_CONS_DOMBY:
case CIL_CONS_INCOMP:
(*depth)++;
rc = __cil_fill_constraint_leaf_expr(current, flavor, op, expr);
if (rc != SEPOL_OK) {
goto exit;
}
break;
case CIL_NOT:
rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_init(expr, flavor);
cil_list_append(*expr, CIL_OP, (void *)op);
cil_list_append(*expr, CIL_LIST, lexpr);
break;
default:
rc = __cil_fill_constraint_expr(current->next->cl_head, flavor, &lexpr, depth);
if (rc != SEPOL_OK) {
goto exit;
}
rc = __cil_fill_constraint_expr(current->next->next->cl_head, flavor, &rexpr, depth);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_init(expr, flavor);
cil_list_append(*expr, CIL_OP, (void *)op);
cil_list_append(*expr, CIL_LIST, lexpr);
cil_list_append(*expr, CIL_LIST, rexpr);
break;
}
(*depth)--;
return SEPOL_OK;
exit:
return rc;
}
int cil_gen_constraint_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **expr)
{
int rc = SEPOL_ERR;
int depth = 0;
if (current->cl_head == NULL) {
goto exit;
}
rc = __cil_fill_constraint_expr(current->cl_head, flavor, expr, &depth);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_log(CIL_ERR, "Bad expression tree for constraint\n");
return rc;
}
int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_LIST,
CIL_SYN_LIST | CIL_SYN_END,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_booleanif *bif = NULL;
struct cil_tree_node *next = NULL;
struct cil_tree_node *cond = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_boolif_init(&bif);
bif->preserved_tunable = tunableif;
rc = cil_gen_expr(parse_current->next, CIL_BOOL, &bif->str_expr);
if (rc != SEPOL_OK) {
goto exit;
}
cond = parse_current->next->next;
/* Destroying expr tree after stack is created*/
if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
cond->cl_head->data != CIL_KEY_CONDFALSE) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Conditional neither true nor false\n");
goto exit;
}
if (cond->next != NULL) {
cond = cond->next;
if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
cond->cl_head->data != CIL_KEY_CONDFALSE) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Conditional neither true nor false\n");
goto exit;
}
}
next = parse_current->next->next;
cil_tree_subtree_destroy(parse_current->next);
parse_current->next = next;
ast_node->flavor = CIL_BOOLEANIF;
ast_node->data = bif;
return SEPOL_OK;
exit:
if (tunableif) {
cil_tree_log(parse_current, CIL_ERR, "Bad tunableif (treated as a booleanif due to preserve-tunables) declaration");
} else {
cil_tree_log(parse_current, CIL_ERR, "Bad booleanif declaration");
}
cil_destroy_boolif(bif);
return rc;
}
void cil_destroy_boolif(struct cil_booleanif *bif)
{
if (bif == NULL) {
return;
}
cil_list_destroy(&bif->str_expr, CIL_TRUE);
cil_list_destroy(&bif->datum_expr, CIL_FALSE);
free(bif);
}
int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_LIST,
CIL_SYN_LIST | CIL_SYN_END,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_tunableif *tif = NULL;
struct cil_tree_node *next = NULL;
struct cil_tree_node *cond = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_tunif_init(&tif);
rc = cil_gen_expr(parse_current->next, CIL_TUNABLE, &tif->str_expr);
if (rc != SEPOL_OK) {
goto exit;
}
cond = parse_current->next->next;
if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
cond->cl_head->data != CIL_KEY_CONDFALSE) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Conditional neither true nor false\n");
goto exit;
}
if (cond->next != NULL) {
cond = cond->next;
if (cond->cl_head->data != CIL_KEY_CONDTRUE &&
cond->cl_head->data != CIL_KEY_CONDFALSE) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Conditional neither true nor false\n");
goto exit;
}
}
/* Destroying expr tree after stack is created*/
next = parse_current->next->next;
cil_tree_subtree_destroy(parse_current->next);
parse_current->next = next;
ast_node->flavor = CIL_TUNABLEIF;
ast_node->data = tif;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad tunableif declaration");
cil_destroy_tunif(tif);
return rc;
}
void cil_destroy_tunif(struct cil_tunableif *tif)
{
if (tif == NULL) {
return;
}
cil_list_destroy(&tif->str_expr, CIL_TRUE);
cil_list_destroy(&tif->datum_expr, CIL_FALSE);
free(tif);
}
int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_N_LISTS,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
int rc = SEPOL_ERR;
struct cil_condblock *cb = NULL;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (ast_node->parent->flavor != CIL_BOOLEANIF && ast_node->parent->flavor != CIL_TUNABLEIF) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Conditional statements must be a direct child of a tunableif or booleanif statement.\n");
goto exit;
}
ast_node->flavor = CIL_CONDBLOCK;
cil_condblock_init(&cb);
cb->flavor = flavor;
ast_node->data = cb;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad %s condition declaration",
(char*)parse_current->data);
cil_destroy_condblock(cb);
return rc;
}
void cil_destroy_condblock(struct cil_condblock *cb)
{
if (cb == NULL) {
return;
}
cil_symtab_array_destroy(cb->symtab);
free(cb);
}
int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
char *key = NULL;
struct cil_alias *alias = NULL;
enum cil_sym_index sym_index;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if (flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) {
cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
rc = SEPOL_ERR;
goto exit;
}
cil_alias_init(&alias);
key = parse_current->next->data;
rc = cil_flavor_to_symtab_index(flavor, &sym_index);
if (rc != SEPOL_OK) {
goto exit;
}
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)alias, (hashtab_key_t)key, sym_index, flavor);
if (rc != SEPOL_OK) {
goto exit;
}
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad %s declaration", (char*)parse_current->data);
cil_destroy_alias(alias);
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_alias(struct cil_alias *alias)
{
if (alias == NULL) {
return;
}
cil_symtab_datum_destroy(&alias->datum);
alias->actual = NULL;
free(alias);
}
int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor)
{
int rc = SEPOL_ERR;
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_END
};
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_aliasactual *aliasactual = NULL;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
if ((flavor == CIL_TYPEALIAS && parse_current->next->data == CIL_KEY_SELF) || parse_current->next->next->data == CIL_KEY_SELF) {
cil_log(CIL_ERR, "The keyword '%s' is reserved\n", CIL_KEY_SELF);
rc = SEPOL_ERR;
goto exit;
}
cil_aliasactual_init(&aliasactual);
aliasactual->alias_str = parse_current->next->data;
aliasactual->actual_str = parse_current->next->next->data;
ast_node->data = aliasactual;
ast_node->flavor = flavor;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad %s association", cil_node_to_string(parse_current));
cil_clear_node(ast_node);
return rc;
}
void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual)
{
if (aliasactual == NULL) {
return;
}
free(aliasactual);
}
int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)