/** * @file * Implementation of the public interface for searching and iterating over * constraints * * @author Kevin Carr kcarr@tresys.com * @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 #include #include #include #include #include "qpol_internal.h" #include "iterator_internal.h" #include #include #include #include #include struct qpol_constraint { const qpol_class_t *obj_class; constraint_node_t *constr; }; typedef struct policy_constr_state { qpol_iterator_t *class_iter; qpol_iterator_t *constr_iter; const qpol_policy_t *policy; /* needed to get sub iterators */ } policy_constr_state_t; static int policy_constr_state_end(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return (qpol_iterator_end(pcs->class_iter) && qpol_iterator_end(pcs->constr_iter)) ? 1 : 0; } static void *policy_constr_state_get_cur(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; void *tmp = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } if (qpol_iterator_get_item(pcs->constr_iter, &tmp)) { return NULL; } return tmp; } static int policy_constr_state_next(qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } qpol_iterator_next(pcs->constr_iter); while (qpol_iterator_end(pcs->constr_iter)) { qpol_iterator_destroy(&pcs->constr_iter); qpol_iterator_next(pcs->class_iter); if (qpol_iterator_end(pcs->class_iter)) return STATUS_SUCCESS; if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class)) return STATUS_ERR; if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &pcs->constr_iter)) return STATUS_ERR; } return STATUS_SUCCESS; } static size_t policy_constr_state_size(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL; size_t count = 0, tmp = 0; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } if (qpol_policy_get_class_iter(pcs->policy, &internal_iter)) return 0; for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) { if (qpol_iterator_get_item(internal_iter, (void **)&obj_class)) goto err; if (qpol_class_get_constraint_iter(pcs->policy, obj_class, &constr_iter)) goto err; if (qpol_iterator_get_size(constr_iter, &tmp)) goto err; count += tmp; tmp = 0; qpol_iterator_destroy(&constr_iter); } qpol_iterator_destroy(&internal_iter); return count; err: qpol_iterator_destroy(&internal_iter); qpol_iterator_destroy(&constr_iter); return 0; } static void policy_constr_state_free(void *x) { policy_constr_state_t *pcs = (policy_constr_state_t *) x; if (!pcs) return; qpol_iterator_destroy(&pcs->class_iter); qpol_iterator_destroy(&pcs->constr_iter); free(pcs); } int qpol_policy_get_constraint_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policy_constr_state_t *pcs = NULL; int error = 0; qpol_class_t *tmp = NULL; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } pcs->policy = policy; if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) { error = errno; goto err; } if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) { error = errno; ERR(policy, "Error getting first class: %s", strerror(error)); goto err; } if (qpol_class_get_constraint_iter(policy, tmp, &pcs->constr_iter)) { error = errno; goto err; } if (qpol_iterator_create(policy, (void *)pcs, policy_constr_state_get_cur, policy_constr_state_next, policy_constr_state_end, policy_constr_state_size, policy_constr_state_free, iter)) { error = errno; goto err; } if (qpol_iterator_end(pcs->constr_iter)) { if (qpol_iterator_next(*iter)) { error = errno; pcs = NULL; /* avoid double free, iterator will destroy this */ ERR(policy, "Error finding first constraint: %s", strerror(error)); goto err; } } return STATUS_SUCCESS; err: policy_constr_state_free(pcs); qpol_iterator_destroy(iter); errno = error; return STATUS_ERR; } int qpol_constraint_get_class(const qpol_policy_t * policy, const qpol_constraint_t * constr, const qpol_class_t ** obj_class) { if (obj_class) *obj_class = NULL; if (!policy || !constr || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *obj_class = constr->obj_class; return STATUS_SUCCESS; } int qpol_constraint_get_perm_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter) { perm_state_t *ps = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !constr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) constr->constr; if (!(ps = calloc(1, sizeof(perm_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; } ps->perm_set = internal_constr->permissions; qpol_class_get_value(policy, constr->obj_class, &ps->obj_class_val); if (qpol_iterator_create(policy, (void *)ps, perm_state_get_cur, perm_state_next, perm_state_end, perm_state_size, free, iter)) { free(ps); return STATUS_ERR; } if (!(ps->perm_set & 1)) /* defaults to bit 0 */ qpol_iterator_next(*iter); return STATUS_SUCCESS; } typedef struct constr_expr_state { constraint_expr_t *head; constraint_expr_t *cur; } constr_expr_state_t; static int constr_expr_state_end(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ces->cur ? 0 : 1; } static void *constr_expr_state_get_cur(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return ces->cur; } static int constr_expr_state_next(qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ces->cur = ces->cur->next; return STATUS_SUCCESS; } static size_t constr_expr_state_size(const qpol_iterator_t * iter) { constr_expr_state_t *ces = NULL; constraint_expr_t *tmp = NULL; size_t count = 0; if (!iter || !(ces = (constr_expr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } for (tmp = ces->head; tmp; tmp = tmp->next) count++; return count; } int qpol_constraint_get_expr_iter(const qpol_policy_t * policy, const qpol_constraint_t * constr, qpol_iterator_t ** iter) { constr_expr_state_t *ces = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !constr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) constr->constr; if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } ces->head = ces->cur = internal_constr->expr; if (qpol_iterator_create(policy, (void *)ces, constr_expr_state_get_cur, constr_expr_state_next, constr_expr_state_end, constr_expr_state_size, free, iter)) { free(ces); return STATUS_ERR; } return STATUS_SUCCESS; } static int policy_constr_state_next_vtrans(qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } qpol_iterator_next(pcs->constr_iter); while (qpol_iterator_end(pcs->constr_iter)) { qpol_iterator_destroy(&pcs->constr_iter); qpol_iterator_next(pcs->class_iter); if (qpol_iterator_end(pcs->class_iter)) return STATUS_SUCCESS; if (qpol_iterator_get_item(pcs->class_iter, (void **)&obj_class)) return STATUS_ERR; if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &pcs->constr_iter)) return STATUS_ERR; } return STATUS_SUCCESS; } static size_t policy_constr_state_size_vtrans(const qpol_iterator_t * iter) { policy_constr_state_t *pcs = NULL; qpol_class_t *obj_class = NULL; qpol_iterator_t *internal_iter = NULL, *constr_iter = NULL; size_t count = 0, tmp = 0; if (!iter || !(pcs = (policy_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } if (qpol_policy_get_class_iter(pcs->policy, &internal_iter)) return 0; for (; !qpol_iterator_end(internal_iter); qpol_iterator_next(internal_iter)) { if (qpol_iterator_get_item(internal_iter, (void **)&obj_class)) goto err; if (qpol_class_get_validatetrans_iter(pcs->policy, obj_class, &constr_iter)) goto err; if (qpol_iterator_get_size(constr_iter, &tmp)) goto err; count += tmp; tmp = 0; qpol_iterator_destroy(&constr_iter); } qpol_iterator_destroy(&internal_iter); return count; err: qpol_iterator_destroy(&internal_iter); qpol_iterator_destroy(&constr_iter); return 0; } int qpol_policy_get_validatetrans_iter(const qpol_policy_t * policy, qpol_iterator_t ** iter) { policy_constr_state_t *pcs = NULL; int error = 0; qpol_class_t *tmp = NULL; if (iter) *iter = NULL; if (!policy || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(pcs = calloc(1, sizeof(policy_constr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } pcs->policy = policy; if (qpol_policy_get_class_iter(policy, &pcs->class_iter)) { error = errno; goto err; } if (qpol_iterator_get_item(pcs->class_iter, (void **)&tmp)) { error = errno; ERR(policy, "Error getting first class: %s", strerror(error)); goto err; } if (qpol_class_get_validatetrans_iter(policy, tmp, &pcs->constr_iter)) { error = errno; goto err; } if (qpol_iterator_create(policy, (void *)pcs, policy_constr_state_get_cur, policy_constr_state_next_vtrans, policy_constr_state_end, policy_constr_state_size_vtrans, policy_constr_state_free, iter)) { error = errno; goto err; } if (qpol_iterator_end(pcs->constr_iter)) { if (qpol_iterator_next(*iter)) { error = errno; pcs = NULL; /* avoid double free, iterator will destroy this */ ERR(policy, "Error finding first validatetrans: %s", strerror(error)); goto err; } } return STATUS_SUCCESS; err: policy_constr_state_free(pcs); qpol_iterator_destroy(iter); errno = error; return STATUS_ERR; } int qpol_validatetrans_get_class(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, const qpol_class_t ** obj_class) { if (obj_class) *obj_class = NULL; if (!policy || !vtrans || !obj_class) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } *obj_class = ((qpol_constraint_t *) vtrans)->obj_class; return STATUS_SUCCESS; } int qpol_validatetrans_get_expr_iter(const qpol_policy_t * policy, const qpol_validatetrans_t * vtrans, qpol_iterator_t ** iter) { constr_expr_state_t *ces = NULL; constraint_node_t *internal_constr = NULL; if (iter) *iter = NULL; if (!policy || !vtrans || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_constr = (constraint_node_t *) ((qpol_constraint_t *) vtrans)->constr; if (!(ces = calloc(1, sizeof(constr_expr_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } ces->head = ces->cur = internal_constr->expr; if (qpol_iterator_create(policy, (void *)ces, constr_expr_state_get_cur, constr_expr_state_next, constr_expr_state_end, constr_expr_state_size, free, iter)) { free(ces); return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_expr_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * expr_type) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !expr_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *expr_type = internal_expr->expr_type; return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_sym_type(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * sym_type) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !sym_type) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *sym_type = internal_expr->attr; return STATUS_SUCCESS; } int qpol_constraint_expr_node_get_op(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, uint32_t * op) { constraint_expr_t *internal_expr = NULL; if (!policy || !expr || !op) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_expr = (constraint_expr_t *) expr; *op = internal_expr->op; return STATUS_SUCCESS; } typedef struct cexpr_name_state { ebitmap_t *inc; ebitmap_t *sub; size_t cur; #define QPOL_CEXPR_NAME_STATE_INC_LIST 0 #define QPOL_CEXPR_NAME_STATE_SUB_LIST 1 unsigned char list; } cexpr_name_state_t; static int cexpr_name_state_end(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (cns->list == QPOL_CEXPR_NAME_STATE_SUB_LIST && (cns->sub ? cns->cur >= cns->sub->highbit : 1)) return 1; return 0; } static int cexpr_name_state_next(qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; ebitmap_t *bmap = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } bmap = (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST ? cns->inc : cns->sub); do { cns->cur++; if (cns->cur >= bmap->highbit) { if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST) { cns->list = QPOL_CEXPR_NAME_STATE_SUB_LIST; cns->cur = 0; bmap = cns->sub; if (!bmap) break; } else { break; } } } while (!ebitmap_get_bit(bmap, cns->cur)); return STATUS_SUCCESS; } static size_t cexpr_name_state_size(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; size_t count = 0, bit = 0; ebitmap_node_t *node = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return 0; } ebitmap_for_each_bit(cns->inc, node, bit) { count += ebitmap_get_bit(cns->inc, bit); } if (!(cns->sub)) return count; bit = 0; ebitmap_for_each_bit(cns->sub, node, bit) { count += ebitmap_get_bit(cns->sub, bit); } return count; } static void *cexpr_name_state_get_cur_user(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return strdup(db->p_user_val_to_name[cns->cur]); } static void *cexpr_name_state_get_cur_role(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } return strdup(db->p_role_val_to_name[cns->cur]); } static void *cexpr_name_state_get_cur_type(const qpol_iterator_t * iter) { cexpr_name_state_t *cns = NULL; const policydb_t *db = NULL; char *tmp = NULL, *name = NULL; size_t len = 0; if (!iter || !(cns = (cexpr_name_state_t *) qpol_iterator_state(iter)) || !(db = qpol_iterator_policy(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } tmp = strdup(db->p_type_val_to_name[cns->cur]); if (cns->list == QPOL_CEXPR_NAME_STATE_INC_LIST) return tmp; len = strlen(tmp); name = calloc(len + 2, sizeof(char)); if (!name) { free(tmp); errno = ENOMEM; return NULL; } len++; snprintf(name, len + 1, "-%s", tmp); free(tmp); return name; } int qpol_constraint_expr_node_get_names_iter(const qpol_policy_t * policy, const qpol_constraint_expr_node_t * expr, qpol_iterator_t ** iter) { constraint_expr_t *internal_expr = NULL; cexpr_name_state_t *cns = NULL; int policy_type = 0; if (iter) *iter = NULL; if (!policy || !expr || !iter) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (qpol_policy_get_type(policy, &policy_type)) return STATUS_ERR; internal_expr = (constraint_expr_t *) expr; if (internal_expr->expr_type != QPOL_CEXPR_TYPE_NAMES) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } if (!(cns = calloc(1, sizeof(cexpr_name_state_t)))) { ERR(policy, "%s", strerror(ENOMEM)); errno = ENOMEM; return STATUS_ERR; } unsigned int policy_version; if (qpol_policy_get_policy_version(policy, &policy_version)) return STATUS_ERR; if (internal_expr->attr & QPOL_CEXPR_SYM_TYPE) { if (policy_type == QPOL_POLICY_KERNEL_BINARY && policy_version <= 28) { cns->inc = &(internal_expr->names); } else if (policy_type == QPOL_POLICY_KERNEL_BINARY && policy_version > 28) { cns->inc = &(internal_expr->type_names->types); } else { cns->inc = &(internal_expr->type_names->types); cns->sub = &(internal_expr->type_names->negset); } } else { cns->inc = &(internal_expr->names); } cns->list = QPOL_CEXPR_NAME_STATE_INC_LIST; cns->cur = cns->inc->node ? cns->inc->node->startbit : 0; switch (internal_expr->attr & ~(QPOL_CEXPR_SYM_TARGET | QPOL_CEXPR_SYM_XTARGET)) { case QPOL_CEXPR_SYM_USER: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_user, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } case QPOL_CEXPR_SYM_ROLE: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_role, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } case QPOL_CEXPR_SYM_TYPE: { if (qpol_iterator_create(policy, (void *)cns, cexpr_name_state_get_cur_type, cexpr_name_state_next, cexpr_name_state_end, cexpr_name_state_size, free, iter)) { return STATUS_ERR; } break; } default: { ERR(policy, "%s", strerror(EINVAL)); free(cns); errno = EINVAL; return STATUS_ERR; } } if (cns->inc->node && !ebitmap_get_bit(cns->inc, cns->cur)) qpol_iterator_next(*iter); return STATUS_SUCCESS; } typedef struct class_constr_state { constraint_node_t *head; constraint_node_t *cur; const qpol_class_t *obj_class; } class_constr_state_t; static int class_constr_state_end(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } return ccs->cur ? 0 : 1; } static void *class_constr_state_get_cur(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; qpol_constraint_t *qc = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return NULL; } if (!(qc = calloc(1, sizeof(qpol_constraint_t)))) { return NULL; /* errno set by calloc */ } qc->obj_class = ccs->obj_class; qc->constr = ccs->cur; return qc; } static int class_constr_state_next(qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter))) { errno = EINVAL; return STATUS_ERR; } if (qpol_iterator_end(iter)) { errno = ERANGE; return STATUS_ERR; } ccs->cur = ccs->cur->next; return STATUS_SUCCESS; } static size_t class_constr_state_size(const qpol_iterator_t * iter) { class_constr_state_t *ccs = NULL; constraint_node_t *tmp = NULL; size_t count = 0; if (!iter || !(ccs = (class_constr_state_t *) qpol_iterator_state(iter)) || qpol_iterator_end(iter)) { errno = EINVAL; return 0; } for (tmp = ccs->head; tmp; tmp = tmp->next) count++; return count; } int qpol_class_get_constraint_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** constr) { class_constr_state_t *ccs = NULL; class_datum_t *internal_class = NULL; int error = 0; if (constr) *constr = NULL; if (!policy || !obj_class || !constr) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_class = (class_datum_t *) obj_class; ccs = calloc(1, sizeof(class_constr_state_t)); if (!ccs) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } ccs->obj_class = obj_class; ccs->head = ccs->cur = internal_class->constraints; if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur, class_constr_state_next, class_constr_state_end, class_constr_state_size, free, constr)) { return STATUS_ERR; } return STATUS_SUCCESS; } int qpol_class_get_validatetrans_iter(const qpol_policy_t * policy, const qpol_class_t * obj_class, qpol_iterator_t ** vtrans) { class_constr_state_t *ccs = NULL; class_datum_t *internal_class = NULL; int error = 0; if (vtrans) *vtrans = NULL; if (!policy || !obj_class || !vtrans) { ERR(policy, "%s", strerror(EINVAL)); errno = EINVAL; return STATUS_ERR; } internal_class = (class_datum_t *) obj_class; ccs = calloc(1, sizeof(class_constr_state_t)); if (!ccs) { error = errno; ERR(policy, "%s", strerror(error)); errno = error; return STATUS_ERR; } ccs->obj_class = obj_class; ccs->head = ccs->cur = internal_class->validatetrans; if (qpol_iterator_create(policy, (void *)ccs, class_constr_state_get_cur, class_constr_state_next, class_constr_state_end, class_constr_state_size, free, vtrans)) { return STATUS_ERR; } return STATUS_SUCCESS; }