/*
* 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 <stdint.h>
#include <unistd.h>
#include <inttypes.h>
#include <sepol/policydb/conditional.h>
#include <sepol/errcodes.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_policy.h"
#include "cil_symtab.h"
#include "cil_strpool.h"
#define SEPOL_DONE 555
#define CLASS_DECL 0
#define ISIDS 1
#define COMMONS 2
#define CLASSES 3
#define INTERFACES 4
#define SENS 5
#define CATS 6
#define LEVELS 7
#define CONSTRAINS 8
#define TYPEATTRTYPES 9
#define ALIASES 10
#define ALLOWS 11
#define CONDS 12
#define USERROLES 13
#define SIDS 14
#define NETIFCONS 15
#define BUFFER 1024
#define NUM_POLICY_FILES 16
struct cil_args_genpolicy {
struct cil_list *users;
struct cil_list *sens;
struct cil_list *cats;
FILE **file_arr;
};
struct cil_args_booleanif {
FILE **file_arr;
uint32_t *file_index;
};
int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr);
int cil_combine_policy(FILE **file_arr, FILE *policy_file)
{
char temp[BUFFER];
int i, rc, rc_read, rc_write;
for(i=0; i<NUM_POLICY_FILES; i++) {
fseek(file_arr[i], 0, SEEK_SET);
while (!feof(file_arr[i])) {
rc_read = fread(temp, 1, BUFFER, file_arr[i]);
if (rc_read == 0 && ferror(file_arr[i])) {
cil_log(CIL_ERR, "Error reading temp policy file\n");
return SEPOL_ERR;
}
rc_write = 0;
while (rc_read > rc_write) {
rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file);
rc_write += rc;
if (rc == 0 && ferror(file_arr[i])) {
cil_log(CIL_ERR, "Error writing to policy.conf\n");
return SEPOL_ERR;
}
}
}
}
return SEPOL_OK;
}
int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i=0; i<sort->count; i++) {
struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "portcon ");
if (portcon->proto == CIL_PROTOCOL_UDP) {
fprintf(file_arr[NETIFCONS], "udp ");
} else if (portcon->proto == CIL_PROTOCOL_TCP) {
fprintf(file_arr[NETIFCONS], "tcp ");
}
fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low);
fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high);
cil_context_to_policy(file_arr, NETIFCONS, portcon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i=0; i<sort->count; i++) {
struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str);
fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str);
cil_context_to_policy(file_arr, NETIFCONS, genfscon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i=0; i<sort->count; i++) {
struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str);
cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context);
fprintf(file_arr[NETIFCONS], " ");
cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
int rc = SEPOL_ERR;
for (i=0; i<sort->count; i++) {
struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i];
char *buf = NULL;
errno = 0;
if (nodecon->addr->family == AF_INET) {
buf = cil_malloc(INET_ADDRSTRLEN);
inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN);
} else if (nodecon->addr->family == AF_INET6) {
buf = cil_malloc(INET6_ADDRSTRLEN);
inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN);
}
if (errno != 0) {
cil_log(CIL_INFO, "Failed to convert ip address to string\n");
rc = SEPOL_ERR;
goto exit;
}
fprintf(file_arr[NETIFCONS], "nodecon %s ", buf);
free(buf);
if (nodecon->mask->family == AF_INET) {
buf = cil_malloc(INET_ADDRSTRLEN);
inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN);
} else if (nodecon->mask->family == AF_INET6) {
buf = cil_malloc(INET6_ADDRSTRLEN);
inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN);
}
if (errno != 0) {
cil_log(CIL_INFO, "Failed to convert mask to string\n");
rc = SEPOL_ERR;
goto exit;
}
fprintf(file_arr[NETIFCONS], "%s ", buf);
free(buf);
cil_context_to_policy(file_arr, NETIFCONS, nodecon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
exit:
return rc;
}
int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i = 0; i < sort->count; i++) {
struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq);
cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i = 0; i < sort->count; i++) {
struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high);
cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i = 0; i < sort->count; i++) {
struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high);
cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i = 0; i < sort->count; i++) {
struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i];
fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev);
cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort)
{
uint32_t i = 0;
for (i=0; i<sort->count; i++) {
struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i];
if (fsuse->type == CIL_FSUSE_XATTR) {
fprintf(file_arr[NETIFCONS], "fs_use_xattr ");
} else if (fsuse->type == CIL_FSUSE_TASK) {
fprintf(file_arr[NETIFCONS], "fs_use_task ");
} else if (fsuse->type == CIL_FSUSE_TRANS) {
fprintf(file_arr[NETIFCONS], "fs_use_trans ");
} else {
return SEPOL_ERR;
}
fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str);
cil_context_to_policy(file_arr, NETIFCONS, fsuse->context);
fprintf(file_arr[NETIFCONS], ";\n");
}
return SEPOL_OK;
}
int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor)
{
struct cil_list_item *curr_key;
struct cil_multimap_item *new_data;
if (list == NULL || key == NULL) {
return SEPOL_ERR;
}
cil_list_for_each(curr_key, list) {
struct cil_multimap_item *curr_multimap_item = curr_key->data;
if (curr_multimap_item != NULL) {
if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) {
struct cil_list_item *curr_value;
cil_list_for_each(curr_value, curr_multimap_item->values) {
if (curr_value == (struct cil_list_item*)value) {
return SEPOL_OK;;
}
}
cil_list_append(curr_multimap_item->values, val_flavor, value);
}
} else {
cil_log(CIL_INFO, "No data in list item\n");
return SEPOL_ERR;
}
}
new_data = cil_malloc(sizeof(*new_data));
new_data->key = key;
cil_list_init(&new_data->values, CIL_LIST_ITEM);
if (value != NULL) {
cil_list_append(new_data->values, val_flavor, value);
}
cil_list_append(list, key_flavor, new_data);
return SEPOL_OK;
}
int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles)
{
struct cil_list_item *current_user;
if (userroles == NULL) {
return SEPOL_OK;
}
cil_list_for_each(current_user, userroles) {
struct cil_multimap_item *user_multimap_item = current_user->data;
struct cil_list_item *current_role;
if (user_multimap_item->values->head == NULL) {
cil_log(CIL_INFO, "No roles associated with user %s\n",
user_multimap_item->key->name);
return SEPOL_ERR;
}
fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name);
cil_list_for_each(current_role, user_multimap_item->values) {
fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name);
}
fprintf(file_arr[USERROLES], " };\n");
}
return SEPOL_OK;
}
int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats)
{
struct cil_list_item *curr_cat;
if (cats == NULL) {
return SEPOL_OK;
}
cil_list_for_each(curr_cat, cats) {
struct cil_multimap_item *cat_multimap_item = curr_cat->data;
fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name);
if (cat_multimap_item->values->head == NULL) {
fprintf(file_arr[CATS], ";\n");
} else {
struct cil_list_item *curr_catalias;
fprintf(file_arr[CATS], " alias");
cil_list_for_each(curr_catalias, cat_multimap_item->values) {
fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name);
}
fprintf(file_arr[CATS], ";\n");
}
}
return SEPOL_OK;
}
int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens)
{
struct cil_list_item *curr_sens;
if (sens == NULL) {
return SEPOL_OK;
}
cil_list_for_each(curr_sens, sens) {
struct cil_multimap_item *sens_multimap_item = curr_sens->data;
fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name);
if (sens_multimap_item->values->head == NULL)
fprintf(file_arr[SENS], ";\n");
else {
struct cil_list_item *curr_sensalias;
fprintf(file_arr[SENS], " alias");
cil_list_for_each(curr_sensalias, sens_multimap_item->values) {
fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name);
}
fprintf(file_arr[SENS], ";\n");
}
}
return SEPOL_OK;
}
void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats)
{
cil_expr_to_policy(file_arr, file_index, cats->datum_expr);
}
void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level)
{
char *sens_str = level->sens->datum.name;
fprintf(file_arr[file_index], "%s", sens_str);
if (level->cats != NULL) {
fprintf(file_arr[file_index], ":");
cil_cats_to_policy(file_arr, file_index, level->cats);
}
}
void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange)
{
struct cil_level *low = lvlrange->low;
struct cil_level *high = lvlrange->high;
cil_level_to_policy(file_arr, file_index, low);
fprintf(file_arr[file_index], "-");
cil_level_to_policy(file_arr, file_index, high);
}
void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context)
{
char *user_str = ((struct cil_symtab_datum*)context->user)->name;
char *role_str = ((struct cil_symtab_datum*)context->role)->name;
char *type_str = ((struct cil_symtab_datum*)context->type)->name;
struct cil_levelrange *lvlrange = context->range;
fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str);
cil_levelrange_to_policy(file_arr, file_index, lvlrange);
}
void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list)
{
struct cil_list_item *curr;
fprintf(file_arr[file_index], " {");
cil_list_for_each(curr, list) {
switch (curr->flavor) {
case CIL_LIST:
cil_perms_to_policy(file_arr, file_index, curr->data);
break;
case CIL_STRING:
fprintf(file_arr[file_index], " %s", (char *)curr->data);
break;
case CIL_DATUM:
fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name);
break;
case CIL_OP: {
enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
char *op_str = NULL;
switch (op_flavor) {
case CIL_AND:
op_str = CIL_KEY_AND;
break;
case CIL_OR:
op_str = CIL_KEY_OR;
break;
case CIL_NOT:
op_str = CIL_KEY_NOT;
break;
case CIL_ALL:
op_str = CIL_KEY_ALL;
break;
case CIL_XOR:
op_str = CIL_KEY_XOR;
break;
default:
cil_log(CIL_ERR, "Unknown operator in expression\n");
break;
}
fprintf(file_arr[file_index], " %s", op_str);
break;
}
default:
cil_log(CIL_ERR, "Unknown flavor in expression\n");
break;
}
}
fprintf(file_arr[file_index], " }");
}
void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr)
{
struct cil_list_item *curr;
cil_list_for_each(curr, classperms) {
if (curr->flavor == CIL_CLASSPERMS) {
struct cil_classperms *cp = curr->data;
if (FLAVOR(cp->class) == CIL_CLASS) {
fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name);
cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms);
fprintf(file_arr[CONSTRAINS], "\n\t");
cil_expr_to_policy(file_arr, CONSTRAINS, expr);
fprintf(file_arr[CONSTRAINS], ";\n");
} else { /* MAP */
struct cil_list_item *i = NULL;
cil_list_for_each(i, cp->perms) {
struct cil_perm *cmp = i->data;
cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr);
}
}
} else { /* SET */
struct cil_classperms_set *cp_set = curr->data;
struct cil_classpermission *cp = cp_set->set;
cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr);
}
}
}
void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor)
{
char *kind = NULL;
if (flavor == CIL_CONSTRAIN) {
kind = CIL_KEY_CONSTRAIN;
} else if (flavor == CIL_MLSCONSTRAIN) {
kind = CIL_KEY_MLSCONSTRAIN;
}
cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr);
}
void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms)
{
struct cil_list_item *i;
cil_list_for_each(i, classperms) {
if (i->flavor == CIL_CLASSPERMS) {
struct cil_classperms *cp = i->data;
if (FLAVOR(cp->class) == CIL_CLASS) {
fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name);
cil_perms_to_policy(file_arr, file_index, cp->perms);
fprintf(file_arr[file_index], ";\n");
} else { /* MAP */
struct cil_list_item *j = NULL;
cil_list_for_each(j, cp->perms) {
struct cil_perm *cmp = j->data;
cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms);
}
}
} else { /* SET */
struct cil_list_item *j;
struct cil_classperms_set *cp_set = i->data;
struct cil_classpermission *cp = cp_set->set;
cil_list_for_each(j, cp->classperms) {
cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data);
}
}
}
}
int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule)
{
const char *kind_str = NULL;
const char *src_str = DATUM(rule->src)->name;
const char *tgt_str = DATUM(rule->tgt)->name;
switch (rule->rule_kind) {
case CIL_AVRULE_ALLOWED:
kind_str = "allow";
break;
case CIL_AVRULE_AUDITALLOW:
kind_str = "auditallow";
break;
case CIL_AVRULE_DONTAUDIT:
kind_str = "dontaudit";
break;
case CIL_AVRULE_NEVERALLOW:
kind_str = "neverallow";
break;
default :
cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n",
rule->rule_kind, src_str, tgt_str);
return SEPOL_ERR;
}
cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->classperms);
return SEPOL_OK;
}
int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule)
{
char *src_str = ((struct cil_symtab_datum*)rule->src)->name;
char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name;
char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name;
char *result_str = ((struct cil_symtab_datum*)rule->result)->name;
switch (rule->rule_kind) {
case CIL_TYPE_TRANSITION:
fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
break;
case CIL_TYPE_CHANGE:
fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str);
break;
case CIL_TYPE_MEMBER:
fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str);
break;
default:
cil_log(CIL_INFO, "Unknown type_rule\n");
return SEPOL_ERR;
}
return SEPOL_OK;
}
int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans)
{
char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name;
char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name;
char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name;
char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name;
fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str);
return SEPOL_OK;
}
static int cil_expr_to_string(struct cil_list *expr, char **out)
{
int rc = SEPOL_ERR;
struct cil_list_item *curr;
char *stack[COND_EXPR_MAXDEPTH] = {};
int pos = 0;
int i;
cil_list_for_each(curr, expr) {
if (pos > COND_EXPR_MAXDEPTH) {
rc = SEPOL_ERR;
goto exit;
}
switch (curr->flavor) {
case CIL_LIST:
rc = cil_expr_to_string(curr->data, &stack[pos]);
if (rc != SEPOL_OK) {
goto exit;
}
pos++;
break;
case CIL_STRING:
stack[pos] = curr->data;
pos++;
break;
case CIL_DATUM:
stack[pos] = ((struct cil_symtab_datum *)curr->data)->name;
pos++;
break;
case CIL_OP: {
int len;
char *expr_str;
enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data);
char *op_str = NULL;
if (pos == 0) {
rc = SEPOL_ERR;
goto exit;
}
switch (op_flavor) {
case CIL_AND:
op_str = CIL_KEY_AND;
break;
case CIL_OR:
op_str = CIL_KEY_OR;
break;
case CIL_NOT:
op_str = CIL_KEY_NOT;
break;
case CIL_ALL:
op_str = CIL_KEY_ALL;
break;
case CIL_EQ:
op_str = CIL_KEY_EQ;
break;
case CIL_NEQ:
op_str = CIL_KEY_NEQ;
break;
case CIL_XOR:
op_str = CIL_KEY_XOR;
break;
case CIL_CONS_DOM:
op_str = CIL_KEY_CONS_DOM;
break;
case CIL_CONS_DOMBY:
op_str = CIL_KEY_CONS_DOMBY;
break;
case CIL_CONS_INCOMP:
op_str = CIL_KEY_CONS_INCOMP;
break;
default:
cil_log(CIL_ERR, "Unknown operator in expression\n");
goto exit;
break;
}
if (op_flavor == CIL_NOT) {
len = strlen(stack[pos-1]) + strlen(op_str) + 4;
expr_str = cil_malloc(len);
snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]);
free(stack[pos-1]);
stack[pos-1] = NULL;
pos--;
} else {
if (pos < 2) {
rc = SEPOL_ERR;
goto exit;
}
len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5;
expr_str = cil_malloc(len);
snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]);
free(stack[pos-2]);
free(stack[pos-1]);
stack[pos-2] = NULL;
stack[pos-1] = NULL;
pos -= 2;
}
stack[pos] = expr_str;
pos++;
break;
}
case CIL_CONS_OPERAND: {
enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data);
char *operand_str = NULL;
switch (operand_flavor) {
case CIL_CONS_U1:
operand_str = CIL_KEY_CONS_U1;
break;
case CIL_CONS_U2:
operand_str = CIL_KEY_CONS_U2;
break;
case CIL_CONS_U3:
operand_str = CIL_KEY_CONS_U3;
break;
case CIL_CONS_T1:
operand_str = CIL_KEY_CONS_T1;
break;
case CIL_CONS_T2:
operand_str = CIL_KEY_CONS_T2;
break;
case CIL_CONS_T3:
operand_str = CIL_KEY_CONS_T3;
break;
case CIL_CONS_R1:
operand_str = CIL_KEY_CONS_R1;
break;
case CIL_CONS_R2:
operand_str = CIL_KEY_CONS_R2;
break;
case CIL_CONS_R3:
operand_str = CIL_KEY_CONS_R3;
break;
case CIL_CONS_L1:
operand_str = CIL_KEY_CONS_L1;
break;
case CIL_CONS_L2:
operand_str = CIL_KEY_CONS_L2;
break;
case CIL_CONS_H1:
operand_str = CIL_KEY_CONS_H1;
break;
case CIL_CONS_H2:
operand_str = CIL_KEY_CONS_H2;
break;
default:
cil_log(CIL_ERR, "Unknown operand in expression\n");
goto exit;
break;
}
stack[pos] = operand_str;
pos++;
break;
}
default:
cil_log(CIL_ERR, "Unknown flavor in expression\n");
goto exit;
break;
}
}
*out = stack[0];
return SEPOL_OK;
exit:
for (i = 0; i < pos; i++) {
free(stack[i]);
}
return rc;
}
int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr)
{
int rc = SEPOL_ERR;
char *str_out;
rc = cil_expr_to_string(expr, &str_out);
if (rc != SEPOL_OK) {
goto out;
}
fprintf(file_arr[file_index], "%s", str_out);
free(str_out);
return SEPOL_OK;
out:
return rc;
}
int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
{
int rc = SEPOL_ERR;
struct cil_args_booleanif *args;
FILE **file_arr;
uint32_t *file_index;
args = extra_args;
file_arr = args->file_arr;
file_index = args->file_index;
switch (node->flavor) {
case CIL_AVRULE:
rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc);
return rc;
}
break;
case CIL_TYPE_RULE:
rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc);
return rc;
}
break;
case CIL_FALSE:
fprintf(file_arr[*file_index], "else {\n");
break;
case CIL_TRUE:
break;
default:
return SEPOL_ERR;
}
return SEPOL_OK;
}
int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args)
{
struct cil_args_booleanif *args;
FILE **file_arr;
uint32_t *file_index;
args = extra_args;
file_arr = args->file_arr;
file_index = args->file_index;
if (node->parent->flavor == CIL_FALSE) {
fprintf(file_arr[*file_index], "}\n");
}
return SEPOL_OK;
}
int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node)
{
int rc = SEPOL_ERR;
struct cil_booleanif *bif = node->data;
struct cil_list *expr = bif->datum_expr;
struct cil_args_booleanif extra_args;
struct cil_tree_node *true_node = NULL;
struct cil_tree_node *false_node = NULL;
struct cil_condblock *cb = NULL;
extra_args.file_arr = file_arr;
extra_args.file_index = &file_index;;
fprintf(file_arr[file_index], "if ");
rc = cil_expr_to_policy(file_arr, file_index, expr);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Failed to write expression\n");
return rc;
}
if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) {
cb = node->cl_head->data;
if (cb->flavor == CIL_CONDTRUE) {
true_node = node->cl_head;
} else if (cb->flavor == CIL_CONDFALSE) {
false_node = node->cl_head;
}
}
if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) {
cb = node->cl_head->next->data;
if (cb->flavor == CIL_CONDTRUE) {
true_node = node->cl_head->next;
} else if (cb->flavor == CIL_CONDFALSE) {
false_node = node->cl_head->next;
}
}
fprintf(file_arr[file_index], "{\n");
if (true_node != NULL) {
rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc);
return rc;
}
}
fprintf(file_arr[file_index], "}\n");
if (false_node != NULL) {
fprintf(file_arr[file_index], "else {\n");
rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc);
return rc;
}
fprintf(file_arr[file_index], "}\n");
}
return SEPOL_OK;
}
int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current)
{
uint32_t flavor = current->flavor;
int rc = SEPOL_ERR;
switch(flavor) {
case CIL_TYPEATTRIBUTE:
fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name);
break;
case CIL_TYPE:
fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name);
break;
case CIL_TYPEALIAS: {
struct cil_alias *alias = current->data;
fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name);
break;
}
case CIL_TYPEBOUNDS: {
struct cil_bounds *bnds = current->data;
fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str);
break;
}
case CIL_TYPEPERMISSIVE: {
struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data;
fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name);
break;
}
case CIL_ROLE:
fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name);
break;
case CIL_BOOL: {
const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false";
fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean);
break;
}
case CIL_COMMON:
fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name);
if (current->cl_head != NULL) {
current = current->cl_head;
fprintf(file_arr[COMMONS], " {");
} else {
cil_log(CIL_INFO, "No permissions given\n");
return SEPOL_ERR;
}
while (current != NULL) {
if (current->flavor == CIL_PERM) {
fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name);
} else {
cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor);
return SEPOL_ERR;
}
current = current->next;
}
fprintf(file_arr[COMMONS], "}\n");
return SEPOL_DONE;
case CIL_AVRULE: {
struct cil_avrule *avrule = (struct cil_avrule*)current->data;
rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write avrule to policy\n");
return rc;
}
break;
}
case CIL_TYPE_RULE: {
struct cil_type_rule *rule = (struct cil_type_rule*)current->data;
rc = cil_typerule_to_policy(file_arr, ALLOWS, rule);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write type rule to policy\n");
return rc;
}
break;
}
case CIL_NAMETYPETRANSITION: {
struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data;
rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n");
return rc;
}
}
case CIL_ROLETRANSITION: {
struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data;
char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name;
char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name;
char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name;
char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name;
fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str);
break;
}
case CIL_ROLEALLOW: {
struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data;
char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name;
char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name;
fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str);
break;
}
case CIL_ROLETYPE: {
struct cil_roletype *roletype = (struct cil_roletype*)current->data;
char *role_str = ((struct cil_symtab_datum*)roletype->role)->name;
char *type_str = ((struct cil_symtab_datum*)roletype->type)->name;
fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str);
break;
}
case CIL_LEVEL:
fprintf(file_arr[LEVELS], "level ");
cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data);
fprintf(file_arr[LEVELS], ";\n");
break;
case CIL_CONSTRAIN:
cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
break;
case CIL_MLSCONSTRAIN:
cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor);
break;
case CIL_VALIDATETRANS: {
struct cil_validatetrans *vt = current->data;
fprintf(file_arr[CONSTRAINS], "validatetrans");
fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name);
cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
fprintf(file_arr[CONSTRAINS], ";\n");
break;
}
case CIL_MLSVALIDATETRANS: {
struct cil_validatetrans *vt = current->data;
fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans");
fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name);
cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr);
fprintf(file_arr[CONSTRAINS], ";\n");
break;
}
case CIL_SID:
fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name);
break;
case CIL_SIDCONTEXT: {
struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data;
fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str);
cil_context_to_policy(file_arr, SIDS, sidcon->context);
fprintf(file_arr[SIDS], "\n");
break;
}
case CIL_POLICYCAP:
fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name);
break;
default:
break;
}
return SEPOL_OK;
}
int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
{
int rc = SEPOL_ERR;
struct cil_args_genpolicy *args = NULL;
struct cil_list *users = NULL;
struct cil_list *sens = NULL;
struct cil_list *cats = NULL;
FILE **file_arr = NULL;
if (extra_args == NULL) {
return SEPOL_ERR;
}
*finished = CIL_TREE_SKIP_NOTHING;
args = extra_args;
users = args->users;
sens = args->sens;
cats = args->cats;
file_arr = args->file_arr;
if (node->cl_head != NULL) {
if (node->flavor == CIL_MACRO) {
*finished = CIL_TREE_SKIP_HEAD;
return SEPOL_OK;
}
if (node->flavor == CIL_BOOLEANIF) {
rc = cil_booleanif_to_policy(file_arr, CONDS, node);
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "Failed to write booleanif contents to file\n");
return rc;
}
*finished = CIL_TREE_SKIP_HEAD;
return SEPOL_OK;
}
if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) {
*finished = CIL_TREE_SKIP_HEAD;
return SEPOL_OK;
}
if (node->flavor != CIL_ROOT) {
rc = cil_name_to_policy(file_arr, node);
if (rc != SEPOL_OK && rc != SEPOL_DONE) {
cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor);
return SEPOL_ERR;
}
}
} else {
switch (node->flavor) {
case CIL_USER:
cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
break;
case CIL_USERROLE: {
struct cil_userrole *userrole = node->data;
cil_multimap_insert(users, &userrole->user->datum, (struct cil_symtab_datum *)userrole->role, CIL_USERROLE, CIL_ROLE);
}
break;
case CIL_CATALIAS: {
struct cil_alias *alias = node->data;
struct cil_symtab_datum *datum = alias->actual;
cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS);
}
break;
case CIL_SENSALIAS: {
struct cil_alias *alias = node->data;
struct cil_symtab_datum *datum = alias->actual;
cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS);
}
break;
default:
rc = cil_name_to_policy(file_arr, node);
if (rc != SEPOL_OK && rc != SEPOL_DONE) {
cil_log(CIL_ERR, "Error converting node to policy %d\n", rc);
return SEPOL_ERR;
}
break;
}
}
return SEPOL_OK;
}
int cil_gen_policy(struct cil_db *db)
{
struct cil_tree_node *curr = db->ast->root;
struct cil_list_item *item;
int rc = SEPOL_ERR;
FILE *policy_file;
FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES);
char *file_path_arr[NUM_POLICY_FILES];
char temp[32];
struct cil_list *users = NULL;
struct cil_list *cats = NULL;
struct cil_list *sens = NULL;
struct cil_args_genpolicy extra_args;
cil_list_init(&users, CIL_LIST_ITEM);
cil_list_init(&cats, CIL_LIST_ITEM);
cil_list_init(&sens, CIL_LIST_ITEM);
strcpy(temp, "/tmp/cil_classdecl-XXXXXX");
file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+");
file_path_arr[CLASS_DECL] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_isids-XXXXXX");
file_arr[ISIDS] = fdopen(mkstemp(temp), "w+");
file_path_arr[ISIDS] = cil_strpool_add(temp);
strcpy(temp,"/tmp/cil_common-XXXXXX");
file_arr[COMMONS] = fdopen(mkstemp(temp), "w+");
file_path_arr[COMMONS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_class-XXXXXX");
file_arr[CLASSES] = fdopen(mkstemp(temp), "w+");
file_path_arr[CLASSES] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_interf-XXXXXX");
file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+");
file_path_arr[INTERFACES] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_sens-XXXXXX");
file_arr[SENS] = fdopen(mkstemp(temp), "w+");
file_path_arr[SENS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_cats-XXXXXX");
file_arr[CATS] = fdopen(mkstemp(temp), "w+");
file_path_arr[CATS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_levels-XXXXXX");
file_arr[LEVELS] = fdopen(mkstemp(temp), "w+");
file_path_arr[LEVELS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_mlscon-XXXXXX");
file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+");
file_path_arr[CONSTRAINS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_attrtypes-XXXXXX");
file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+");
file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_aliases-XXXXXX");
file_arr[ALIASES] = fdopen(mkstemp(temp), "w+");
file_path_arr[ALIASES] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_allows-XXXXXX");
file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+");
file_path_arr[ALLOWS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_conds-XXXXXX");
file_arr[CONDS] = fdopen(mkstemp(temp), "w+");
file_path_arr[CONDS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_userroles-XXXXXX");
file_arr[USERROLES] = fdopen(mkstemp(temp), "w+");
file_path_arr[USERROLES] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_sids-XXXXXX");
file_arr[SIDS] = fdopen(mkstemp(temp), "w+");
file_path_arr[SIDS] = cil_strpool_add(temp);
strcpy(temp, "/tmp/cil_netifcons-XXXXXX");
file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+");
file_path_arr[NETIFCONS] = cil_strpool_add(temp);
policy_file = fopen("policy.conf", "w+");
cil_list_for_each(item, db->sidorder) {
fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name);
}
cil_list_for_each(item, db->classorder) {
struct cil_class *class = item->data;
struct cil_tree_node *node = class->datum.nodes->head->data;
fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name);
fprintf(file_arr[CLASSES], "class %s ", class->datum.name);
if (class->common != NULL) {
fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name);
}
if (node->cl_head != NULL) {
struct cil_tree_node *curr_perm = node->cl_head;
fprintf(file_arr[CLASSES], "{ ");
while (curr_perm != NULL) {
fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name);
curr_perm = curr_perm->next;
}
fprintf(file_arr[CLASSES], "}");
}
fprintf(file_arr[CLASSES], "\n");
}
if (db->catorder->head != NULL) {
cil_list_for_each(item, db->catorder) {
cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0);
}
}
if (db->sensitivityorder->head != NULL) {
fprintf(file_arr[SENS], "sensitivityorder { ");
cil_list_for_each(item, db->sensitivityorder) {
fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name);
}
fprintf(file_arr[SENS], "};\n");
}
extra_args.users = users;
extra_args.sens = sens;
extra_args.cats = cats;
extra_args.file_arr= file_arr;
rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error walking tree\n");
return rc;
}
rc = cil_netifcon_to_policy(file_arr, db->netifcon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_genfscon_to_policy(file_arr, db->genfscon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_portcon_to_policy(file_arr, db->portcon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_nodecon_to_policy(file_arr, db->nodecon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_fsuse_to_policy(file_arr, db->fsuse);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_pirqcon_to_policy(file_arr, db->pirqcon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_iomemcon_to_policy(file_arr, db->iomemcon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_ioportcon_to_policy(file_arr, db->ioportcon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return rc;
}
rc = cil_userrole_to_policy(file_arr, users);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return SEPOL_ERR;
}
rc = cil_sens_to_policy(file_arr, sens);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return SEPOL_ERR;
}
rc = cil_cat_to_policy(file_arr, cats);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return SEPOL_ERR;
}
rc = cil_combine_policy(file_arr, policy_file);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Error creating policy.conf\n");
return SEPOL_ERR;
}
// Remove temp files
int i;
for (i=0; i<NUM_POLICY_FILES; i++) {
rc = fclose(file_arr[i]);
if (rc != 0) {
cil_log(CIL_ERR, "Error closing temporary file\n");
return SEPOL_ERR;
}
rc = unlink(file_path_arr[i]);
if (rc != 0) {
cil_log(CIL_ERR, "Error unlinking temporary files\n");
return SEPOL_ERR;
}
}
rc = fclose(policy_file);
if (rc != 0) {
cil_log(CIL_ERR, "Error closing policy.conf\n");
return SEPOL_ERR;
}
free(file_arr);
cil_list_destroy(&users, CIL_FALSE);
cil_list_destroy(&cats, CIL_FALSE);
cil_list_destroy(&sens, CIL_FALSE);
return SEPOL_OK;
}