diff options
Diffstat (limited to 'libqpol/src/syn_rule_query.c')
-rw-r--r-- | libqpol/src/syn_rule_query.c | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/libqpol/src/syn_rule_query.c b/libqpol/src/syn_rule_query.c new file mode 100644 index 0000000..3e63204 --- /dev/null +++ b/libqpol/src/syn_rule_query.c @@ -0,0 +1,782 @@ +/** + * @file + * Public interface for querying syntactic rules from the extended + * policy image. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <qpol/syn_rule_query.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/util.h> +#include <sepol/policydb/conditional.h> +#include "qpol_internal.h" +#include "iterator_internal.h" +#include "syn_rule_internal.h" +#include <errno.h> +#include <stdlib.h> + +typedef struct syn_rule_class_state +{ + class_perm_node_t *head; + class_perm_node_t *cur; +} syn_rule_class_state_t; + +static int syn_rule_class_state_end(const qpol_iterator_t * iter) +{ + syn_rule_class_state_t *srcs = NULL; + + if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + if (srcs->cur == NULL) + return 1; + else + return 0; +} + +static void *syn_rule_class_state_get_cur(const qpol_iterator_t * iter) +{ + syn_rule_class_state_t *srcs = NULL; + const policydb_t *db = NULL; + + if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter)) || + !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { + errno = EINVAL; + return NULL; + } + + return db->class_val_to_struct[srcs->cur->class - 1]; +} + +static int syn_rule_class_state_next(qpol_iterator_t * iter) +{ + syn_rule_class_state_t *srcs = NULL; + + if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + if (qpol_iterator_end(iter)) { + errno = ERANGE; + return STATUS_ERR; + } + + srcs->cur = srcs->cur->next; + + return STATUS_SUCCESS; +} + +static size_t syn_rule_class_state_size(const qpol_iterator_t * iter) +{ + syn_rule_class_state_t *srcs = NULL; + size_t count = 0; + class_perm_node_t *cpn = NULL; + + if (!iter || !(srcs = (syn_rule_class_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return 0; + } + + for (cpn = srcs->head; cpn; cpn = cpn->next) + count++; + + return count; +} + +typedef struct syn_rule_perm_state +{ + char **perm_list; + size_t perm_list_sz; + size_t cur; +} syn_rule_perm_state_t; + +static int syn_rule_perm_state_end(const qpol_iterator_t * iter) +{ + syn_rule_perm_state_t *srps = NULL; + + if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + return (srps->cur >= srps->perm_list_sz ? 1 : 0); +} + +static void *syn_rule_perm_state_get_cur(const qpol_iterator_t * iter) +{ + syn_rule_perm_state_t *srps = NULL; + + if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { + errno = EINVAL; + return NULL; + } + + return srps->perm_list[srps->cur]; +} + +static int syn_rule_perm_state_next(qpol_iterator_t * iter) +{ + syn_rule_perm_state_t *srps = NULL; + + if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + if (qpol_iterator_end(iter)) { + errno = ERANGE; + return STATUS_ERR; + } + + srps->cur++; + + return STATUS_SUCCESS; +} + +static size_t syn_rule_perm_state_size(const qpol_iterator_t * iter) +{ + syn_rule_perm_state_t *srps = NULL; + + if (!iter || !(srps = (syn_rule_perm_state_t *) qpol_iterator_state(iter))) { + errno = EINVAL; + return STATUS_ERR; + } + + return srps->perm_list_sz; +} + +static void syn_rule_perm_state_free(void *state) +{ + size_t i; + + syn_rule_perm_state_t *srps = (syn_rule_perm_state_t *) state; + + if (!srps) + return; + + for (i = 0; i < srps->perm_list_sz; i++) + free(srps->perm_list[i]); + free(srps->perm_list); + free(srps); +} + +/***************************** type set functions ****************************/ + +int qpol_type_set_get_included_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter) +{ + type_set_t *internal_ts = NULL; + ebitmap_state_t *es = NULL; + int error = 0; + + if (iter) + *iter = NULL; + + if (!policy || !ts || !iter) { + ERR(policy, "%s", strerror(EINVAL)); + error = EINVAL; + return STATUS_ERR; + } + + internal_ts = (type_set_t *) ts; + + es = calloc(1, sizeof(ebitmap_state_t)); + if (!es) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return STATUS_ERR; + } + + es->bmap = &(internal_ts->types); + es->cur = es->bmap->node ? es->bmap->node->startbit : 0; + + if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type, + ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) { + free(es); + return STATUS_ERR; + } + + if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) + ebitmap_state_next(*iter); + + return STATUS_SUCCESS; +} + +int qpol_type_set_get_subtracted_types_iter(const qpol_policy_t * policy, const qpol_type_set_t * ts, qpol_iterator_t ** iter) +{ + type_set_t *internal_ts = NULL; + ebitmap_state_t *es = NULL; + int error = 0; + + if (iter) + *iter = NULL; + + if (!policy || !ts || !iter) { + ERR(policy, "%s", strerror(EINVAL)); + error = EINVAL; + return STATUS_ERR; + } + + internal_ts = (type_set_t *) ts; + + es = calloc(1, sizeof(ebitmap_state_t)); + if (!es) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return STATUS_ERR; + } + + es->bmap = &(internal_ts->negset); + es->cur = es->bmap->node ? es->bmap->node->startbit : 0; + + if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_type, + ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, iter)) { + free(es); + return STATUS_ERR; + } + + if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) + ebitmap_state_next(*iter); + + return STATUS_SUCCESS; +} + +int qpol_type_set_get_is_star(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_star) +{ + type_set_t *internal_ts = NULL; + + if (is_star) + *is_star = 0; + + if (!policy || !ts || !is_star) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_ts = (type_set_t *) ts; + + if (internal_ts->flags == TYPE_STAR) + *is_star = 1; + + return STATUS_SUCCESS; +} + +int qpol_type_set_get_is_comp(const qpol_policy_t * policy, const qpol_type_set_t * ts, uint32_t * is_comp) +{ + type_set_t *internal_ts = NULL; + + if (is_comp) + *is_comp = 0; + + if (!policy || !ts || !is_comp) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_ts = (type_set_t *) ts; + + if (internal_ts->flags == TYPE_COMP) + *is_comp = 1; + + return STATUS_SUCCESS; +} + +/***************************** syn_avule functions ****************************/ + +int qpol_syn_avrule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * rule_type) +{ + avrule_t *internal_rule = NULL; + + if (rule_type) + *rule_type = 0; + + if (!policy || !rule || !rule_type) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + if (internal_rule->specified == AVRULE_DONTAUDIT) + *rule_type = QPOL_RULE_DONTAUDIT; + else + *rule_type = internal_rule->specified; + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, + const qpol_type_set_t ** source_set) +{ + avrule_t *internal_rule = NULL; + + if (source_set) + *source_set = NULL; + + if (!policy || !rule || !source_set) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *source_set = (qpol_type_set_t *) (&internal_rule->stypes); + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, + const qpol_type_set_t ** target_set) +{ + avrule_t *internal_rule = NULL; + + if (target_set) + *target_set = NULL; + + if (!policy || !rule || !target_set) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *target_set = (qpol_type_set_t *) (&internal_rule->ttypes); + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_is_target_self(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_self) +{ + avrule_t *internal_rule = NULL; + + if (is_self) + *is_self = 0; + + if (!policy || !rule || !is_self) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + if (internal_rule->flags & RULE_SELF) + *is_self = 1; + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** classes) +{ + syn_rule_class_state_t *srcs = NULL; + avrule_t *internal_rule = NULL; + int error = 0; + + if (classes) + *classes = NULL; + + if (!policy || !rule || !classes) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + if (!(srcs = calloc(1, sizeof(syn_rule_class_state_t)))) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + srcs->head = srcs->cur = internal_rule->perms; + + if (qpol_iterator_create(policy, (void *)srcs, + syn_rule_class_state_get_cur, syn_rule_class_state_next, + syn_rule_class_state_end, syn_rule_class_state_size, free, classes)) { + error = errno; + ERR(policy, "%s", strerror(error)); + free(srcs); + errno = error; + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_perm_iter(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, qpol_iterator_t ** perms) +{ + avrule_t *internal_rule = NULL; + policydb_t *db = NULL; + char **perm_list, *tmp = NULL, **tmp_copy = NULL; + class_perm_node_t *node = NULL; + size_t node_num = 0, i, cur, perm_list_sz = 0; + int error = 0; + syn_rule_perm_state_t *srps = NULL; + + if (perms) + *perms = NULL; + + if (!policy || !rule || !perms) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + for (node = internal_rule->perms; node; node = node->next) + node_num++; + + /* for now allocate space for maximum number of unique perms */ + perm_list = calloc(node_num * 32, sizeof(char *)); + if (!perm_list) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return STATUS_ERR; + } + + for (node = internal_rule->perms; node; node = node->next) { + for (i = 0; i < db->class_val_to_struct[node->class - 1]->permissions.nprim; i++) { + if (!(node->data & (1 << i))) + continue; + tmp = sepol_av_to_string(db, node->class, (sepol_access_vector_t) (1 << i)); + if (tmp) { + tmp++; /* remove prepended space */ + for (cur = 0; cur < perm_list_sz; cur++) + if (!strcmp(tmp, perm_list[cur])) + break; + if (cur < perm_list_sz) + continue; + perm_list[perm_list_sz] = strdup(tmp); + if (!(perm_list[perm_list_sz])) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + perm_list_sz++; + } else { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + } + } + + /* shrink to actual needed size */ + tmp_copy = realloc(perm_list, perm_list_sz * sizeof(char *)); + if (!tmp_copy) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + perm_list = tmp_copy; + + srps = calloc(1, sizeof(syn_rule_perm_state_t)); + if (!srps) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + srps->perm_list = perm_list; + srps->perm_list_sz = perm_list_sz; + srps->cur = 0; + + if (qpol_iterator_create(policy, (void *)srps, + syn_rule_perm_state_get_cur, syn_rule_perm_state_next, + syn_rule_perm_state_end, syn_rule_perm_state_size, syn_rule_perm_state_free, perms)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto err; + } + + return STATUS_SUCCESS; + + err: + for (i = 0; i < perm_list_sz; i++) + free(perm_list[i]); + free(perm_list); + errno = error; + return STATUS_ERR; +} + +int qpol_syn_avrule_get_lineno(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, unsigned long *lineno) +{ + avrule_t *internal_rule = NULL; + + if (lineno) + *lineno = 0; + + if (!policy || !rule || !lineno) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *lineno = internal_rule->line; + + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_cond(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, const qpol_cond_t ** cond) +{ + if (cond) + *cond = NULL; + + if (!policy || !rule || !cond) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + *cond = (qpol_cond_t *) ((struct qpol_syn_rule *)rule)->cond; + return STATUS_SUCCESS; +} + +int qpol_syn_avrule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_avrule_t * rule, uint32_t * is_enabled) +{ + int truth; + if (is_enabled) + *is_enabled = 0; + + if (!policy || !rule || !is_enabled) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + if (!((struct qpol_syn_rule *)rule)->cond) + *is_enabled = 1; + else { + truth = cond_evaluate_expr(&policy->p->p, ((struct qpol_syn_rule *)rule)->cond->expr); + if (truth < 0) { + ERR(policy, "%s", strerror(ERANGE)); + errno = ERANGE; + return STATUS_ERR; + } + if (!((struct qpol_syn_rule *)rule)->cond_branch) + *is_enabled = truth; + else + *is_enabled = truth ? 0 : 1; + } + return STATUS_SUCCESS; +} + +/***************************** syn_terule functions ****************************/ + +int qpol_syn_terule_get_rule_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * rule_type) +{ + avrule_t *internal_rule = NULL; + + if (rule_type) + *rule_type = 0; + + if (!policy || !rule || !rule_type) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *rule_type = internal_rule->specified; + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_source_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, + const qpol_type_set_t ** source_set) +{ + avrule_t *internal_rule = NULL; + + if (source_set) + *source_set = NULL; + + if (!policy || !rule || !source_set) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *source_set = (qpol_type_set_t *) (&internal_rule->stypes); + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_target_type_set(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, + const qpol_type_set_t ** target_set) +{ + avrule_t *internal_rule = NULL; + + if (target_set) + *target_set = NULL; + + if (!policy || !rule || !target_set) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *target_set = (qpol_type_set_t *) (&internal_rule->ttypes); + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_class_iter(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, qpol_iterator_t ** classes) +{ + syn_rule_class_state_t *srcs = NULL; + avrule_t *internal_rule = NULL; + int error = 0; + + if (classes) + *classes = NULL; + + if (!policy || !rule || !classes) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + if (!(srcs = calloc(1, sizeof(syn_rule_class_state_t)))) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + srcs->head = srcs->cur = internal_rule->perms; + + if (qpol_iterator_create(policy, (void *)srcs, + syn_rule_class_state_get_cur, syn_rule_class_state_next, + syn_rule_class_state_end, syn_rule_class_state_size, free, classes)) { + error = errno; + ERR(policy, "%s", strerror(error)); + free(srcs); + errno = error; + return STATUS_ERR; + } + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_default_type(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_type_t ** dflt) +{ + avrule_t *internal_rule = NULL; + policydb_t *db = NULL; + + if (dflt) + *dflt = 0; + + if (!policy || !rule || !dflt) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + db = &policy->p->p; + + /* since it is required that default be the same for all classes just return the first */ + *dflt = (qpol_type_t *) (db->type_val_to_struct[internal_rule->perms->data - 1]); + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_lineno(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, unsigned long *lineno) +{ + avrule_t *internal_rule = NULL; + + if (lineno) + *lineno = 0; + + if (!policy || !rule || !lineno) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + internal_rule = ((struct qpol_syn_rule *)rule)->rule; + + *lineno = internal_rule->line; + + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_cond(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, const qpol_cond_t ** cond) +{ + if (cond) + *cond = NULL; + + if (!policy || !rule || !cond) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + *cond = (qpol_cond_t *) ((struct qpol_syn_rule *)rule)->cond; + return STATUS_SUCCESS; +} + +int qpol_syn_terule_get_is_enabled(const qpol_policy_t * policy, const qpol_syn_terule_t * rule, uint32_t * is_enabled) +{ + int truth; + if (is_enabled) + *is_enabled = 0; + + if (!policy || !rule || !is_enabled) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + if (!((struct qpol_syn_rule *)rule)->cond) + *is_enabled = 1; + else { + truth = cond_evaluate_expr(&policy->p->p, ((struct qpol_syn_rule *)rule)->cond->expr); + if (truth < 0) { + ERR(policy, "%s", strerror(ERANGE)); + errno = ERANGE; + return STATUS_ERR; + } + if (!((struct qpol_syn_rule *)rule)->cond_branch) + *is_enabled = truth; + else + *is_enabled = truth ? 0 : 1; + } + return STATUS_SUCCESS; +} |