diff options
Diffstat (limited to 'libpoldiff/src/bool_diff.c')
-rw-r--r-- | libpoldiff/src/bool_diff.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/libpoldiff/src/bool_diff.c b/libpoldiff/src/bool_diff.c new file mode 100644 index 0000000..3db1e46 --- /dev/null +++ b/libpoldiff/src/bool_diff.c @@ -0,0 +1,333 @@ +/** + * @file + * Implementation for computing semantic differences in booleans. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Randy Wicks rwicks@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 "poldiff_internal.h" + +#include <apol/util.h> +#include <apol/vector.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdbool.h> + +struct poldiff_bool_summary +{ + size_t num_added; + size_t num_removed; + size_t num_modified; + apol_vector_t *diffs; +}; + +struct poldiff_bool +{ + char *name; + poldiff_form_e form; + bool state; +}; + +void poldiff_bool_get_stats(const poldiff_t * diff, size_t stats[5]) +{ + if (diff == NULL || stats == NULL) { + ERR(diff, "%s", strerror(EINVAL)); + errno = EINVAL; + return; + } + stats[0] = diff->bool_diffs->num_added; + stats[1] = diff->bool_diffs->num_removed; + stats[2] = diff->bool_diffs->num_modified; + stats[3] = 0; + stats[4] = 0; +} + +char *poldiff_bool_to_string(const poldiff_t * diff, const void *boolean) +{ + poldiff_bool_t *b = (poldiff_bool_t *) boolean; + size_t len = 0; + char *s = NULL; + if (diff == NULL || boolean == NULL) { + ERR(diff, "%s", strerror(EINVAL)); + errno = EINVAL; + return NULL; + } + switch (b->form) { + case POLDIFF_FORM_ADDED: + { + if (apol_str_appendf(&s, &len, "+ %s", b->name) < 0) { + break; + } + return s; + } + case POLDIFF_FORM_REMOVED: + { + if (apol_str_appendf(&s, &len, "- %s", b->name) < 0) { + break; + } + return s; + } + case POLDIFF_FORM_MODIFIED: + { + if (apol_str_appendf + (&s, &len, "* %s (changed from %s)", b->name, (b->state ? "false to true" : "true to false")) < 0) { + break; + } + return s; + } + default: + { + ERR(diff, "%s", strerror(ENOTSUP)); + errno = ENOTSUP; + return NULL; + } + } + errno = ENOMEM; + return NULL; +} + +const apol_vector_t *poldiff_get_bool_vector(const poldiff_t * diff) +{ + if (diff == NULL) { + errno = EINVAL; + return NULL; + } + return diff->bool_diffs->diffs; +} + +const char *poldiff_bool_get_name(const poldiff_bool_t * boolean) +{ + if (boolean == NULL) { + errno = EINVAL; + return NULL; + } + return boolean->name; +} + +poldiff_form_e poldiff_bool_get_form(const void *boolean) +{ + if (boolean == NULL) { + errno = EINVAL; + return 0; + } + return ((const poldiff_bool_t *)boolean)->form; +} + +/******************** protected functions ********************/ + +static void bool_free(void *elem) +{ + if (elem != NULL) { + poldiff_bool_t *b = (poldiff_bool_t *) elem; + free(b->name); + free(b); + } +} + +poldiff_bool_summary_t *bool_create(void) +{ + poldiff_bool_summary_t *bs = calloc(1, sizeof(*bs)); + if (bs == NULL) { + return NULL; + } + if ((bs->diffs = apol_vector_create(bool_free)) == NULL) { + bool_destroy(&bs); + return NULL; + } + return bs; +} + +void bool_destroy(poldiff_bool_summary_t ** bs) +{ + if (bs != NULL && *bs != NULL) { + apol_vector_destroy(&(*bs)->diffs); + free(*bs); + *bs = NULL; + } +} + +int bool_reset(poldiff_t * diff) +{ + int error = 0; + + if (diff == NULL) { + ERR(diff, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + + bool_destroy(&diff->bool_diffs); + diff->bool_diffs = bool_create(); + if (diff->bool_diffs == NULL) { + error = errno; + ERR(diff, "%s", strerror(error)); + errno = error; + return -1; + } + + return 0; +} + +/** + * Comparison function for two bools from the same policy. + */ +static int bool_name_comp(const void *x, const void *y, void *arg) +{ + qpol_bool_t *c1 = (qpol_bool_t *) x; + qpol_bool_t *c2 = (qpol_bool_t *) y; + apol_policy_t *p = (apol_policy_t *) arg; + qpol_policy_t *q = apol_policy_get_qpol(p); + const char *name1, *name2; + if (qpol_bool_get_name(q, c1, &name1) < 0 || qpol_bool_get_name(q, c2, &name2) < 0) { + return 0; + } + return strcmp(name1, name2); +} + +apol_vector_t *bool_get_items(poldiff_t * diff, const apol_policy_t * policy) +{ + qpol_iterator_t *iter = NULL; + apol_vector_t *v = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + if (qpol_policy_get_bool_iter(q, &iter) < 0) { + return NULL; + } + v = apol_vector_create_from_iter(iter, NULL); + if (v == NULL) { + error = errno; + ERR(diff, "%s", strerror(error)); + qpol_iterator_destroy(&iter); + errno = error; + return NULL; + } + qpol_iterator_destroy(&iter); + apol_vector_sort(v, bool_name_comp, (void *)policy); + return v; +} + +int bool_comp(const void *x, const void *y, const poldiff_t * diff) +{ + qpol_bool_t *c1 = (qpol_bool_t *) x; + qpol_bool_t *c2 = (qpol_bool_t *) y; + const char *name1, *name2; + if (qpol_bool_get_name(diff->orig_qpol, c1, &name1) < 0 || qpol_bool_get_name(diff->mod_qpol, c2, &name2) < 0) { + return 0; + } + return strcmp(name1, name2); +} + +/** + * Allocate and return a new bool difference object. + * + * @param diff Policy diff error handler. + * @param form Form of the difference. + * @param name Name of the bool that is different. + * + * @return A newly allocated and initialized diff, or NULL upon error. + * The caller is responsible for calling bool_free() upon the + * returned value. + */ +static poldiff_bool_t *make_diff(const poldiff_t * diff, poldiff_form_e form, const char *name) +{ + poldiff_bool_t *pb; + int error; + if ((pb = calloc(1, sizeof(*pb))) == NULL || (pb->name = strdup(name)) == NULL) { + error = errno; + bool_free(pb); + ERR(diff, "%s", strerror(error)); + errno = error; + return NULL; + } + pb->form = form; + return pb; +} + +int bool_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item) +{ + qpol_bool_t *c = (qpol_bool_t *) item; + const char *name = NULL; + poldiff_bool_t *pb; + int error; + if ((form == POLDIFF_FORM_ADDED && + qpol_bool_get_name(diff->mod_qpol, c, &name) < 0) || + ((form == POLDIFF_FORM_REMOVED || form == POLDIFF_FORM_MODIFIED) && qpol_bool_get_name(diff->orig_qpol, c, &name) < 0)) + { + return -1; + } + pb = make_diff(diff, form, name); + if (pb == NULL) { + return -1; + } + if (apol_vector_append(diff->bool_diffs->diffs, pb) < 0) { + error = errno; + ERR(diff, "%s", strerror(error)); + bool_free(pb); + errno = error; + return -1; + } + if (form == POLDIFF_FORM_ADDED) + diff->bool_diffs->num_added++; + else + diff->bool_diffs->num_removed++; + return 0; +} + +int bool_deep_diff(poldiff_t * diff, const void *x, const void *y) +{ + qpol_bool_t *b1 = (qpol_bool_t *) x; + qpol_bool_t *b2 = (qpol_bool_t *) y; + const char *name; + int s1, s2; + poldiff_bool_t *b = NULL; + int retval = -1, error = 0; + + if (qpol_bool_get_name(diff->orig_qpol, b1, &name) < 0 || + qpol_bool_get_state(diff->orig_qpol, b1, &s1) < 0 || qpol_bool_get_state(diff->mod_qpol, b2, &s2) < 0) { + error = errno; + goto cleanup; + } + if (s1 != s2) { + if ((b = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) { + error = errno; + goto cleanup; + } + if (s2) + b->state = true; + else + b->state = false; + } + if (b != NULL) { + if (apol_vector_append(diff->bool_diffs->diffs, b) < 0) { + error = errno; + ERR(diff, "%s", strerror(error)); + goto cleanup; + } + diff->bool_diffs->num_modified++; + } + retval = 0; + cleanup: + errno = error; + return retval; +} |