diff options
author | Miroslav Grepl <mgrepl@redhat.com> | 2014-04-11 09:37:53 +0200 |
---|---|---|
committer | Miroslav Grepl <mgrepl@redhat.com> | 2014-04-11 09:37:53 +0200 |
commit | 47be9ff57e72906660bb62a515222f482131e1fb (patch) | |
tree | 2cb0ef0ba48d73b1df7cc0915754a17e19464bb6 /sechecker/sechecker.c | |
download | setools-master.tar.gz setools-master.tar.xz setools-master.zip |
Create setools-3.3.7 git repomaster
Diffstat (limited to 'sechecker/sechecker.c')
-rw-r--r-- | sechecker/sechecker.c | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/sechecker/sechecker.c b/sechecker/sechecker.c new file mode 100644 index 0000000..57bb7f1 --- /dev/null +++ b/sechecker/sechecker.c @@ -0,0 +1,1230 @@ +/** + * @file + * Implementation of the public interface for all sechecker modules + * and the library. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2008 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sechecker.h" +#include "register_list.h" +#include "sechk_parse.h" +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <apol/policy.h> +#include <apol/util.h> +#include <apol/vector.h> + +#include <sefs/util.h> +#include <sefs/fcfile.hh> +#include <sefs/query.hh> + +#ifdef LIBSELINUX +#include <selinux/selinux.h> +#endif + +#include <qpol/policy.h> +#include <qpol/util.h> + +static int sechk_lib_compare_sev(const char *a, const char *b) +{ + int aval, bval; + + if (a == NULL || b == NULL) { + assert(false); + errno = EINVAL; + return -1; + } + + if (strcmp(a, SECHK_SEV_NONE) == 0) + aval = 0; + else if (strcmp(a, SECHK_SEV_LOW) == 0) + aval = 1; + else if (strcmp(a, SECHK_SEV_MED) == 0) + aval = 2; + else if (strcmp(a, SECHK_SEV_HIGH) == 0) + aval = 3; + else { + assert(false); + errno = EINVAL; + return -1; + } + + if (strcmp(b, SECHK_SEV_NONE) == 0) + bval = 0; + else if (strcmp(b, SECHK_SEV_LOW) == 0) + bval = 1; + else if (strcmp(b, SECHK_SEV_MED) == 0) + bval = 2; + else if (strcmp(b, SECHK_SEV_HIGH) == 0) + bval = 3; + else { + assert(false); + errno = EINVAL; + return -1; + } + + if (aval == bval) + return 0; + + return aval < bval ? -1 : 1; +} + +int sechk_lib_set_minsev(const char *minsev, sechk_lib_t * lib) +{ + if (lib == NULL || lib->policy == NULL || minsev == NULL) { + assert(false); + errno = EINVAL; + return -1; + } + + if (strcmp(minsev, SECHK_SEV_LOW) == 0) + lib->minsev = SECHK_SEV_LOW; + else if (strcmp(minsev, SECHK_SEV_MED) == 0) + lib->minsev = SECHK_SEV_MED; + else if (strcmp(minsev, SECHK_SEV_HIGH) == 0) + lib->minsev = SECHK_SEV_HIGH; + else { + ERR(lib->policy, "%s", "Invalid severity."); + errno = EINVAL; + return -1; + } + return 0; +} + +sechk_module_t *sechk_module_new(void) +{ + sechk_module_t *mod = NULL; + int error = 0; + + mod = calloc(1, sizeof(sechk_module_t)); + if (!mod) + return NULL; + + /* create empty vectors */ + if (!(mod->options = apol_vector_create(sechk_name_value_free)) || + !(mod->requirements = apol_vector_create(sechk_name_value_free)) || + !(mod->dependencies = apol_vector_create(sechk_name_value_free)) + || !(mod->functions = apol_vector_create(sechk_fn_free))) { + error = errno; + apol_vector_destroy(&mod->options); + apol_vector_destroy(&mod->requirements); + apol_vector_destroy(&mod->dependencies); + apol_vector_destroy(&mod->functions); + free(mod); + errno = error; + return NULL; + } + + return mod; +} + +sechk_lib_t *sechk_lib_new(void) +{ + sechk_lib_t *lib = NULL; + int retv, error; + const sechk_module_name_reg_t *reg_list; + size_t num_known_modules = 0; + size_t i = 0; + sechk_module_t *tmp = NULL; + + /* allocate the new sechk_lib_t structure */ + lib = (sechk_lib_t *) calloc(1, sizeof(sechk_lib_t)); + if (!lib) { + error = errno; + perror("Error creating module library"); + goto exit_err; + } + + /* create the module array from the known modules in register list */ + num_known_modules = sechk_register_list_get_num_modules(); + reg_list = sechk_register_list_get_modules(); + lib->modules = apol_vector_create(sechk_module_free); + if (!lib->modules) { + error = errno; + perror("Error adding modules"); + goto exit_err; + + } + for (i = 0; i < num_known_modules; i++) { + tmp = sechk_module_new(); + if (!tmp) { + error = errno; + perror("Error adding modules"); + goto exit_err; + } + tmp->name = strdup(reg_list[i].name); + if (!tmp->name) { + error = errno; + perror("Error adding modules"); + goto exit_err; + } + if (apol_vector_append(lib->modules, tmp)) { + error = errno; + perror("Error adding modules"); + goto exit_err; + } + tmp = NULL; + } + + /* set the default output format */ + lib->outputformat = SECHK_OUT_SHORT; + lib->minsev = SECHK_SEV_LOW; + + /* register modules */ + if ((retv = sechk_lib_register_modules(reg_list, lib)) != 0) { + error = errno; + perror("Error registering modules"); + goto exit_err; + } + exit: + return lib; + + exit_err: + sechk_lib_destroy(&lib); + sechk_module_free(tmp); + errno = error; + goto exit; +} + +void sechk_lib_destroy(sechk_lib_t ** lib) +{ + if (lib == NULL || *lib == NULL) + return; + + apol_vector_destroy(&((*lib)->modules)); + apol_policy_destroy(&((*lib)->policy)); + apol_vector_destroy(&((*lib)->fc_entries)); + free((*lib)->fc_path); + sefs_fclist_destroy(&((*lib)->fc_file)); + free((*lib)->selinux_config_path); + apol_policy_path_destroy(&((*lib)->policy_path)); + free(*lib); + *lib = NULL; +} + +void sechk_module_free(void *module) +{ + sechk_module_t *mod = (sechk_module_t *) module; + + if (!module) + return; + + /* do not free describtin fields */ + sechk_result_destroy(&mod->result); + apol_vector_destroy(&mod->options); + apol_vector_destroy(&mod->requirements); + apol_vector_destroy(&mod->dependencies); + /* do not free severity */ + if (mod->data) { + assert(mod->data_free); + mod->data_free(mod->data); + } + free(mod->name); + mod->name = NULL; + apol_vector_destroy(&mod->functions); + free(mod); +} + +void sechk_fn_free(void *fn_struct) +{ + sechk_fn_t *fn = (sechk_fn_t *) fn_struct; + if (!fn_struct) + return; + + free(fn->name); + /* NEVER free fn->fn */ + free(fn); +} + +void sechk_name_value_free(void *nv) +{ + sechk_name_value_t *in = (sechk_name_value_t *) nv; + if (!nv) + return; + + free(in->name); + free(in->value); + free(nv); +} + +void sechk_result_destroy(sechk_result_t ** res) +{ + if (!res || !(*res)) + return; + + free((*res)->test_name); + apol_vector_destroy(&((*res)->items)); + free(*res); + *res = NULL; +} + +void sechk_item_free(void *item) +{ + sechk_item_t *it = (sechk_item_t *) item; + + if (!item) + return; + + apol_vector_destroy(&it->proof); + if (it->item_free_fn) + it->item_free_fn(it->item); + + free(item); +} + +void sechk_proof_free(void *proof) +{ + sechk_proof_t *p = (sechk_proof_t *) proof; + + if (!proof) + return; + + free(p->text); + free(p->xml_out); + + if (p->elem_free_fn) + p->elem_free_fn(p->elem); + + free(proof); +} + +sechk_fn_t *sechk_fn_new(void) +{ + /* no initialization needed here */ + return (sechk_fn_t *) calloc(1, sizeof(sechk_fn_t)); +} + +sechk_name_value_t *sechk_name_value_new(const char *name, const char *value) +{ + sechk_name_value_t *nv; + int error; + + nv = (sechk_name_value_t *) calloc(1, sizeof(sechk_name_value_t)); + if (!nv) + return NULL; + if (name) { + nv->name = strdup(name); + if (!nv->name) { + error = errno; + goto err; + } + } + if (value) { + nv->value = strdup(value); + if (!nv->value) { + error = errno; + goto err; + } + } + + return nv; + + err: + free(nv->name); + free(nv); + errno = error; + return NULL; +} + +sechk_result_t *sechk_result_new(void) +{ + /* initilization to zero is sufficient here */ + return (sechk_result_t *) calloc(1, sizeof(sechk_result_t)); +} + +sechk_item_t *sechk_item_new(free_fn_t fn) +{ + sechk_item_t *it = NULL; + + it = (sechk_item_t *) calloc(1, sizeof(sechk_item_t)); + if (!it) + return NULL; + it->item_free_fn = fn; + + return it; +} + +sechk_proof_t *sechk_proof_new(free_fn_t fn) +{ + sechk_proof_t *proof = NULL; + proof = (sechk_proof_t *) calloc(1, sizeof(sechk_proof_t)); + if (!proof) + return NULL; + proof->type = SECHK_ITEM_NONE; + proof->elem_free_fn = fn; + return proof; +} + +int sechk_lib_load_policy(apol_policy_path_t * policy_mods, sechk_lib_t * lib) +{ + + char *default_policy_path = NULL; + int retv = -1; + + if (!lib) + return -1; + + /* if no policy is given, attempt to find default */ + if (!policy_mods) { + retv = qpol_default_policy_find(&default_policy_path); + if (retv < 0) { + fprintf(stderr, "Default policy search failed: %s\n", strerror(errno)); + return -1; + } else if (retv != 0) { + fprintf(stderr, "No default policy found.\n"); + return -1; + } + policy_mods = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, default_policy_path, NULL); + lib->policy = apol_policy_create_from_policy_path(policy_mods, QPOL_POLICY_OPTION_MATCH_SYSTEM, NULL, NULL); + if (lib->policy == NULL) { + fprintf(stderr, "Error: failed opening default policy\n"); + return -1; + } + lib->policy_path = policy_mods; + if (!(lib->outputformat & SECHK_OUT_QUIET)) { + fprintf(stderr, "Using policy: %s\n", apol_policy_path_get_primary(lib->policy_path)); + } + } else { + lib->policy_path = policy_mods; + lib->policy = apol_policy_create_from_policy_path(policy_mods, 0, NULL, NULL); + if (lib->policy == NULL) { + fprintf(stderr, "Error: failed opening policy %s\n", apol_policy_path_to_string(lib->policy_path)); + goto err; + } + } + return 0; + + err: + apol_policy_destroy(&lib->policy); + return -1; +} + +int sechk_lib_load_fc(const char *fcfilelocation, sechk_lib_t * lib) +{ + int error = 0; + char *default_fc_path = NULL; + sefs_fclist_t *fcfile = NULL; + sefs_query_t *q = NULL; + + /* if no policy we can't parse the fc file */ + if (!lib || !lib->policy) { + errno = EINVAL; + return -1; + } + + /* if no file_contexts file is given attempt to find the default */ + if (!fcfilelocation) { + default_fc_path = sefs_default_file_contexts_get_path(); + if (default_fc_path == NULL) { + error = errno; + WARN(lib->policy, "Unable to find default file_contexts file: %s", strerror(error)); + errno = error; + return 0; /* not fatal error until a module requires this to exist */ + } + if (strcmp(default_fc_path, "") == 0) { + WARN(lib->policy, "%s", "The system has no default file_contexts file."); + free(default_fc_path); + errno = ENOSYS; + return 0; /* not fatal error until a module requires this to exist */ + } + fcfile = sefs_fcfile_create_from_file(default_fc_path, NULL, NULL); + q = sefs_query_create(); + lib->fc_entries = sefs_fclist_run_query(fcfile, q); + if (!(lib->fc_entries)) { + error = errno; + WARN(lib->policy, "Unable to process file_contexts file %s.", default_fc_path); + free(default_fc_path); + errno = error; + return -1; + } else { + lib->fc_path = default_fc_path; + lib->fc_file = fcfile; + } + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + fprintf(stderr, "Using file contexts: %s\n", lib->fc_path); + } + } else { + fcfile = sefs_fcfile_create_from_file(fcfilelocation, NULL, NULL); + q = sefs_query_create(); + lib->fc_entries = sefs_fclist_run_query(fcfile, q); + if (!(lib->fc_entries)) { + error = errno; + WARN(lib->policy, "Unable to process file_contexts file %s.", fcfilelocation); + errno = error; + return -1; + } else { + lib->fc_path = strdup(fcfilelocation); + lib->fc_file = fcfile; + } + } + sefs_query_destroy(&q); + + return 0; +} + +int sechk_lib_register_modules(const sechk_module_name_reg_t * register_fns, sechk_lib_t * lib) +{ + int retv, error = 0; + size_t i; + sechk_register_fn_t fn = NULL; + if (!register_fns || !lib) { + fprintf(stderr, "Error: could not register modules\n"); + errno = EINVAL; + return -1; + } + if (apol_vector_get_size(lib->modules) != sechk_register_list_get_num_modules()) { + fprintf(stderr, + "Error: the number of registered modules (%zd) does not match the number of modules in the configuration file (%zd).\n", + sechk_register_list_get_num_modules(), apol_vector_get_size(lib->modules)); + errno = EINVAL; + return -1; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + fn = (sechk_register_fn_t) (register_fns[i].fn); + retv = fn(lib); + if (retv) { + error = errno; + fprintf(stderr, "Error: could not register module #%zd\n", i); + errno = error; + return retv; + } + } + + return 0; +} + +sechk_mod_fn_t sechk_lib_get_module_function(const char *module_name, const char *function_name, const sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + size_t i; + + if (!module_name || !function_name || !lib) { + fprintf(stderr, "Error: failed to get function from module\n"); + errno = EINVAL; + return NULL; + } + + /* find the correct module */ + mod = sechk_lib_get_module(module_name, lib); + if (!mod) { + fprintf(stderr, "Error: %s: no such module\n", module_name); + errno = ENOENT; + return NULL; + } + + /* find function in module */ + for (i = 0; i < apol_vector_get_size(mod->functions); i++) { + fn_struct = apol_vector_get_element(mod->functions, i); + if (!strcmp(fn_struct->name, function_name)) + break; + else + fn_struct = NULL; + } + if (!fn_struct) { + fprintf(stderr, "Error: %s: no such function in module %s\n", function_name, module_name); + errno = ENOENT; + return NULL; + } + + return fn_struct->fn; +} + +sechk_module_t *sechk_lib_get_module(const char *module_name, const sechk_lib_t * lib) +{ + size_t i; + sechk_module_t *mod = NULL; + + if (!module_name || !lib) { + fprintf(stderr, "Error: failed to get module\n"); + errno = EINVAL; + return NULL; + } + + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (!(mod->name)) + continue; + if (!strcmp(mod->name, module_name)) + return mod; + } + fprintf(stderr, "Error: %s: no such module\n", module_name); + errno = ENOENT; + return NULL; +} + +sechk_result_t *sechk_lib_get_module_result(const char *module_name, const sechk_lib_t * lib) +{ + size_t i; + sechk_module_t *mod = NULL; + sechk_mod_fn_t run = NULL; + + if (!module_name || !lib) { + fprintf(stderr, "Error: failed to get module result\n"); + errno = EINVAL; + return NULL; + } + + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (!(mod->name)) + continue; + if (strcmp(mod->name, module_name)) + continue; + if (!(mod->result)) { + if (!(run = sechk_lib_get_module_function(module_name, SECHK_MOD_FN_RUN, lib)) || + run(mod, lib->policy, NULL) < 0) { + return NULL; /* run or get function will set errno */ + } + } + return mod->result; + } + fprintf(stderr, "Error: %s: no such module\n", module_name); + errno = ENOENT; + return NULL; +} + +int sechk_lib_check_module_dependencies(sechk_lib_t * lib) +{ + int idx = 0; + size_t i, j; + bool test = true, done = false, *processed = NULL; + sechk_name_value_t *nv = NULL; + sechk_module_t *mod = NULL, *dep = NULL; + + if (!lib) { + fprintf(stderr, "Error: invalid module library\n"); + errno = EINVAL; + return -1; + } + + processed = (bool *) calloc(apol_vector_get_size(lib->modules), sizeof(bool)); + if (!processed) { + perror(NULL); + return -1; + } + + /* check dependencies and select dependencies to be run */ + while (!done) { + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + if (processed[i]) + continue; + mod = apol_vector_get_element(lib->modules, i); + if (!mod->selected) { + processed[i] = true; + continue; + } + for (j = 0; j < apol_vector_get_size(mod->dependencies); j++) { + nv = apol_vector_get_element(mod->dependencies, j); + test = false; + test = sechk_lib_check_dependency(nv, lib); + if (!test) { + ERR(lib->policy, "Dependency %s not found for %s.", nv->name, mod->name); + free(processed); + errno = ENOENT; + return -1; + } + idx = sechk_lib_get_module_idx(nv->value, lib); + dep = apol_vector_get_element(lib->modules, idx); + if (!dep->selected) { + processed[idx] = false; + dep->selected = true; + } + } + processed[i] = true; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + if (!processed[i]) + break; + } + if (i == apol_vector_get_size(lib->modules)) + done = true; + } + free(processed); + + return 0; +} + +int sechk_lib_check_module_requirements(sechk_lib_t * lib) +{ + int retv = 0; + size_t i, j; + bool test = true; + sechk_name_value_t *nv = NULL; + sechk_module_t *mod = NULL; + + /* check requirements for all selected modules */ + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (!mod->selected) + continue; + for (j = 0; j < apol_vector_get_size(mod->requirements); j++) { + nv = apol_vector_get_element(mod->requirements, j); + test = false; + test = sechk_lib_check_requirement(nv, lib); + if (!test) { + /* if we're in quiet mode then we quit on a failed requirement */ + if (lib->outputformat & (SECHK_OUT_QUIET)) { + errno = ENOTSUP; + return -1; + } else { + /* otherwise we just disable this module and keep testing */ + ERR(lib->policy, "Requirements not met for %s.", mod->name); + mod->selected = false; + retv = -1; + break; + } + } + } + } + return retv; +} + +int sechk_lib_init_modules(sechk_lib_t * lib) +{ + int retv, error = 0; + size_t i; + sechk_module_t *mod = NULL; + sechk_mod_fn_t init_fn = NULL; + + if (lib == NULL || lib->modules == NULL) { + errno = EINVAL; + return -1; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (!mod->selected) + continue; + init_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_INIT, lib); + if (!init_fn) { + error = errno; + fprintf(stderr, "Error: could not initialize module %s\n", mod->name); + errno = error; + return -1; + } + retv = init_fn(mod, lib->policy, NULL); + if (retv) + return retv; + } + + return 0; +} + +int sechk_lib_run_modules(sechk_lib_t * lib) +{ + int retv, num_selected = 0, rc = 0; + size_t i; + sechk_module_t *mod = NULL; + sechk_mod_fn_t run_fn = NULL; + + if (!lib) { + fprintf(stderr, "Error: invalid library\n"); + errno = EINVAL; + return -1; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (mod->selected) + num_selected++; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + /* if module is "off" do not run */ + if (!mod->selected) + continue; + /* if module is below the minsev do not run unless its exactly one module */ + if (lib->minsev && sechk_lib_compare_sev(mod->severity, lib->minsev) < 0 && num_selected != 1) + continue; + assert(mod->name); + run_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_RUN, lib); + if (!run_fn) { + ERR(lib->policy, "Could not run module %s.", mod->name); + errno = ENOTSUP; + return -1; + } + retv = run_fn(mod, lib->policy, NULL); + + if (retv < 0) { + /* module failure */ + /* only put output failures if we are not in quiet mode */ + if (lib->outputformat & ~(SECHK_OUT_QUIET)) + ERR(lib->policy, "Module %s failed.", mod->name); + rc = -1; + } else if (retv > 0) { + /* a module looking for policy errors has found one + * if in quiet mode stop since running additional + * modules will not change the return code */ + if (lib->outputformat & (SECHK_OUT_QUIET)) + return -1; + } + } + return rc; +} + +int sechk_lib_print_modules_report(sechk_lib_t * lib) +{ + int retv, num_selected = 0, rc = 0; + size_t i; + sechk_module_t *mod = NULL; + sechk_mod_fn_t print_fn = NULL; + + if (!lib) { + fprintf(stderr, "Error: invalid library\n"); + errno = EINVAL; + return -1; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (mod->selected) + num_selected++; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + /* if module is "off" or its output format is quiet continue */ + if (!mod->selected || mod->outputformat & SECHK_OUT_QUIET) + continue; + /* if module is below the minsev do not print unless exactly one module is selected */ + if (lib->minsev && sechk_lib_compare_sev(mod->severity, lib->minsev) < 0 && num_selected != 1) + continue; + /* if module is the only selected one make sure output is generated */ + if (mod->outputformat == SECHK_OUT_NONE && num_selected == 1) + mod->outputformat = SECHK_OUT_SHORT; + assert(mod->name); + printf("\nModule name: %s\tSeverity: %s\n%s\n", mod->name, mod->severity, mod->detailed_description); + print_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_PRINT, lib); + if (!print_fn) { + ERR(lib->policy, "Could not get print function for module %s.", mod->name); + errno = ENOTSUP; + return -1; + } + retv = print_fn(mod, lib->policy, NULL); + if (retv) { + fprintf(stderr, "Error: unable to print results for module %s \n", mod->name); + rc = -1; + } + } + + return rc; +} + +bool sechk_lib_check_requirement(sechk_name_value_t * req, sechk_lib_t * lib) +{ + struct stat stat_buf; + + if (!req) { + fprintf(stderr, "Error: invalid requirement\n"); + errno = EINVAL; + return false; + } + + if (!lib || !lib->policy) { + fprintf(stderr, "Error: invalid library\n"); + errno = EINVAL; + return false; + } + + if (!strcmp(req->name, SECHK_REQ_POLICY_CAP)) { + if (!strcmp(req->value, SECHK_REQ_CAP_ATTRIB_NAMES)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_ATTRIB_NAMES)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_MLS)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_MLS)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_SYN_RULES)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_SYN_RULES)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_RULES_LOADED)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_RULES_LOADED)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_LINE_NOS)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_LINE_NUMBERS)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_CONDITIONALS)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_CONDITIONALS)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else if (!strcmp(req->value, SECHK_REQ_CAP_MODULES)) { + if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_MODULES)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + } + return false; + } + } else { + ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value); + return false; + } + } else if (!strcmp(req->name, SECHK_REQ_DEFAULT_CONTEXTS)) { +#ifdef LIBSELINUX + if (stat(selinux_default_context_path(), &stat_buf) < 0) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s not met.", req->name); + } + return false; + } +#else + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Checking requirement %s: %s", req->name, strerror(ENOTSUP)); + } + return false; +#endif + } else if (!strcmp(req->name, SECHK_REQ_FILE_CONTEXTS)) { + if (!lib->fc_entries || !apol_vector_get_size(lib->fc_entries)) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) { + ERR(lib->policy, "Requirement %s not met.", req->name); + } + } + } else if (!strcmp(req->name, SECHK_REQ_SYSTEM)) { + if (!strcmp(req->value, SECHK_REQ_SYS_SELINUX)) { +#ifdef LIBSELINUX + if (!is_selinux_mls_enabled() || !is_selinux_enabled()) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + return false; + } +#else + if (lib->outputformat & ~(SECHK_OUT_QUIET)) + ERR(lib->policy, "Checking requirement %s, %s: %s", req->name, req->value, strerror(ENOTSUP)); + return false; +#endif + } else if (!strcmp(req->value, SECHK_REQ_SYS_MLS)) { +#ifdef LIBSELINUX + if (!is_selinux_mls_enabled() || !is_selinux_enabled()) { + if (lib->outputformat & ~(SECHK_OUT_QUIET)) + ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value); + return false; + } +#else + if (lib->outputformat & ~(SECHK_OUT_QUIET)) + ERR(lib->policy, "Checking requirement %s, %s: %s", req->name, req->value, strerror(ENOTSUP)); + return false; +#endif + } else { + ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value); + return false; + } + } else { + ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value); + return false; + } + + return true; +} + +bool sechk_lib_check_dependency(sechk_name_value_t * dep, sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + + if (!dep || !dep->value) { + fprintf(stderr, "Error: invalid dependency\n"); + errno = EINVAL; + return false; + } + + if (!lib) { + fprintf(stderr, "Error: invalid library\n"); + errno = EINVAL; + return false; + } + + mod = sechk_lib_get_module(dep->value, lib); + if (!mod) { + fprintf(stderr, "Error: could not find dependency %s\n", dep->value); + errno = ENOENT; + return false; + } + + return true; +} + +int sechk_lib_set_outputformat(unsigned char out, sechk_lib_t * lib) +{ + size_t i; + sechk_module_t *mod = NULL; + + if (!lib || !out) { + errno = EINVAL; + return -1; + } + + lib->outputformat = out; + + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + mod->outputformat = out; + } + + return 0; +} + +sechk_proof_t *sechk_proof_copy(sechk_proof_t * orig) +{ + sechk_proof_t *copy = NULL; + + if (!orig) + return NULL; + + copy = sechk_proof_new(orig->elem_free_fn); + if (!copy) { + fprintf(stderr, "Error: out of memory\n"); + errno = ENOMEM; + return NULL; + } + + copy->elem = orig->elem; + copy->type = orig->type; + copy->text = strdup(orig->text); + if (!copy->text) { + fprintf(stderr, "Error: out of memory\n"); + errno = ENOMEM; + return NULL; + } + copy->xml_out = NULL; /* TODO: do xml string copy here */ + + return copy; +} + +int sechk_lib_load_profile(const char *prof_name, sechk_lib_t * lib) +{ + const sechk_profile_name_reg_t *profiles; + char *profpath = NULL, *prof_filename = NULL, *path = NULL; + int retv = -1, error = 0; + size_t num_profiles, i; + sechk_module_t *mod = NULL; + + if (!prof_name || !lib) { + fprintf(stderr, "Error: invalid parameters to load profile\n"); + return -1; + } + + /* try to find the profile in our known profiles */ + profiles = sechk_register_list_get_profiles(); + num_profiles = sechk_register_list_get_num_profiles(); + for (i = 0; i < num_profiles; i++) { + if (strcmp(profiles[i].name, prof_name) == 0) { + break; + } + } + /* this is a known installed profile, look for it in that directory */ + if (i < num_profiles) { + /* first look in the local subdir using just PROF_SUBDIR/profile */ + prof_filename = (char *)calloc(strlen(profiles[i].file) + 4 + strlen(PROF_SUBDIR), sizeof(char)); + if (!prof_filename) { + fprintf(stderr, "Error: out of memory\n"); + errno = ENOMEM; + return -1; + } + sprintf(prof_filename, "%s/%s", PROF_SUBDIR, profiles[i].file); + path = apol_file_find(prof_filename); + if (!path) { + free(prof_filename); + prof_filename = NULL; + prof_filename = (char *)calloc(strlen(PROFILE_INSTALL_DIR) + strlen(profiles[i].file) + 4, sizeof(char)); + if (!prof_filename) { + fprintf(stderr, "Error: out of memory\n"); + errno = ENOMEM; + return -1; + } + sprintf(prof_filename, "%s/%s", PROFILE_INSTALL_DIR, profiles[i].file); + path = apol_file_find(prof_filename); + if (!path) { + fprintf(stderr, "Error: Unable to find path\n"); + error = ENOENT; + goto sechk_load_profile_error; + } + } + + /* concatenate path and filename */ + profpath = (char *)calloc(3 + strlen(path) + strlen(prof_filename), sizeof(char)); + if (!profpath) { + fprintf(stderr, "Error: out of memory\n"); + error = ENOMEM; + goto sechk_load_profile_error; + } + sprintf(profpath, "%s/%s", path, prof_filename); + free(path); + free(prof_filename); + path = NULL; + prof_filename = NULL; + } else { + profpath = strdup(prof_name); + } + + /* parse the profile */ + retv = sechk_lib_parse_profile(profpath, lib); + if (retv) { + error = errno; + fprintf(stderr, "Error: could not parse profile\n"); + goto sechk_load_profile_error; + } + + /* turn off output for any unselected modules */ + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (!mod->selected) + mod->outputformat = SECHK_OUT_NONE; + } + + free(profpath); + free(prof_filename); + free(path); + return 0; + + sechk_load_profile_error: + free(profpath); + free(prof_filename); + free(path); + errno = error; + return -1; +} + +static int sechk_option_name_compare(const void *a, const void *b, void *data __attribute__ ((unused))) +{ + sechk_name_value_t *in_a, *in_b; + + in_a = (sechk_name_value_t *) a; + in_b = (sechk_name_value_t *) b; + + return strcmp(in_a->name, in_b->name); +} + +int sechk_lib_module_clear_option(sechk_module_t * module, char *option) +{ + apol_vector_t *new_opts = NULL; + sechk_name_value_t *needle = NULL, *nv = NULL, *tmp = NULL; + int error = 0; + size_t i = 0; + + if (!module || !option) { + errno = EINVAL; + return -1; + } + + if (!(needle = sechk_name_value_new(option, NULL))) { + error = errno; + ERR(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error)); + errno = error; + return -1; + } + + /* if not here nothing to do */ + if (apol_vector_get_index(module->options, needle, sechk_option_name_compare, NULL, &i) < 0) { + sechk_name_value_free(needle); + return 0; + } + + if (!(new_opts = apol_vector_create(sechk_name_value_free))) { + error = errno; + ERR(module->parent_lib->policy, "%s", strerror(error)); + errno = error; + return -1; + } + + /* add all options of a different name to a new vector to replace the old */ + for (i = 0; i < apol_vector_get_size(module->options); i++) { + nv = apol_vector_get_element(module->options, i); + if (strcmp(nv->name, needle->name)) { + if (!(tmp = sechk_name_value_new(nv->name, nv->value))) { + error = errno; + WARN(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error)); + goto err; + } + if (apol_vector_append(new_opts, (void *)tmp)) { + error = errno; + WARN(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error)); + goto err; + } + tmp = NULL; /* avoid double free */ + } + } + + sechk_name_value_free(needle); + apol_vector_destroy(&module->options); + module->options = new_opts; + + return 0; + + err: + sechk_name_value_free(tmp); + sechk_name_value_free(needle); + apol_vector_destroy(&new_opts); + errno = error; + return -1; +} + +/* get the index of a module in the library by name */ +int sechk_lib_get_module_idx(const char *name, sechk_lib_t * lib) +{ + size_t i; + sechk_module_t *mod = NULL; + + if (!name || !lib || !lib->modules) { + errno = EINVAL; + return -1; + } + for (i = 0; i < apol_vector_get_size(lib->modules); i++) { + mod = apol_vector_get_element(lib->modules, i); + if (mod->name && !strcmp(name, mod->name)) + return i; + } + errno = ENOENT; + return -1; +} + +int sechk_proof_with_element_compare(const void *in_proof, const void *elem, void *unused __attribute__ ((unused))) +{ + const sechk_proof_t *proof = (const sechk_proof_t *)in_proof; + + if (!proof) + return 1; + + /* explicit pointer to integer cast */ + return (int)((char *)proof->elem - (char *)elem); +} |