diff options
Diffstat (limited to 'libapol/src/relabel-analysis.c')
-rw-r--r-- | libapol/src/relabel-analysis.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/libapol/src/relabel-analysis.c b/libapol/src/relabel-analysis.c new file mode 100644 index 0000000..d1cab99 --- /dev/null +++ b/libapol/src/relabel-analysis.c @@ -0,0 +1,813 @@ +/** + * @file + * Implementation of the direct relabelling analysis. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-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 "policy-query-internal.h" + +#include <errno.h> +#include <string.h> + +/* defines for mode */ +#define APOL_RELABEL_MODE_OBJ 0x01 +#define APOL_RELABEL_MODE_SUBJ 0x02 + +struct apol_relabel_analysis +{ + unsigned int mode, direction; + char *type, *result; + apol_vector_t *classes, *subjects; + regex_t *result_regex; +}; + +/** + * Results are in the form of a list of apol_relabel_result_t nodes. + * Each node has three sublists of apol_relabel_result_pair_t. + */ +struct apol_relabel_result +{ + apol_vector_t *to; + apol_vector_t *from; + apol_vector_t *both; + const qpol_type_t *type; +}; + +struct apol_relabel_result_pair +{ + const qpol_avrule_t *ruleA, *ruleB; + const qpol_type_t *intermed; +}; + +#define PERM_RELABELTO "relabelto" +#define PERM_RELABELFROM "relabelfrom" + +/******************** actual analysis rountines ********************/ + +/** + * Given an avrule, determine which relabel direction it has (to, + * from, or both). + * + * @param p Policy containing avrule. + * @param avrule Rule to examine. + * + * @return One of APOL_RELABEL_DIR_TO, APOL_RELABEL_DIR_FROM, + * APOL_RELABEL_DIR_BOTH, or < 0 if direction could not be determined. + */ +static int relabel_analysis_get_direction(const apol_policy_t * p, const qpol_avrule_t * avrule) +{ + qpol_iterator_t *iter; + int to = 0, from = 0, retval = -1; + + if (qpol_avrule_get_perm_iter(p->p, avrule, &iter) < 0) { + goto cleanup; + } + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + char *perm; + if (qpol_iterator_get_item(iter, (void **)&perm) < 0) { + goto cleanup; + } + if (strcmp(perm, PERM_RELABELTO) == 0) { + to = 1; + } else if (strcmp(perm, PERM_RELABELFROM) == 0) { + from = 1; + } + free(perm); + perm = NULL; + } + if (to && from) { + retval = APOL_RELABEL_DIR_BOTH; + } else if (to) { + retval = APOL_RELABEL_DIR_TO; + } else if (from) { + retval = APOL_RELABEL_DIR_FROM; + } + cleanup: + qpol_iterator_destroy(&iter); + return retval; +} + +/** + * Given an apol_relabel_result_t node and a qpol_type_t, determine if + * the two match. + * + * @param a Pointer to a apol_relabel_result_t. + * @param b Pointer to a type. + * @param data (Unused). + * + * @return 0 if the result node's type matches the given type, + * non-zero if not. + */ +static int relabel_result_comp_func(const void *a, const void *b, void *data __attribute__ ((unused))) +{ + apol_relabel_result_t *r = (apol_relabel_result_t *) a; + qpol_type_t *t = (qpol_type_t *) b; + return (int)((char *)r->type - (char *)t); +} + +static void relabel_result_free(void *result) +{ + if (result != NULL) { + apol_relabel_result_t *r = (apol_relabel_result_t *) result; + apol_vector_destroy(&r->to); + apol_vector_destroy(&r->from); + apol_vector_destroy(&r->both); + free(result); + } +} + +/** + * Given a qpol_type_t pointer, find and return the first + * apol_relabel_result_t node within vector v that matches the type. + * If there does not exist a node with that type, then allocate a new + * one, append it to the vector, and return it. The caller is + * expected to eventually call apol_vector_destroy() upon the vector. + * + * @param p Policy, used for error handling. + * @param results A vector of apol_relabel_result_t nodes. + * @param type Target type to find. + * + * @return An apol_relabel_result_t node from which to append results, + * or NULL upon error. + */ +static apol_relabel_result_t *relabel_result_get_node(const apol_policy_t * p, apol_vector_t * results, const qpol_type_t * type) +{ + apol_relabel_result_t *result; + size_t i; + if (apol_vector_get_index(results, type, relabel_result_comp_func, NULL, &i) == 0) { + return (apol_relabel_result_t *) apol_vector_get_element(results, i); + } + /* make a new result node */ + if ((result = calloc(1, sizeof(*result))) == NULL || + (result->to = apol_vector_create(free)) == NULL || + (result->from = apol_vector_create(free)) == NULL || + (result->both = apol_vector_create(free)) == NULL || apol_vector_append(results, result) < 0) { + ERR(p, "%s", strerror(errno)); + relabel_result_free(result); + return NULL; + } + result->type = type; + return result; +} + +/** + * Given a vector of strings representing type names, allocate and + * return a vector of qpol_type_t pointers into the given policy for + * those types. If a type name is really an alias, obtain and store + * its primary instead. + * + * @param p Policy to which look up types + * @param v Vector of strings. + * + * @return A newly allocated apol_vector_t, which the caller must free + * with apol_vector_destroy(). If a type name was not found or upon + * other error return NULL. + */ +static apol_vector_t *relabel_analysis_get_type_vector(const apol_policy_t * p, const apol_vector_t * v) +{ + apol_vector_t *types = NULL; + size_t i; + int retval = -1; + + if ((types = apol_vector_create_with_capacity(apol_vector_get_size(v), NULL)) == NULL) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + char *s = (char *)apol_vector_get_element(v, i); + const qpol_type_t *type; + if (apol_query_get_type(p, s, &type) < 0) { + goto cleanup; + } + if (apol_vector_append(types, (void *)type)) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + } + + retval = 0; + cleanup: + if (retval == -1) { + apol_vector_destroy(&types); + return NULL; + } + return types; +} + +/** + * Given a type, see if it is an element within a vector of + * qpol_type_t pointers. If the type is really an attribute, also + * check if any of the attribute's types are a member of v. If v is + * NULL then the comparison always succeeds. + * + * @param p Policy to which look up types. + * @param v Target vector of qpol_type_t pointers. + * @param type Source type to find. + * + * @return 1 if type is a member of v, 0 if not, < 0 on error. + */ +static int relabel_analysis_compare_type_to_vector(const apol_policy_t * p, const apol_vector_t * v, const qpol_type_t * type) +{ + size_t i; + unsigned char isattr; + qpol_iterator_t *iter = NULL; + int retval = -1; + if (v == NULL || apol_vector_get_index(v, type, NULL, NULL, &i) == 0) { + retval = 1; /* found it */ + goto cleanup; + } + if (qpol_type_get_isattr(p->p, type, &isattr) < 0) { + goto cleanup; + } + if (!isattr) { /* not an attribute, so comparison failed */ + retval = 0; + goto cleanup; + } + if (qpol_type_get_type_iter(p->p, type, &iter) < 0) { + goto cleanup; + } + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_type_t *t; + if (qpol_iterator_get_item(iter, (void **)&t) < 0) { + goto cleanup; + } + if (apol_vector_get_index(v, t, NULL, NULL, &i) == 0) { + retval = 1; + goto cleanup; + } + } + retval = 0; /* no matches */ + cleanup: + qpol_iterator_destroy(&iter); + return retval; +} + +/** + * Given two avrules, possbily append it to the object results vector + * onto the appropriate rules vector. The decision to actually append + * or not is dependent upon the filtering options stored within the + * relabel analysis object. + * + * @param p Policy containing avrule. + * @param r Relabel analysis query object, containing filtering options. + * @param ruleA First AV rule to add. + * @param ruleB Other AV rule to add. + * @param result Results vector being built. + * + * @return 0 on success, < 0 on error. + */ +static int append_avrules_to_object_vector(const apol_policy_t * p, + apol_relabel_analysis_t * r, + const qpol_avrule_t * ruleA, const qpol_avrule_t * ruleB, apol_vector_t * results) +{ + const qpol_type_t *sourceA, *sourceB, *target, *intermed; + unsigned char isattrA, isattrB; + apol_vector_t *target_v = NULL, *result_list; + size_t i; + apol_relabel_result_t *result; + apol_relabel_result_pair_t *pair = NULL; + int retval = -1, compval, dirA, dirB; + if (qpol_avrule_get_target_type(p->p, ruleB, &target) < 0 || (target_v = apol_query_expand_type(p, target)) == NULL) { + goto cleanup; + } + if (qpol_avrule_get_source_type(p->p, ruleA, &sourceA) < 0 || + qpol_avrule_get_source_type(p->p, ruleB, &sourceB) < 0 || + qpol_type_get_isattr(p->p, sourceA, &isattrA) < 0 || qpol_type_get_isattr(p->p, sourceB, &isattrB) < 0) { + goto cleanup; + } + /* If both rules use the same attribute, retain the attribute + * to minimize the number of results and to indicate that all + * types with that attribute have the permission to relabel. */ + if ((isattrA && isattrB) || !isattrA) { + intermed = sourceA; + } else { + intermed = sourceB; + } + for (i = 0; i < apol_vector_get_size(target_v); i++) { + target = (qpol_type_t *) apol_vector_get_element(target_v, i); + /* exclude if B(t) does not match search criteria */ + compval = apol_compare_type(p, target, r->type, 0, NULL); + if (compval < 0) { + goto cleanup; + } else if (compval == 1) { + continue; /* don't care about relabels to itself */ + } + compval = apol_compare_type(p, target, r->result, APOL_QUERY_REGEX, &r->result_regex); + if (compval < 0) { + goto cleanup; + } else if (compval == 0) { + continue; + } + if ((result = relabel_result_get_node(p, results, target)) == NULL) { + goto cleanup; + } + if ((dirA = relabel_analysis_get_direction(p, ruleA)) < 0 || (dirB = relabel_analysis_get_direction(p, ruleB)) < 0) { + goto cleanup; + } + if ((pair = calloc(1, sizeof(*pair))) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + if (dirA == APOL_RELABEL_DIR_BOTH && dirB == APOL_RELABEL_DIR_BOTH) { + result_list = result->both; + pair->ruleA = ruleA; + pair->ruleB = ruleB; + } else if (dirA == APOL_RELABEL_DIR_FROM || dirB == APOL_RELABEL_DIR_TO) { + result_list = result->to; + pair->ruleA = ruleA; + pair->ruleB = ruleB; + } else { + result_list = result->from; + pair->ruleA = ruleB; + pair->ruleB = ruleA; + } + pair->intermed = intermed; + if ((apol_vector_append(result_list, pair)) < 0) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + pair = NULL; + } + retval = 0; + cleanup: + free(pair); + apol_vector_destroy(&target_v); + return retval; +} + +/** + * Search through sets av and bv, finding pairs of avrules that + * satisfy a relabel and adding those pairs to result vector v. + * + * @param p Policy containing avrules. + * @param r Relabel analysis query object. + * @param v Vector of apol_relabel_result_t nodes. + * @param av Vector of qpol_avrule_t pointers. + * @param bv Vector of qpol_avrule_t pointers. + * @param subjects_v Vector of permitted qpol_type_t subjects, or NULL + * to allow all types. + * + * @return 0 on success, < 0 upon error. + */ +static int relabel_analysis_matchup(const apol_policy_t * p, + apol_relabel_analysis_t * r, + apol_vector_t * av, apol_vector_t * bv, const apol_vector_t * subjects_v, apol_vector_t * v) +{ + const qpol_avrule_t *a_avrule, *b_avrule; + const qpol_type_t *a_source, *a_target, *b_source, *b_target, *start_type; + const qpol_class_t *a_class, *b_class; + apol_vector_t *start_v = NULL; + size_t i, j; + int compval, retval = -1; + + if (apol_query_get_type(p, r->type, &start_type) < 0) { + goto cleanup; + } + for (i = 0; i < apol_vector_get_size(av); i++) { + a_avrule = apol_vector_get_element(av, i); + if (qpol_avrule_get_source_type(p->p, a_avrule, &a_source) < 0 || + qpol_avrule_get_target_type(p->p, a_avrule, &a_target) < 0 || + qpol_avrule_get_object_class(p->p, a_avrule, &a_class) < 0) { + goto cleanup; + } + compval = relabel_analysis_compare_type_to_vector(p, subjects_v, a_source); + if (compval < 0) { + goto cleanup; + } else if (compval == 0) { + continue; + } + if ((start_v = apol_query_expand_type(p, a_source)) == NULL) { + goto cleanup; + } + + /* check if there exists a B s.t. B(s) = source and + * B(t) != r->type and B(o) = A(o) */ + for (j = 0; j < apol_vector_get_size(bv); j++) { + b_avrule = apol_vector_get_element(bv, j); + if (qpol_avrule_get_source_type(p->p, b_avrule, &b_source) < 0 || + qpol_avrule_get_target_type(p->p, b_avrule, &b_target) < 0 || + qpol_avrule_get_object_class(p->p, b_avrule, &b_class) < 0) { + goto cleanup; + } + if (relabel_analysis_compare_type_to_vector(p, start_v, b_source) != 1 || + b_target == start_type || a_class != b_class) { + continue; + } + if (append_avrules_to_object_vector(p, r, a_avrule, b_avrule, v) < 0) { + goto cleanup; + } + } + apol_vector_destroy(&start_v); + } + + retval = 0; + cleanup: + apol_vector_destroy(&start_v); + return retval; +} + +/** + * Get a list of allow rules, whose target type matches r->type and + * whose permission is <i>opposite</i> of the direction given (e.g., + * relabelfrom if given DIR_TO). Only include rules whose class is a + * member of r->classes and whose source is a member of subjects_v. + * + * @param p Policy to which look up rules. + * @param r Structure containing parameters for subject relabel analysis. + * @param v Target vector to which append discovered rules. + * @param direction Relabelling direction to search. + * @param subjects_v If not NULL, then a vector of qpol_type_t pointers. + * + * @return 0 on success, < 0 on error. + */ +static int relabel_analysis_object(const apol_policy_t * p, + apol_relabel_analysis_t * r, + apol_vector_t * v, unsigned int direction, const apol_vector_t * subjects_v) +{ + apol_avrule_query_t *a = NULL, *b = NULL; + apol_vector_t *a_rules = NULL, *b_rules = NULL; + char *perm1, *perm2; + size_t i; + int retval = -1; + + if (direction == APOL_RELABEL_DIR_TO) { + perm1 = PERM_RELABELFROM; + perm2 = PERM_RELABELTO; + } else { + perm1 = PERM_RELABELTO; + perm2 = PERM_RELABELFROM; + } + + if ((a = apol_avrule_query_create()) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + if (apol_avrule_query_set_rules(p, a, QPOL_RULE_ALLOW) < 0 || + apol_avrule_query_set_target(p, a, r->type, 1) < 0 || apol_avrule_query_append_perm(p, a, perm1) < 0) { + goto cleanup; + } + for (i = 0; r->classes != NULL && i < apol_vector_get_size(r->classes); i++) { + if (apol_avrule_query_append_class(p, a, apol_vector_get_element(r->classes, i)) < 0) { + goto cleanup; + } + } + if (apol_avrule_get_by_query(p, a, &a_rules) < 0) { + goto cleanup; + } + + if ((b = apol_avrule_query_create()) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + if (apol_avrule_query_set_rules(p, b, QPOL_RULE_ALLOW) < 0 || apol_avrule_query_append_perm(p, b, perm2) < 0) { + goto cleanup; + } + for (i = 0; r->classes != NULL && i < apol_vector_get_size(r->classes); i++) { + if (apol_avrule_query_append_class(p, b, apol_vector_get_element(r->classes, i)) < 0) { + goto cleanup; + } + } + if (apol_avrule_get_by_query(p, b, &b_rules) < 0) { + goto cleanup; + } + + if (relabel_analysis_matchup(p, r, a_rules, b_rules, subjects_v, v) < 0) { + goto cleanup; + } + retval = 0; + cleanup: + apol_avrule_query_destroy(&a); + apol_vector_destroy(&a_rules); + apol_avrule_query_destroy(&b); + apol_vector_destroy(&b_rules); + return retval; +} + +/** + * Given an avrule, possbily append it to the subject results vector + * onto the appropriate rules vector. The decision to actually append + * or not is dependent upon the filtering options stored within the + * relabel analysis object. + * + * @param p Policy containing avrule. + * @param r Relabel analysis query object, containing filtering options. + * @param avrule AV rule to add. + * @param result Results vector being built. + * + * @return 0 on success, < 0 on error. + */ +static int append_avrule_to_subject_vector(const apol_policy_t * p, + apol_relabel_analysis_t * r, const qpol_avrule_t * avrule, apol_vector_t * results) +{ + const qpol_type_t *target; + apol_vector_t *target_v = NULL, *result_list = NULL; + size_t i; + apol_relabel_result_t *result; + apol_relabel_result_pair_t *pair = NULL; + int retval = -1, dir, compval; + if ((dir = relabel_analysis_get_direction(p, avrule)) < 0) { + goto cleanup; + } + if (qpol_avrule_get_target_type(p->p, avrule, &target) < 0 || (target_v = apol_query_expand_type(p, target)) == NULL) { + goto cleanup; + } + for (i = 0; i < apol_vector_get_size(target_v); i++) { + target = (qpol_type_t *) apol_vector_get_element(target_v, i); + compval = apol_compare_type(p, target, r->type, 0, NULL); + if (compval < 0) { + goto cleanup; + } else if (compval == 1) { + continue; /* don't care about relabels to itself */ + } + compval = apol_compare_type(p, target, r->result, APOL_QUERY_REGEX, &r->result_regex); + if (compval < 0) { + goto cleanup; + } else if (compval == 0) { + continue; + } + if ((result = relabel_result_get_node(p, results, target)) == NULL) { + goto cleanup; + } + if ((pair = calloc(1, sizeof(*pair))) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + pair->ruleA = avrule; + pair->ruleB = NULL; + pair->intermed = NULL; + switch (dir) { + case APOL_RELABEL_DIR_TO: + result_list = result->to; + break; + case APOL_RELABEL_DIR_FROM: + result_list = result->from; + break; + case APOL_RELABEL_DIR_BOTH: + result_list = result->both; + break; + } + if ((apol_vector_append(result_list, pair)) < 0) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + pair = NULL; + } + retval = 0; + cleanup: + apol_vector_destroy(&target_v); + free(pair); + return retval; +} + +/** + * Get a list of all allow rules, whose source type matches r->type + * and whose permission list has either "relabelto" or "relabelfrom". + * Only include rules whose class is a member of r->classes. Add + * instances of those to the result vector. + * + * @param p Policy to which look up rules. + * @param r Structure containing parameters for subject relabel analysis. + * @param v Target vector to which append discovered rules. + * + * @return 0 on success, < 0 on error. + */ +static int relabel_analysis_subject(const apol_policy_t * p, apol_relabel_analysis_t * r, apol_vector_t * v) +{ + apol_avrule_query_t *a = NULL; + apol_vector_t *avrules_v = NULL; + const qpol_avrule_t *avrule; + size_t i; + int retval = -1; + + if ((a = apol_avrule_query_create()) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + if (apol_avrule_query_set_rules(p, a, QPOL_RULE_ALLOW) < 0 || + apol_avrule_query_set_source(p, a, r->type, 1) < 0 || + apol_avrule_query_append_perm(p, a, PERM_RELABELTO) < 0 || apol_avrule_query_append_perm(p, a, PERM_RELABELFROM) < 0) { + goto cleanup; + } + for (i = 0; r->classes != NULL && i < apol_vector_get_size(r->classes); i++) { + if (apol_avrule_query_append_class(p, a, apol_vector_get_element(r->classes, i)) < 0) { + goto cleanup; + } + } + if (apol_avrule_get_by_query(p, a, &avrules_v) < 0) { + goto cleanup; + } + + for (i = 0; i < apol_vector_get_size(avrules_v); i++) { + avrule = (qpol_avrule_t *) apol_vector_get_element(avrules_v, i); + if (append_avrule_to_subject_vector(p, r, avrule, v) < 0) { + goto cleanup; + } + } + + retval = 0; + cleanup: + apol_avrule_query_destroy(&a); + apol_vector_destroy(&avrules_v); + return retval; +} + +/******************** public functions below ********************/ + +int apol_relabel_analysis_do(const apol_policy_t * p, apol_relabel_analysis_t * r, apol_vector_t ** v) +{ + apol_vector_t *subjects_v = NULL; + const qpol_type_t *start_type; + int retval = -1; + *v = NULL; + + if (r->mode == 0 || r->type == NULL) { + ERR(p, "%s", strerror(EINVAL)); + goto cleanup; + } + if (apol_query_get_type(p, r->type, &start_type) < 0) { + goto cleanup; + } + + if ((*v = apol_vector_create(relabel_result_free)) == NULL) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + + if (r->mode == APOL_RELABEL_MODE_OBJ) { + if (r->subjects != NULL && (subjects_v = relabel_analysis_get_type_vector(p, r->subjects)) == NULL) { + goto cleanup; + } + if ((r->direction & APOL_RELABEL_DIR_TO) && relabel_analysis_object(p, r, *v, APOL_RELABEL_DIR_TO, subjects_v) < 0) { + goto cleanup; + } + if ((r->direction & APOL_RELABEL_DIR_FROM) && + relabel_analysis_object(p, r, *v, APOL_RELABEL_DIR_FROM, subjects_v) < 0) { + goto cleanup; + } + } else { + if (relabel_analysis_subject(p, r, *v) < 0) { + goto cleanup; + } + } + + retval = 0; + cleanup: + apol_vector_destroy(&subjects_v); + if (retval != 0) { + apol_vector_destroy(v); + } + return retval; +} + +apol_relabel_analysis_t *apol_relabel_analysis_create(void) +{ + return calloc(1, sizeof(apol_relabel_analysis_t)); +} + +void apol_relabel_analysis_destroy(apol_relabel_analysis_t ** r) +{ + if (r != NULL && *r != NULL) { + free((*r)->type); + free((*r)->result); + apol_vector_destroy(&(*r)->classes); + apol_vector_destroy(&(*r)->subjects); + apol_regex_destroy(&(*r)->result_regex); + free(*r); + *r = NULL; + } +} + +int apol_relabel_analysis_set_dir(const apol_policy_t * p, apol_relabel_analysis_t * r, unsigned int dir) +{ + if (p == NULL || r == NULL) { + ERR(p, "%s", strerror(EINVAL)); + return -1; + } + + switch (dir) { + case APOL_RELABEL_DIR_BOTH: + case APOL_RELABEL_DIR_TO: + case APOL_RELABEL_DIR_FROM: + { + r->mode = APOL_RELABEL_MODE_OBJ; + r->direction = dir; + break; + } + case APOL_RELABEL_DIR_SUBJECT: + { + r->mode = APOL_RELABEL_MODE_SUBJ; + r->direction = APOL_RELABEL_DIR_BOTH; + break; + } + default: + { + ERR(p, "%s", strerror(EINVAL)); + return -1; + } + } + return 0; +} + +int apol_relabel_analysis_set_type(const apol_policy_t * p, apol_relabel_analysis_t * r, const char *name) +{ + if (p == NULL || r == NULL || name == NULL) { + ERR(p, "%s", strerror(EINVAL)); + return -1; + } + return apol_query_set(p, &r->type, NULL, name); +} + +int apol_relabel_analysis_append_class(const apol_policy_t * p, apol_relabel_analysis_t * r, const char *obj_class) +{ + char *s; + if (p == NULL || r == NULL) { + ERR(p, "%s", strerror(EINVAL)); + return -1; + } + if (obj_class == NULL) { + apol_vector_destroy(&r->classes); + } else if ((s = strdup(obj_class)) == NULL || (r->classes == NULL && (r->classes = apol_vector_create(free)) == NULL) + || apol_vector_append(r->classes, s) < 0) { + ERR(p, "%s", strerror(errno)); + return -1; + } + return 0; +} + +int apol_relabel_analysis_append_subject(const apol_policy_t * p, apol_relabel_analysis_t * r, const char *subject) +{ + char *s; + if (p == NULL || r == NULL) { + ERR(p, "%s", strerror(EINVAL)); + return -1; + } + if (subject == NULL) { + apol_vector_destroy(&r->subjects); + } else if ((s = strdup(subject)) == NULL || + (r->subjects == NULL && (r->subjects = apol_vector_create(free)) == NULL) || + apol_vector_append(r->subjects, s) < 0) { + ERR(p, "%s", strerror(errno)); + return -1; + } + return 0; +} + +int apol_relabel_analysis_set_result_regex(const apol_policy_t * p, apol_relabel_analysis_t * r, const char *result) +{ + return apol_query_set(p, &r->result, &r->result_regex, result); +} + +/******************** functions to access relabel results ********************/ + +const apol_vector_t *apol_relabel_result_get_to(const apol_relabel_result_t * r) +{ + return r->to; +} + +const apol_vector_t *apol_relabel_result_get_from(const apol_relabel_result_t * r) +{ + return r->from; +} + +const apol_vector_t *apol_relabel_result_get_both(const apol_relabel_result_t * r) +{ + return r->both; +} + +const qpol_type_t *apol_relabel_result_get_result_type(const apol_relabel_result_t * r) +{ + return r->type; +} + +const qpol_avrule_t *apol_relabel_result_pair_get_ruleA(const apol_relabel_result_pair_t * p) +{ + return p->ruleA; +} + +const qpol_avrule_t *apol_relabel_result_pair_get_ruleB(const apol_relabel_result_pair_t * p) +{ + return p->ruleB; +} + +const qpol_type_t *apol_relabel_result_pair_get_intermediate_type(const apol_relabel_result_pair_t * p) +{ + return p->intermed; +} |