/** * @file * Implementation of the interface for searching and iterating over * policy MLS components. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2006-2007. 2015 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 #include #include #include #include #include #include "iterator_internal.h" #include #include "qpol_internal.h" /* level */ int qpol_policy_get_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_level_t ** datum) { policydb_t *db = NULL; hashtab_datum_t internal_datum = NULL; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name); if (internal_datum == NULL) { ERR(policy, "could not find datum for level %s", name); errno = EINVAL; *datum = NULL; return STATUS_ERR; } *datum = (qpol_level_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_level_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_levels.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_level_get_isalias(const qpol_policy_t * policy, const qpol_level_t * datum, unsigned char *isalias) { level_datum_t *internal_datum; if (policy == NULL || datum == NULL || isalias == NULL) { if (isalias != NULL) *isalias = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; *isalias = internal_datum->isalias; return STATUS_SUCCESS; } int qpol_level_get_value(const qpol_policy_t * policy, const qpol_level_t * datum, uint32_t * value) { level_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; *value = internal_datum->level->sens; return STATUS_SUCCESS; } int qpol_level_get_cat_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** cats) { level_datum_t *internal_datum = NULL; ebitmap_state_t *es = NULL; int error = 0; if (policy == NULL || datum == NULL || cats == NULL) { if (cats != NULL) *cats = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (level_datum_t *) datum; es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_datum->level->cat); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*cats); return STATUS_SUCCESS; } int qpol_level_get_name(const qpol_policy_t * policy, const qpol_level_t * datum, const char **name) { level_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (level_datum_t *) datum; *name = db->p_sens_val_to_name[internal_datum->level->sens - 1]; return STATUS_SUCCESS; } typedef struct level_alias_hash_state { unsigned int bucket; hashtab_node_t *node; hashtab_t *table; uint32_t val; } level_alias_hash_state_t; static int hash_state_next_level_alias(qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; level_datum_t *datum = NULL; if (iter == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } do { hash_state_next(iter); datum = hs->node ? (level_datum_t *) hs->node->datum : NULL; } while (datum != NULL && (datum->level->sens != hs->val || !datum->isalias)); return STATUS_SUCCESS; } static void *hash_state_get_cur_alias(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; if (iter == NULL) { errno = EINVAL; return NULL; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return NULL; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return NULL; } return hs->node->key; } static size_t hash_state_level_alias_size(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; hashtab_node_t *tmp_node; level_datum_t *tmp_lvl_datum; uint32_t tmp_bucket = 0; size_t count = 0; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (!hs) { errno = EINVAL; return STATUS_ERR; } for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { tmp_lvl_datum = tmp_node ? tmp_node->datum : NULL; if (tmp_lvl_datum) { if (tmp_lvl_datum->isalias && tmp_lvl_datum->level->sens == hs->val) count++; } } } return count; } int qpol_level_get_alias_iter(const qpol_policy_t * policy, const qpol_level_t * datum, qpol_iterator_t ** aliases) { level_datum_t *internal_datum = NULL; policydb_t *db = NULL; int error; level_alias_hash_state_t *hs = NULL; if (policy == NULL || datum == NULL || aliases == NULL) { if (aliases != NULL) *aliases = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (level_datum_t *) datum; hs = calloc(1, sizeof(level_alias_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_levels.table; hs->node = (*(hs->table))->htable[0]; hs->val = internal_datum->level->sens; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias, hash_state_next_level_alias, hash_state_end, hash_state_level_alias_size, free, aliases)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || !((level_datum_t *) hs->node->datum)->isalias || ((level_datum_t *) (hs->node->datum))->level->sens != hs->val) hash_state_next_level_alias(*aliases); return STATUS_SUCCESS; } /* cat */ int qpol_policy_get_cat_by_name(const qpol_policy_t * policy, const char *name, const qpol_cat_t ** datum) { hashtab_datum_t internal_datum; policydb_t *db; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)name); if (internal_datum == NULL) { *datum = NULL; ERR(policy, "could not find datum for cat %s", name); errno = EINVAL; return STATUS_ERR; } *datum = (qpol_cat_t *) internal_datum; return STATUS_SUCCESS; } int qpol_policy_get_cat_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policydb_t *db; int error = 0; hash_state_t *hs = NULL; if (policy == NULL || iter == NULL) { if (iter != NULL) *iter = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; hs = calloc(1, sizeof(hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_cats.table; hs->node = (*(hs->table))->htable[0]; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, hash_state_next, hash_state_end, hash_state_size, free, iter)) { free(hs); return STATUS_ERR; } if (hs->node == NULL) hash_state_next(*iter); return STATUS_SUCCESS; } int qpol_cat_get_value(const qpol_policy_t * policy, const qpol_cat_t * datum, uint32_t * value) { cat_datum_t *internal_datum = NULL; if (policy == NULL || datum == NULL || value == NULL) { if (value != NULL) *value = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cat_datum_t *) datum; *value = internal_datum->s.value; return STATUS_SUCCESS; } int qpol_cat_get_isalias(const qpol_policy_t * policy, const qpol_cat_t * datum, unsigned char *isalias) { cat_datum_t *internal_datum; if (policy == NULL || datum == NULL || isalias == NULL) { if (isalias != NULL) *isalias = 0; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_datum = (cat_datum_t *) datum; *isalias = internal_datum->isalias; return STATUS_SUCCESS; } int qpol_cat_get_name(const qpol_policy_t * policy, const qpol_cat_t * datum, const char **name) { cat_datum_t *internal_datum = NULL; policydb_t *db = NULL; if (policy == NULL || datum == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (cat_datum_t *) datum; *name = db->p_cat_val_to_name[internal_datum->s.value - 1]; return STATUS_SUCCESS; } static int hash_state_next_cat_alias(qpol_iterator_t * iter) { /* using level alias state datum since data needed is identical */ level_alias_hash_state_t *hs = NULL; cat_datum_t *datum = NULL; if (iter == NULL) { errno = EINVAL; return STATUS_ERR; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (hs == NULL) { errno = EINVAL; return STATUS_ERR; } if (hs->bucket >= (*(hs->table))->size) { errno = ERANGE; return STATUS_ERR; } do { hash_state_next(iter); datum = hs->node ? (cat_datum_t *) hs->node->datum : NULL; } while (datum != NULL && (datum->s.value != hs->val || !datum->isalias)); return STATUS_SUCCESS; } static size_t hash_state_cat_alias_size(const qpol_iterator_t * iter) { level_alias_hash_state_t *hs = NULL; hashtab_node_t *tmp_node; cat_datum_t *tmp_cat_datum; uint32_t tmp_bucket = 0; size_t count = 0; if (iter == NULL || qpol_iterator_state(iter) == NULL) { errno = EINVAL; return 0; } hs = (level_alias_hash_state_t *) qpol_iterator_state(iter); if (!hs) { errno = EINVAL; return STATUS_ERR; } for (tmp_bucket = 0; tmp_bucket < (*(hs->table))->size; tmp_bucket++) { for (tmp_node = (*(hs->table))->htable[tmp_bucket]; tmp_node; tmp_node = tmp_node->next) { tmp_cat_datum = tmp_node ? tmp_node->datum : NULL; if (tmp_cat_datum) { if (tmp_cat_datum->isalias && tmp_cat_datum->s.value == hs->val) count++; } } } return count; } int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * datum, qpol_iterator_t ** aliases) { cat_datum_t *internal_datum = NULL; policydb_t *db = NULL; int error; level_alias_hash_state_t *hs = NULL; if (policy == NULL || datum == NULL || aliases == NULL) { if (aliases != NULL) *aliases = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } db = &policy->p->p; internal_datum = (cat_datum_t *) datum; hs = calloc(1, sizeof(level_alias_hash_state_t)); if (hs == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } hs->table = &db->p_cats.table; hs->node = (*(hs->table))->htable[0]; hs->val = internal_datum->s.value; if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur_alias, hash_state_next_cat_alias, hash_state_end, hash_state_cat_alias_size, free, aliases)) { free(hs); return STATUS_ERR; } if (hs->node == NULL || ((cat_datum_t *) (hs->node->datum))->s.value != hs->val) hash_state_next_cat_alias(*aliases); return STATUS_SUCCESS; } /* mls range */ int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t *low, const qpol_mls_level_t *high, qpol_mls_range_t **dest) { mls_range_t *internal_range = NULL; mls_level_t *internal_low = NULL, *internal_high = NULL; if (policy == NULL || low == NULL || high == NULL || dest == NULL) { if (dest != NULL) *dest = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *dest = NULL; internal_low = (mls_level_t*)low; internal_high = (mls_level_t*)high; if (!mls_level_dom(internal_high, internal_low)) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = malloc(sizeof(mls_range_t)); if (!internal_range) { ERR(policy, "%s", strerror(errno)); return STATUS_ERR; } mls_range_init(internal_range); if (mls_level_cpy(&internal_range->level[0], internal_low) < 0) { goto err; } if (mls_level_cpy(&internal_range->level[1], internal_high) < 0) { goto err; } *dest = (qpol_mls_range_t*) internal_range; return STATUS_SUCCESS; err: mls_range_destroy(internal_range); free(internal_range); errno = ENOMEM; return STATUS_ERR; } int qpol_mls_range_get_low_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level) { mls_range_t *internal_range = NULL; if (policy == NULL || range == NULL || level == NULL) { if (level != NULL) *level = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = (mls_range_t *) range; *level = (qpol_mls_level_t *) & (internal_range->level[0]); return STATUS_SUCCESS; } int qpol_mls_range_get_high_level(const qpol_policy_t * policy, const qpol_mls_range_t * range, const qpol_mls_level_t ** level) { mls_range_t *internal_range = NULL; if (policy == NULL || range == NULL || level == NULL) { if (level != NULL) *level = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_range = (mls_range_t *) range; *level = (qpol_mls_level_t *) & (internal_range->level[1]); return STATUS_SUCCESS; } /* mls_level */ int qpol_mls_level_get_sens_name(const qpol_policy_t * policy, const qpol_mls_level_t * level, const char **name) { policydb_t *db = NULL; mls_level_t *internal_level = NULL; if (policy == NULL || level == NULL || name == NULL) { if (name != NULL) *name = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_level = (mls_level_t *) level; db = &policy->p->p; *name = db->p_sens_val_to_name[internal_level->sens - 1]; return STATUS_SUCCESS; } int qpol_mls_level_get_cat_iter(const qpol_policy_t * policy, const qpol_mls_level_t * level, qpol_iterator_t ** cats) { mls_level_t *internal_level = NULL; ebitmap_state_t *es = NULL; int error = 0; if (policy == NULL || level == NULL || cats == NULL) { if (cats != NULL) *cats = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_level = (mls_level_t *) level; es = calloc(1, sizeof(ebitmap_state_t)); if (es == NULL) { error = errno; ERR(policy, "%s", strerror(ENOMEM)); errno = error; return STATUS_ERR; } es->bmap = &(internal_level->cat); es->cur = es->bmap->node ? es->bmap->node->startbit : 0; if (qpol_iterator_create(policy, es, ebitmap_state_get_cur_cat, ebitmap_state_next, ebitmap_state_end, ebitmap_state_size, free, cats)) { free(es); return STATUS_ERR; } if (es->bmap->node && !ebitmap_get_bit(es->bmap, es->cur)) ebitmap_state_next(*cats); return STATUS_SUCCESS; } int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, const qpol_semantic_level_t * src, qpol_mls_level_t **dest) { policydb_t *db = NULL; mls_semantic_level_t *internal_semantic = NULL; mls_level_t *internal_level = NULL; if (policy == NULL || src == NULL || dest == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; *dest = NULL; return STATUS_ERR; } internal_semantic = (mls_semantic_level_t*) src; db = &policy->p->p; internal_level = malloc(sizeof(mls_level_t)); if (!internal_level) { return STATUS_ERR; } mls_level_init(internal_level); if(mls_semantic_level_expand(internal_semantic, internal_level, db, policy->sh) < 0) { mls_level_destroy(internal_level); free(internal_level); errno = EINVAL; *dest = NULL; return STATUS_ERR; } *dest = (qpol_mls_level_t*) internal_level; return STATUS_SUCCESS; } /* semantic level */ int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_semantic_level_t ** datum) { policydb_t *db = NULL; hashtab_datum_t internal_datum = NULL; mls_semantic_level_t *internal_semantic = NULL; if (policy == NULL || name == NULL || datum == NULL) { if (datum != NULL) *datum = NULL; ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_semantic = malloc(sizeof(mls_semantic_level_t)); if (!internal_semantic) { return STATUS_ERR; } mls_semantic_level_init(internal_semantic); db = &policy->p->p; internal_datum = hashtab_search(db->p_levels.table, (hashtab_key_t)name); if (internal_datum == NULL) { mls_semantic_level_destroy(internal_semantic); free(internal_semantic); *datum = NULL; ERR(policy, "could not find datum for level %s", name); errno = ENOENT; return STATUS_ERR; } internal_semantic->sens = ((level_datum_t*)internal_datum)->level->sens; *datum = (qpol_semantic_level_t *) internal_semantic; return STATUS_SUCCESS; } int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high) { hashtab_datum_t internal_datum; policydb_t *db = NULL; mls_semantic_level_t *internal_level = NULL; mls_semantic_cat_t *internal_cat = NULL; if (policy == NULL || level == NULL || low == NULL || high == NULL) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_cat = malloc(sizeof(mls_semantic_cat_t)); if (!internal_cat) { return STATUS_ERR; } mls_semantic_cat_init(internal_cat); db = &policy->p->p; internal_level = (mls_semantic_level_t*) level; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)low); if (internal_datum == NULL) { ERR(policy, "could not find datum for cat %s", low); goto err; } internal_cat->low = ((cat_datum_t*)internal_datum)->s.value; internal_datum = hashtab_search(db->p_cats.table, (hashtab_key_t)high); if (internal_datum == NULL) { ERR(policy, "could not find datum for cat %s", high); goto err; } internal_cat->high = ((cat_datum_t*)internal_datum)->s.value; if (internal_cat->low > internal_cat->high) { ERR(policy, "invalid semantic category range: %s.%s", low, high); goto err; } if (!(internal_level->cat)) { internal_level->cat = internal_cat; } else { mls_semantic_cat_t *curr = internal_level->cat; while(curr->next) { curr = curr->next; } curr->next = internal_cat; } return STATUS_SUCCESS; err: mls_semantic_cat_destroy(internal_cat); free(internal_cat); errno = ENOENT; return STATUS_ERR; } void qpol_semantic_level_destroy(qpol_semantic_level_t * level) { if (level == NULL) { return; } mls_semantic_level_destroy((mls_semantic_level_t*) level); free(level); }