diff options
Diffstat (limited to 'libapol/src/fscon-query.c')
-rw-r--r-- | libapol/src/fscon-query.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/libapol/src/fscon-query.c b/libapol/src/fscon-query.c new file mode 100644 index 0000000..be3c7d3 --- /dev/null +++ b/libapol/src/fscon-query.c @@ -0,0 +1,437 @@ +/** + * @file + * + * Provides a way for setools to make queries about genfscons and + * fs_use statements within a policy. The caller obtains a query + * object, fills in its parameters, and then runs the query; it + * obtains a vector of results. Searches are conjunctive -- all + * fields of the search query must match for a datum to be added to + * the results query. + * + * @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 "policy-query-internal.h" +#include <apol/render.h> + +#include <errno.h> +#include <stdio.h> +#include <stdbool.h> + +struct apol_genfscon_query +{ + char *fs, *path; + uint32_t objclass; + bool objclass_set; + apol_context_t *context; + unsigned int flags; +}; + +struct apol_fs_use_query +{ + char *fs; + uint32_t behavior; + bool behavior_set; + apol_context_t *context; + unsigned int flags; +}; + +/******************** genfscon queries ********************/ + +int apol_genfscon_get_by_query(const apol_policy_t * p, const apol_genfscon_query_t * g, apol_vector_t ** v) +{ + qpol_iterator_t *iter; + int retval = -1, retval2; + qpol_genfscon_t *genfscon = NULL; + *v = NULL; + if (qpol_policy_get_genfscon_iter(p->p, &iter) < 0) { + return -1; + } + if ((*v = apol_vector_create(free)) == NULL) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + if (qpol_iterator_get_item(iter, (void **)&genfscon) < 0) { + goto cleanup; + } + if (g != NULL) { + const char *fs, *path; + uint32_t objclass; + const qpol_context_t *context; + if (qpol_genfscon_get_name(p->p, genfscon, &fs) < 0 || + qpol_genfscon_get_path(p->p, genfscon, &path) < 0 || + qpol_genfscon_get_class(p->p, genfscon, &objclass) < 0 || + qpol_genfscon_get_context(p->p, genfscon, &context) < 0) { + goto cleanup; + } + retval2 = apol_compare(p, fs, g->fs, 0, NULL); + if (retval2 < 0) { + goto cleanup; + } else if (retval2 == 0) { + free(genfscon); + continue; + } + retval2 = apol_compare(p, path, g->path, 0, NULL); + if (retval2 < 0) { + goto cleanup; + } else if (retval2 == 0) { + free(genfscon); + continue; + } + if (g->objclass_set && g->objclass != objclass) { + free(genfscon); + continue; + } + retval2 = apol_compare_context(p, context, g->context, g->flags); + if (retval2 < 0) { + goto cleanup; + } else if (retval2 == 0) { + free(genfscon); + continue; + } + } + if (apol_vector_append(*v, genfscon)) { + ERR(p, "%s", strerror(EINVAL)); + goto cleanup; + } + } + + retval = 0; + cleanup: + if (retval != 0) { + apol_vector_destroy(v); + free(genfscon); + } + qpol_iterator_destroy(&iter); + return retval; +} + +apol_genfscon_query_t *apol_genfscon_query_create(void) +{ + apol_genfscon_query_t *g = calloc(1, sizeof(apol_genfscon_query_t)); + if (g != NULL) { + g->objclass = -1; + } + return g; +} + +void apol_genfscon_query_destroy(apol_genfscon_query_t ** g) +{ + if (*g != NULL) { + free((*g)->fs); + free((*g)->path); + apol_context_destroy(&((*g)->context)); + free(*g); + *g = NULL; + } +} + +int apol_genfscon_query_set_filesystem(const apol_policy_t * p, apol_genfscon_query_t * g, const char *fs) +{ + return apol_query_set(p, &g->fs, NULL, fs); +} + +int apol_genfscon_query_set_path(const apol_policy_t * p, apol_genfscon_query_t * g, const char *path) +{ + int tmp = apol_query_set(p, &g->path, NULL, path); + if (!tmp && g->path) { + if (strlen(g->path) > 1 && g->path[strlen(g->path) - 1] == '/') + g->path[strlen(g->path) - 1] = 0; + } + return tmp; +} + +int apol_genfscon_query_set_objclass(const apol_policy_t * p, apol_genfscon_query_t * g, int objclass) +{ + if (objclass < 0) { + g->objclass = 0; + g->objclass_set = false; + } else { + switch (objclass) { + case QPOL_CLASS_BLK_FILE: + case QPOL_CLASS_CHR_FILE: + case QPOL_CLASS_DIR: + case QPOL_CLASS_FIFO_FILE: + case QPOL_CLASS_FILE: + case QPOL_CLASS_LNK_FILE: + case QPOL_CLASS_SOCK_FILE: + case QPOL_CLASS_ALL: + { + g->objclass = objclass; + g->objclass_set = true; + break; + } + default: + ERR(p, "%s", "Invalid object class given."); + return -1; + } + } + return 0; +} + +int apol_genfscon_query_set_context(const apol_policy_t * p __attribute__ ((unused)), + apol_genfscon_query_t * g, apol_context_t * context, unsigned int range_match) +{ + if (g->context != NULL) { + apol_context_destroy(&g->context); + } + g->context = context; + g->flags = (g->flags & ~APOL_QUERY_FLAGS) | range_match; + return 0; +} + +char *apol_genfscon_render(const apol_policy_t * p, const qpol_genfscon_t * genfscon) +{ + char *line = NULL, *retval = NULL; + const qpol_context_t *ctxt = NULL; + char *context_str = NULL; + const char *type_str = NULL; + const char *name = NULL, *path = NULL; + uint32_t fclass; + + if (!genfscon || !p) + goto cleanup; + + if (qpol_genfscon_get_name(p->p, genfscon, &name)) + goto cleanup; + if (qpol_genfscon_get_path(p->p, genfscon, &path)) + goto cleanup; + if (qpol_genfscon_get_class(p->p, genfscon, &fclass)) + return NULL; + if (qpol_genfscon_get_context(p->p, genfscon, &ctxt)) + goto cleanup; + + switch (fclass) { + case QPOL_CLASS_DIR: + type_str = " -d "; + break; + case QPOL_CLASS_CHR_FILE: + type_str = " -c "; + break; + case QPOL_CLASS_BLK_FILE: + type_str = " -b "; + break; + case QPOL_CLASS_FILE: + type_str = " -- "; + break; + case QPOL_CLASS_FIFO_FILE: + type_str = " -p "; + break; + case QPOL_CLASS_LNK_FILE: + type_str = " -l "; + break; + case QPOL_CLASS_SOCK_FILE: + type_str = " -s "; + break; + case QPOL_CLASS_ALL: + type_str = " "; + break; + default: + goto cleanup; + break; + } + context_str = apol_qpol_context_render(p, ctxt); + if (!context_str) + goto cleanup; + + if (asprintf(&line, "genfscon %s %s %s %s", name, path, type_str, context_str) < 0) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + retval = line; + cleanup: + free(context_str); + if (retval != line) { + free(line); + } + return retval; +} + +/******************** fs_use queries ********************/ + +int apol_fs_use_get_by_query(const apol_policy_t * p, const apol_fs_use_query_t * f, apol_vector_t ** v) +{ + qpol_iterator_t *iter; + int retval = -1, retval2; + const qpol_fs_use_t *fs_use = NULL; + *v = NULL; + if (qpol_policy_get_fs_use_iter(p->p, &iter) < 0) { + return -1; + } + if ((*v = apol_vector_create(NULL)) == NULL) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + if (qpol_iterator_get_item(iter, (void **)&fs_use) < 0) { + goto cleanup; + } + if (f != NULL) { + const char *fs; + uint32_t behavior; + const qpol_context_t *context = NULL; + if (qpol_fs_use_get_name(p->p, fs_use, &fs) < 0 || qpol_fs_use_get_behavior(p->p, fs_use, &behavior) < 0) { + goto cleanup; + } + if (behavior != QPOL_FS_USE_PSID && qpol_fs_use_get_context(p->p, fs_use, &context) < 0) { + goto cleanup; + } + retval2 = apol_compare(p, fs, f->fs, 0, NULL); + if (retval2 < 0) { + goto cleanup; + } else if (retval2 == 0) { + continue; + } + if (f->behavior_set && f->behavior != behavior) { + continue; + } + /* recall that fs_use_psid statements do not + * have contexts */ + if (f->context != NULL && behavior == QPOL_FS_USE_PSID) { + retval2 = 0; + } else { + retval2 = apol_compare_context(p, context, f->context, f->flags); + if (retval2 < 0) { + goto cleanup; + } + } + if (retval2 == 0) { + continue; + } + } + if (apol_vector_append(*v, (void *)fs_use)) { + ERR(p, "%s", strerror(EINVAL)); + goto cleanup; + } + } + + retval = 0; + cleanup: + if (retval != 0) { + apol_vector_destroy(v); + } + qpol_iterator_destroy(&iter); + return retval; +} + +apol_fs_use_query_t *apol_fs_use_query_create(void) +{ + apol_fs_use_query_t *f = calloc(1, sizeof(apol_fs_use_query_t)); + if (f != NULL) { + f->behavior = -1; + } + return f; +} + +void apol_fs_use_query_destroy(apol_fs_use_query_t ** f) +{ + if (*f != NULL) { + free((*f)->fs); + apol_context_destroy(&((*f)->context)); + free(*f); + *f = NULL; + } +} + +int apol_fs_use_query_set_filesystem(const apol_policy_t * p, apol_fs_use_query_t * f, const char *fs) +{ + return apol_query_set(p, &f->fs, NULL, fs); +} + +int apol_fs_use_query_set_behavior(const apol_policy_t * p, apol_fs_use_query_t * f, int behavior) +{ + if (behavior < 0) { + f->behavior = 0; + f->behavior_set = false; + } else { + switch (behavior) { + case QPOL_FS_USE_XATTR: + case QPOL_FS_USE_TASK: + case QPOL_FS_USE_TRANS: + case QPOL_FS_USE_GENFS: + case QPOL_FS_USE_NONE: + case QPOL_FS_USE_PSID: + { + f->behavior = behavior; + f->behavior_set = true; + break; + } + default: + ERR(p, "%s", "Invalid fs_use behavior given."); + return -1; + } + } + return 0; +} + +int apol_fs_use_query_set_context(const apol_policy_t * p __attribute__ ((unused)), + apol_fs_use_query_t * f, apol_context_t * context, unsigned int range_match) +{ + if (f->context != NULL) { + apol_context_destroy(&f->context); + } + f->context = context; + f->flags = (f->flags & ~APOL_QUERY_FLAGS) | range_match; + return 0; +} + +char *apol_fs_use_render(const apol_policy_t * p, const qpol_fs_use_t * fsuse) +{ + char *context_str = NULL; + char *line = NULL, *retval = NULL; + const char *behavior_str = NULL; + const char *fsname = NULL; + const qpol_context_t *ctxt = NULL; + uint32_t behavior; + + if (qpol_fs_use_get_behavior(p->p, fsuse, &behavior)) + goto cleanup; + if ((behavior_str = apol_fs_use_behavior_to_str(behavior)) == NULL) { + ERR(p, "%s", "Could not get behavior string."); + goto cleanup; + } + + if (qpol_fs_use_get_name(p->p, fsuse, &fsname)) + goto cleanup; + + if (behavior == QPOL_FS_USE_PSID) { + context_str = strdup(""); + } else { + if (qpol_fs_use_get_context(p->p, fsuse, &ctxt)) + goto cleanup; + context_str = apol_qpol_context_render(p, ctxt); + if (!context_str) { + goto cleanup; + } + } + if (asprintf(&line, "%s %s %s", behavior_str, fsname, context_str) < 0) { + ERR(p, "%s", strerror(EINVAL)); + goto cleanup; + } + + retval = line; + cleanup: + free(context_str); + if (retval != line) { + free(line); + } + return retval; +} |