diff options
Diffstat (limited to 'sechecker/modules')
48 files changed, 14656 insertions, 0 deletions
diff --git a/sechecker/modules/attribs_wo_rules.c b/sechecker/modules/attribs_wo_rules.c new file mode 100644 index 0000000..4f2c00e --- /dev/null +++ b/sechecker/modules/attribs_wo_rules.c @@ -0,0 +1,520 @@ +/** + * @file + * Implementation of the attributes without rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "attribs_wo_rules.h" +#include <apol/type-query.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "attribs_wo_rules"; + +/* The register function registers all of a module's functions + * with the library. */ +int attribs_wo_rules_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "attributes not used in any rule"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds attributes in the policy that are not used in any rules; These\n" + "attributes will get thrown out by the compiler and have no effect on the \n" + "security environment. They are unnecessary and should be removed.\n"; + mod->opt_description = + "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n" + " none\n"; + mod->severity = SECHK_SEV_LOW; + /* assign requirements */ + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_rules_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_rules_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_rules_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = &attribs_wo_rules_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. */ +int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *attr_vector; + apol_role_query_t *role_query = NULL; + apol_avrule_query_t *avrule_query = NULL; + apol_terule_query_t *terule_query = NULL; + apol_vector_t *avrule_vector; + apol_vector_t *terule_vector; + apol_vector_t *role_vector; + qpol_iterator_t *constraint_iter; + qpol_iterator_t *node_iter = NULL; + qpol_iterator_t *name_iter = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int found = 0, error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + res->item_type = SECHK_ITEM_ATTRIB; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + + if (!(avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + if (!(terule_query = apol_terule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + if (!(role_query = apol_role_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + + apol_attr_get_by_query(policy, NULL, &attr_vector); + for (i = 0; i < apol_vector_get_size(attr_vector); i++) { + qpol_type_t *attr; + const char *attr_name; + attr = apol_vector_get_element(attr_vector, i); + qpol_type_get_name(q, attr, &attr_name); + + /* access rules */ + apol_avrule_query_set_source(policy, avrule_query, attr_name, 0); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + if (apol_vector_get_size(avrule_vector) > 0) { + apol_vector_destroy(&avrule_vector); + continue; + } + apol_vector_destroy(&avrule_vector); + + apol_avrule_query_set_source(policy, avrule_query, NULL, 0); + apol_avrule_query_set_target(policy, avrule_query, attr_name, 0); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + if (apol_vector_get_size(avrule_vector) > 0) { + apol_vector_destroy(&avrule_vector); + continue; + } + apol_avrule_query_set_target(policy, avrule_query, NULL, 0); + apol_vector_destroy(&avrule_vector); + + /* type rules */ + apol_terule_query_set_source(policy, terule_query, attr_name, 0); + apol_terule_get_by_query(policy, terule_query, &terule_vector); + if (apol_vector_get_size(terule_vector) > 0) { + apol_vector_destroy(&terule_vector); + continue; + } + apol_vector_destroy(&terule_vector); + + apol_terule_query_set_source(policy, terule_query, NULL, 0); + apol_terule_query_set_target(policy, terule_query, attr_name, 0); + apol_terule_get_by_query(policy, terule_query, &terule_vector); + if (apol_vector_get_size(terule_vector) > 0) { + apol_vector_destroy(&terule_vector); + continue; + } + apol_terule_query_set_target(policy, terule_query, NULL, 0); + apol_vector_destroy(&terule_vector); + + /* role trans */ + apol_role_query_set_type(policy, role_query, attr_name); + apol_role_get_by_query(policy, role_query, &role_vector); + if (apol_vector_get_size(role_vector) > 0) { + apol_vector_destroy(&role_vector); + continue; + } + apol_vector_destroy(&role_vector); + + /* Check constraints */ + constraint_iter = NULL; + node_iter = NULL; + name_iter = NULL; + found = 0; + qpol_policy_get_constraint_iter(q, &constraint_iter); + for (; !qpol_iterator_end(constraint_iter); qpol_iterator_next(constraint_iter)) { + qpol_constraint_t *constraint; + + qpol_iterator_get_item(constraint_iter, (void **)&constraint); + qpol_constraint_get_expr_iter(q, constraint, &node_iter); + + for (; !qpol_iterator_end(node_iter); qpol_iterator_next(node_iter)) { + qpol_constraint_expr_node_t *constraint_node; + uint32_t node_type; + + qpol_iterator_get_item(node_iter, (void **)&constraint_node); + qpol_constraint_expr_node_get_expr_type(q, constraint_node, &node_type); + + if (node_type == QPOL_CEXPR_TYPE_NAMES) { + qpol_constraint_expr_node_get_names_iter(q, constraint_node, &name_iter); + + for (; !qpol_iterator_end(name_iter); qpol_iterator_next(name_iter)) { + char *name; + + qpol_iterator_get_item(name_iter, (void **)&name); + if (!strcmp(name, attr_name)) { + found = 1; + free(name); + name = NULL; + break; + } + free(name); + name = NULL; + } + qpol_iterator_destroy(&name_iter); + if (found) + break; + } + } + qpol_iterator_destroy(&node_iter); + free(constraint); + if (found) + break; + } + qpol_iterator_destroy(&constraint_iter); + if (found) + continue; + + /* if we get here then the attrib was not found anywhere in a rule so add it */ + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + item->test_result = 1; + item->item = (void *)attr; + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + proof->type = SECHK_ITEM_ATTRIB; + proof->text = strdup("attribute was not used in any rules."); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_rules_run_fail; + } + } + apol_avrule_query_destroy(&avrule_query); + apol_role_query_destroy(&role_query); + apol_terule_query_destroy(&terule_query); + apol_vector_destroy(&attr_vector); + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + attribs_wo_rules_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd attributes.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following attributes do not appear in any rules.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + type = NULL; + type_name = NULL; + + return 0; +} + +int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/attribs_wo_rules.h b/sechecker/modules/attribs_wo_rules.h new file mode 100644 index 0000000..e2869d5 --- /dev/null +++ b/sechecker/modules/attribs_wo_rules.h @@ -0,0 +1,63 @@ +/** + * @file + * Defines the interface for the attributes without rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef ATTRIBS_WO_RULES +#define ATTRIBS_WO_RULES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/role-query.h> +#include <apol/avrule-query.h> +#include <apol/terule-query.h> +#include <apol/type-query.h> + +/* Module functions: + * Do not change any of these prototypes or you will not be + * able to run the module in the library + * NOTE: while using a modular format SEChecker is built + * statically; this means that all modules and their functions + * are in the same namespace. */ + int attribs_wo_rules_register(sechk_lib_t * lib); + int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +/* NOTE: While SEChecker is build statically, it is + * intended that no module directly call a function + * from another but instead use get_module_function() + * to get the desired function from the library. */ + + int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/attribs_wo_types.c b/sechecker/modules/attribs_wo_types.c new file mode 100644 index 0000000..edac010 --- /dev/null +++ b/sechecker/modules/attribs_wo_types.c @@ -0,0 +1,399 @@ +/** + * @file + * Implementation of the attributes without types module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "attribs_wo_types.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "attribs_wo_types"; + +/* The register function registers all of a module's functions + * with the library. */ +int attribs_wo_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "attributes with no types"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds attributes in the policy that are not associated with any\n" + "types. Attributes without types can cause type fields in rules to expand to\n" + "empty sets and thus become unreachable. This makes for misleading policy source\n" "files.\n"; + mod->opt_description = + "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n" + " none\n"; + mod->severity = SECHK_SEV_LOW; + /* assign requirements */ + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_types_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_types_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_types_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = attribs_wo_types_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *attr_vector = NULL; + qpol_iterator_t *types = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + res->item_type = SECHK_ITEM_ATTRIB; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + + apol_attr_get_by_query(policy, NULL, &attr_vector); + for (i = 0; i < apol_vector_get_size(attr_vector); i++) { + qpol_type_t *attr; + const char *attr_name; + int at_end; + + attr = apol_vector_get_element(attr_vector, i); + qpol_type_get_name(q, attr, &attr_name); + qpol_type_get_type_iter(q, attr, &types); + at_end = qpol_iterator_end(types); + qpol_iterator_destroy(&types); + if (!at_end) + continue; + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + proof->type = SECHK_ITEM_ATTRIB; + proof->text = (char *)calloc(strlen("attribute has no types") + strlen(attr_name) + 1, sizeof(char)); + sprintf(proof->text, "attribute %s has no types", attr_name); + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + } + item->item = (void *)attr; + item->test_result = 1; + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto attribs_wo_types_run_fail; + } + } + qpol_iterator_destroy(&types); + apol_vector_destroy(&attr_vector); + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + attribs_wo_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + /* display the statistics of the results */ + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd attributes.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following attributes are not associated with any types.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + type = NULL; + type_name = NULL; + + return 0; +} + +int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * polciy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/attribs_wo_types.h b/sechecker/modules/attribs_wo_types.h new file mode 100644 index 0000000..da11801 --- /dev/null +++ b/sechecker/modules/attribs_wo_types.h @@ -0,0 +1,48 @@ +/** + * @file + * Defines the interface for the attributes without types module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef ATTRIBS_WO_TYPES +#define ATTRIBS_WO_TYPES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/type-query.h> + + int attribs_wo_types_register(sechk_lib_t * lib); + int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/domain_and_file.c b/sechecker/modules/domain_and_file.c new file mode 100644 index 0000000..418e2a5 --- /dev/null +++ b/sechecker/modules/domain_and_file.c @@ -0,0 +1,398 @@ +/** + * @file + * Implementation of the domain and file type module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "domain_and_file.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "domain_and_file"; + +int domain_and_file_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + sechk_name_value_t *nv = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign descriptions */ + mod->brief_description = "types treated as a domain and file type"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in the policy treated as both a domain and a file \n" + "type. See find_domains and find_file_types modules for details about the \n" + "heuristics used to determine these types. It is considered bad security\n" + "practice to use the same type for a domain and its data objects because it \n" + "requires that less restrictive access be granted to these types.\n"; + mod->opt_description = "Module requirements:\n" " attribute names\n" + " file_contexts\n" + "Module dependencies:\n" " find_domains module\n" " find_file_types module\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* assign requirements */ + nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES); + apol_vector_append(mod->requirements, (void *)nv); + nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL); + apol_vector_append(mod->requirements, (void *)nv); + + /* assign dependencies */ + apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")); + apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_file_types")); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = &domain_and_file_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = domain_and_file_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = domain_and_file_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + sechk_result_t *domain_res = NULL, *file_type_res = NULL; + size_t i, j, k; + sechk_mod_fn_t run_fn = NULL; + sechk_name_value_t *dep = NULL; + apol_vector_t *domain_vector; + apol_vector_t *type_vector; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + + /* run dependencies */ + for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) { + dep = apol_vector_get_element(mod->dependencies, i); + run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib); + run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL); + } + + /* get results */ + domain_res = sechk_lib_get_module_result("find_domains", mod->parent_lib); + if (!domain_res) { + error = errno; + ERR(policy, "%s", "Unable to get results for module find_domains"); + goto domain_and_file_run_fail; + } + file_type_res = sechk_lib_get_module_result("find_file_types", mod->parent_lib); + if (!file_type_res) { + error = errno; + ERR(policy, "%s", "Unable to get results for module find_file_types"); + goto domain_and_file_run_fail; + } + + /* get lists */ + domain_vector = (apol_vector_t *) domain_res->items; + type_vector = (apol_vector_t *) file_type_res->items; + + /* build the both list */ + for (i = 0; i < apol_vector_get_size(type_vector); i++) { + sechk_item_t *type_item; + qpol_type_t *type; + const char *type_name; + + type_item = apol_vector_get_element(type_vector, i); + type = type_item->item; + qpol_type_get_name(q, type, &type_name); + for (j = 0; j < apol_vector_get_size(domain_vector); j++) { + sechk_item_t *domain_item; + qpol_type_t *domain; + const char *domain_name; + + domain_item = apol_vector_get_element(domain_vector, j); + domain = domain_item->item; + qpol_type_get_name(q, domain, &domain_name); + if (!strcmp(domain_name, type_name)) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + item->item = (void *)domain; + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + for (k = 0; k < apol_vector_get_size(domain_item->proof); k++) { + sechk_proof_t *domain_proof; + + domain_proof = apol_vector_get_element(domain_item->proof, k); + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + proof->type = SECHK_ITEM_TYPE; + proof->text = strdup(domain_proof->text); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + } + for (k = 0; k < apol_vector_get_size(type_item->proof); k++) { + sechk_proof_t *type_proof; + + type_proof = apol_vector_get_element(type_item->proof, k); + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + proof->type = SECHK_ITEM_TYPE; + proof->text = strdup(type_proof->text); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domain_and_file_run_fail; + } + } + } + } + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + domain_and_file_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd types.\n", num_items); + } + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/domain_and_file.h b/sechecker/modules/domain_and_file.h new file mode 100644 index 0000000..81b82c1 --- /dev/null +++ b/sechecker/modules/domain_and_file.h @@ -0,0 +1,46 @@ +/** + * @file + * Defines the interface for the domain and file type module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef DOMAIN_AND_FILE +#define DOMAIN_AND_FILE + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> + + int domain_and_file_register(sechk_lib_t * lib); + int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/domains_wo_roles.c b/sechecker/modules/domains_wo_roles.c new file mode 100644 index 0000000..38b42a8 --- /dev/null +++ b/sechecker/modules/domains_wo_roles.c @@ -0,0 +1,386 @@ +/** + * @file + * Implementation of the domains without roles module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "domains_wo_roles.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "domains_wo_roles"; + +/* The register function registers all of a module's functions + * with the library. */ +int domains_wo_roles_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "domains with no roles"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all domains in the policy not associated with a role. These \n" + "domains cannot have a valid security context. The object_r role is not \n" "considered in this check.\n"; + mod->opt_description = + "Module requirements:\n" + " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + /* assign requirements */ + apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)); + + /* assign dependencies */ + apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = domains_wo_roles_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = domains_wo_roles_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = domains_wo_roles_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. */ +int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + int retv, error; + size_t i; + sechk_module_t *mod_ptr = NULL; + sechk_mod_fn_t run_fn = NULL; + apol_vector_t *domain_vector; + apol_vector_t *role_vector; + qpol_policy_t *q = apol_policy_get_qpol(policy); + apol_role_query_t *role_query = NULL; + sechk_result_t *find_domains_res = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "Error: %s\n", strerror(error)); + goto domains_wo_roles_run_fail; + } + + run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib); + if (!run_fn) { + error = errno; + ERR(policy, "%s", "Unable to find run function for module find_domains"); + goto domains_wo_roles_run_fail; + } + + retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL); + if (retv) { + error = errno; + ERR(policy, "%s", "Unable to run module find_domains"); + goto domains_wo_roles_run_fail; + } + + if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) { + error = errno; + ERR(policy, "%s", "Unable to get results for module find_domains"); + goto domains_wo_roles_run_fail; + } + + domain_vector = (apol_vector_t *) find_domains_res->items; + + if (!(role_query = apol_role_query_create())) { + error = errno; + ERR(policy, "Error: %s\n", strerror(error)); + goto domains_wo_roles_run_fail; + } + + for (i = 0; i < apol_vector_get_size(domain_vector); i++) { + qpol_type_t *domain; + const char *domain_name; + + item = apol_vector_get_element(domain_vector, i); + domain = item->item; + qpol_type_get_name(q, domain, &domain_name); + + apol_role_query_set_type(policy, role_query, domain_name); + apol_role_get_by_query(policy, role_query, &role_vector); + if (apol_vector_get_size(role_vector) > 0) { + apol_vector_destroy(&role_vector); + continue; + } + apol_vector_destroy(&role_vector); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->text = strdup("Domain has no role.\n"); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + + } + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + item->item = (void *)domain; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(NULL, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(NULL, "%s", strerror(ENOMEM)); + goto domains_wo_roles_run_fail; + } + } + apol_role_query_destroy(&role_query); + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + domains_wo_roles_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd types.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following types are domains but not associated with any roles.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + type = NULL; + type_name = NULL; + + return 0; +} diff --git a/sechecker/modules/domains_wo_roles.h b/sechecker/modules/domains_wo_roles.h new file mode 100644 index 0000000..e46a9b3 --- /dev/null +++ b/sechecker/modules/domains_wo_roles.h @@ -0,0 +1,47 @@ +/** + * @file + * Defines the interface for the domains without roles module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef DOMAINS_WO_ROLES +#define DOMAINS_WO_ROLES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/role-query.h> + + int domains_wo_roles_register(sechk_lib_t * lib); + int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_assoc_types.c b/sechecker/modules/find_assoc_types.c new file mode 100644 index 0000000..0e72801 --- /dev/null +++ b/sechecker/modules/find_assoc_types.c @@ -0,0 +1,407 @@ +/** + * @file + * Implementation of the association types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "find_assoc_types.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_assoc_types"; + +int find_assoc_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds types with an unlabeled initial sid. \n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_NONE; + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_assoc_types_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_assoc_types_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_assoc_types_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_assoc_types_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)\n", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + char *buff = NULL; + size_t buff_sz = 0; + const qpol_isid_t *isid; + const char *type_name = NULL; + const qpol_type_t *type; + const qpol_context_t *context; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto find_assoc_types_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + + /* Initialize vectors */ + + qpol_policy_get_isid_by_name(q, "unlabeled", &isid); + if (!isid) { + error = errno; + goto find_assoc_types_run_fail; + } + + if (apol_str_append(&buff, &buff_sz, "sid unlabeled ") != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + + qpol_isid_get_context(q, isid, &context); + qpol_context_get_type(q, context, &type); + qpol_type_get_name(q, type, &type_name); + + if (apol_str_append(&buff, &buff_sz, type_name) != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + } + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + + item->test_result = 1; + item->item = (void *)type; + proof->type = SECHK_ITEM_TYPE; + proof->text = buff; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_assoc_types_run_fail; + } + + mod->result = res; + + return 0; + + find_assoc_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + free(buff); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the + * results to stdout. */ +int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Error: wrong module (%s)\n", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd assoc type(s).\n", num_items); + } + /* The list reassoc component is a display of all items + * found without any supassocing proof. The default method + * is to display a comma separated list four items to a line + * this may need to be changed for longer items. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (j = 0; j < num_items; j++) { + i++; + i %= 4; + item = apol_vector_get_element(mod->result->items, j); + type = item->item; + qpol_type_get_name(q, type, &type_name); + if (item) + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + /* The proof reassoc component is a display of a list of items + * with an indented list of proof statements supassocing the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with (or, if long, such as a + * rule, followed by) the severity. Each proof element is then + * displayed in an indented list one per line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (j = 0; j < apol_vector_get_size(mod->result->items); j++) { + item = apol_vector_get_element(mod->result->items, j); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", type_name); + for (k = 0; k < apol_vector_get_size(item->proof); k++) { + proof = apol_vector_get_element(item->proof, k); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + type = NULL; + type_name = NULL; + + return 0; +} + +int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/find_assoc_types.h b/sechecker/modules/find_assoc_types.h new file mode 100644 index 0000000..23cda10 --- /dev/null +++ b/sechecker/modules/find_assoc_types.h @@ -0,0 +1,51 @@ +/** + * @file + * Defines the interface for the association types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_ASSOC_TYPES +#define FIND_ASSOC_TYPES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> + +/* Module functions: + * Do not change any of these prototypes or you will not be + * able to run the module in the library */ + int find_assoc_types_register(sechk_lib_t * lib); + int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_domains.c b/sechecker/modules/find_domains.c new file mode 100644 index 0000000..b59abac --- /dev/null +++ b/sechecker/modules/find_domains.c @@ -0,0 +1,633 @@ +/** + * @file + * Implementation of the find domains utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "find_domains.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_domains"; + +int find_domains_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This is a utility module which finds types in a policy that are treated as a \n" + "domain. A type is considered a domain if any of the following is true:\n" + "\n" + " 1) it has an attribute associated with domains\n" + " 2) it is the source of a TE rule for object class other than filesystem\n" + " 3) it is the default type in a type_transition rule for object class process \n" + " 4) it is associated with a role other than object_r\n"; + mod->opt_description = + "Module requirements:\n" + " attribute names\n" + "Module dependencies:\n" " none\n" "Module options:\n" " domain_attributes can be set in a profile\n"; + mod->severity = SECHK_SEV_NONE; + /* assign requirements */ + apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)); + + /* assign options */ + apol_vector_append(mod->options, sechk_name_value_new("domain_attribute", "domain")); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_domains_init; + apol_vector_append(mod->functions, fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_domains_run; + apol_vector_append(mod->functions, fn_struct); + + mod->data_free = find_domains_data_free; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_domains_print; + apol_vector_append(mod->functions, fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_domains_get_list; + apol_vector_append(mod->functions, fn_struct); + + return 0; +} + +int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_name_value_t *opt = NULL; + find_domains_data_t *datum = NULL; + size_t i, j; + qpol_type_t *attr = NULL; + apol_vector_t *attr_vector = NULL; + apol_attr_query_t *attr_query = apol_attr_query_create(); + qpol_policy_t *q = apol_policy_get_qpol(policy); + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = find_domains_data_new(); + if (!datum) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + if (!(datum->domain_attribs = apol_vector_create(NULL))) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data = datum; + + for (i = 0; i < apol_vector_get_size(mod->options); i++) { + opt = apol_vector_get_element(mod->options, i); + if (!strcmp(opt->name, "domain_attribute")) { + apol_attr_query_set_attr(policy, attr_query, opt->value); + apol_attr_get_by_query(policy, attr_query, &attr_vector); + for (j = 0; j < apol_vector_get_size(attr_vector); j++) { + const char *domain_attrib; + attr = apol_vector_get_element(attr_vector, j); + qpol_type_get_name(q, attr, &domain_attrib); + if (apol_vector_append(datum->domain_attribs, (void *)domain_attrib) < 0) { + apol_vector_destroy(&attr_vector); + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + + } + } + apol_vector_destroy(&attr_vector); + } + } + apol_attr_query_destroy(&attr_query); + return 0; +} + +int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + int error = 0; + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + const char *type_name = NULL; + find_domains_data_t *datum = NULL; + size_t i, j, proof_idx; + apol_vector_t *domain_vector = NULL, *avrule_vector = NULL, *terule_vector = NULL, *role_vector = NULL; + apol_terule_query_t *terule_query = NULL; + apol_avrule_query_t *avrule_query = NULL; + apol_role_query_t *role_query = NULL; + qpol_iterator_t *domain_attr_iter = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + datum = (find_domains_data_t *) mod->data; + res = sechk_result_new(); + if (!res) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + errno = error; + return -1; + } + res->item_type = SECHK_ITEM_TYPE; + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + + if (apol_type_get_by_query(policy, NULL, &domain_vector) < 0) { + goto find_domains_run_fail; + } + + for (i = 0; i < apol_vector_get_size(domain_vector); i++) { + qpol_type_t *type = apol_vector_get_element(domain_vector, i); + qpol_type_get_name(q, type, &type_name); + + if (qpol_type_get_attr_iter(q, type, &domain_attr_iter) < 0) { + error = errno; + ERR(policy, "Can't get attributes for type %s", type_name); + goto find_domains_run_fail; + } + + for (; !qpol_iterator_end(domain_attr_iter); qpol_iterator_next(domain_attr_iter)) { + const char *attr_name; + const qpol_type_t *attr; + size_t nfta; + + qpol_iterator_get_item(domain_attr_iter, (void **)&attr); + qpol_type_get_name(q, attr, &attr_name); + for (nfta = 0; nfta < apol_vector_get_size(datum->domain_attribs); nfta++) { + const char *domain_attrib; + + domain_attrib = apol_vector_get_element(datum->domain_attribs, nfta); + if (!strcmp(attr_name, domain_attrib)) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + proof->type = SECHK_ITEM_ATTRIB; + proof->elem = (void *)attr; + asprintf(&proof->text, "%s has attribute %s", type_name, attr_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + } + } + qpol_iterator_destroy(&domain_attr_iter); + + /* rule src check !filesystem associate */ + if (!(avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + apol_avrule_query_set_source(policy, avrule_query, type_name, 0); + if (apol_avrule_get_by_query(policy, avrule_query, &avrule_vector) < 0) { + error = errno; + ERR(policy, "%s", "Unable to retrieve AV rules"); + goto find_domains_run_fail; + } + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + const qpol_avrule_t *avrule = NULL; + const qpol_class_t *class = NULL; + const char *class_name = NULL; + + avrule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_object_class(q, avrule, &class); + qpol_class_get_name(q, class, &class_name); + if (strcmp("filesystem", class_name)) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + proof->type = SECHK_ITEM_AVRULE; + proof->text = apol_avrule_render(policy, avrule); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + } + apol_vector_destroy(&avrule_vector); + apol_avrule_query_destroy(&avrule_query); + + /* type rule check file object */ + if (!(terule_query = apol_terule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + apol_terule_query_set_default(policy, terule_query, type_name); + apol_terule_query_append_class(policy, terule_query, "process"); + if (apol_terule_get_by_query(policy, terule_query, &terule_vector) < 0) { + error = errno; + ERR(policy, "%s", "Unable to retrieve TE rules"); + goto find_domains_run_fail; + } + for (j = 0; j < apol_vector_get_size(terule_vector); j++) { + qpol_terule_t *terule = NULL; + terule = apol_vector_get_element(terule_vector, j); + + if (apol_vector_get_index(item->proof, terule, sechk_proof_with_element_compare, NULL, &proof_idx) == 0) + continue; + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + proof->type = SECHK_ITEM_TERULE; + proof->elem = terule; + proof->text = apol_terule_render(policy, terule); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + apol_vector_destroy(&terule_vector); + apol_terule_query_destroy(&terule_query); + + /* Check Roles */ + if (!(role_query = apol_role_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + apol_role_query_set_type(policy, role_query, type_name); + apol_role_get_by_query(policy, role_query, &role_vector); + for (j = 0; j < apol_vector_get_size(role_vector); j++) { + const qpol_role_t *role; + const char *role_name; + + role = (qpol_role_t *) apol_vector_get_element(role_vector, j); + qpol_role_get_name(q, role, &role_name); + if (!strcmp("object_r", role_name)) + continue; + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + proof->type = SECHK_ITEM_ROLE; + proof->elem = (void *)role; + asprintf(&proof->text, "role %s types %s;", role_name, type_name); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "Error: %s\n", strerror(error)); + goto find_domains_run_fail; + } + } + apol_vector_destroy(&role_vector); + apol_role_query_destroy(&role_query); + + /* insert any results for this type */ + if (item) { + item->item = type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_domains_run_fail; + } + } + item = NULL; + type = NULL; + type_name = NULL; + } + apol_vector_destroy(&domain_vector); + + /* results are valid at this point */ + mod->result = res; + return 0; + + find_domains_run_fail: + qpol_iterator_destroy(&domain_attr_iter); + apol_vector_destroy(&domain_vector); + apol_vector_destroy(&avrule_vector); + apol_vector_destroy(&terule_vector); + apol_vector_destroy(&role_vector); + apol_avrule_query_destroy(&avrule_query); + apol_terule_query_destroy(&terule_query); + apol_role_query_destroy(&role_query); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +void find_domains_data_free(void *data) +{ + find_domains_data_t *datum = (find_domains_data_t *) data; + + if (datum) { + apol_vector_destroy(&datum->domain_attribs); + } + free(data); +} + +int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + find_domains_data_t *datum = NULL; + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + sechk_proof_t *proof = NULL; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp("find_domains", mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = (find_domains_data_t *) mod->data; + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) { + return 0; /* not an error - no output is requested */ + } + if (outformat & SECHK_OUT_STATS) { + printf("Found %i domain types.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following types are domains.\n"); + } + + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} + +find_domains_data_t *find_domains_data_new(void) +{ + find_domains_data_t *datum = NULL; + + datum = (find_domains_data_t *) calloc(1, sizeof(find_domains_data_t)); + + return datum; +} diff --git a/sechecker/modules/find_domains.h b/sechecker/modules/find_domains.h new file mode 100644 index 0000000..917cd41 --- /dev/null +++ b/sechecker/modules/find_domains.h @@ -0,0 +1,60 @@ +/** + * @file + * Defines the interface for the find domains utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_DOMAINS +#define FIND_DOMAINS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/type-query.h> +#include <apol/role-query.h> +#include <apol/terule-query.h> +#include <apol/avrule-query.h> + + typedef struct find_domains_data + { + apol_vector_t *domain_attribs; + int num_domain_attribs; + } find_domains_data_t; + + void find_domains_data_free(void *data); + find_domains_data_t *find_domains_data_new(void); + + int find_domains_register(sechk_lib_t * lib); + int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_file_types.c b/sechecker/modules/find_file_types.c new file mode 100644 index 0000000..193e3f3 --- /dev/null +++ b/sechecker/modules/find_file_types.c @@ -0,0 +1,636 @@ +/** + * @file + * Implementation of the find file types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Randy Wicks rwicks@tresys.com + * + * Copyright (C) 2005-2007 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 "find_file_types.h" + +#include <qpol/genfscon_query.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +static const char *const mod_name = "find_file_types"; + +int find_file_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + sechk_name_value_t *nv = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in the policy treated as a file type. A type is \n" + "considered a file type if any of the following is true:\n" + "\n" + " 1) it has an attribute associated with file types\n" + " 2) it is the source of a rule to allow filesystem associate permission\n" + " 3) it is the default type of a type transition rule with an object class\n" " other than process\n" + " 4) it is specified in a context in the file_contexts file\n"; + mod->opt_description = "Module requirements:\n" " attribute names\n" + " file_contexts\n" + "Module dependencies:\n" " none\n" "Module options:\n" " file_type_attribute can be modified in a profile\n"; + mod->severity = SECHK_SEV_NONE; + /* assign requirements */ + nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES); + apol_vector_append(mod->requirements, (void *)nv); + nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL); + apol_vector_append(mod->requirements, (void *)nv); + + /* assign options */ + nv = sechk_name_value_new("file_type_attribute", "file_type"); + apol_vector_append(mod->options, (void *)nv); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_file_types_init; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_file_types_run; + apol_vector_append(mod->functions, (void *)fn_struct); + + mod->data_free = find_file_types_data_free; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_file_types_print; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_file_types_get_list; + apol_vector_append(mod->functions, (void *)fn_struct); + + return 0; +} + +int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_name_value_t *opt = NULL; + find_file_types_data_t *datum = NULL; + apol_vector_t *attr_vector = NULL; + apol_attr_query_t *attr_query = apol_attr_query_create(); + qpol_type_t *attr = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + size_t i = 0, j = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = find_file_types_data_new(); + if (!datum) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + if (!(datum->file_type_attribs = apol_vector_create(NULL))) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + mod->data = datum; + + for (i = 0; i < apol_vector_get_size(mod->options); i++) { + opt = apol_vector_get_element(mod->options, i); + if (!strcmp(opt->name, "file_type_attribute")) { + apol_attr_query_set_attr(policy, attr_query, opt->value); + apol_attr_get_by_query(policy, attr_query, &attr_vector); + for (j = 0; j < apol_vector_get_size(attr_vector); j++) { + const char *file_attrib; + attr = apol_vector_get_element(attr_vector, j); + qpol_type_get_name(q, attr, &file_attrib); + if (apol_vector_append(datum->file_type_attribs, (void *)file_attrib) < 0) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + } + apol_vector_destroy(&attr_vector); + } + } + apol_attr_query_destroy(&attr_query); + return 0; +} + +int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + find_file_types_data_t *datum; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + sechk_result_t *res = NULL; + const char *type_name = NULL; + apol_avrule_query_t *avrule_query = NULL; + apol_terule_query_t *terule_query = NULL; + apol_vector_t *avrule_vector = NULL; + apol_vector_t *terule_vector = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + size_t i, j, x; + char *buff = NULL; + int error = 0; + + /* NEW */ + size_t num_fc_entries = 0; + apol_vector_t *type_vector = NULL; + apol_vector_t *fc_entry_vector = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + datum = (find_file_types_data_t *) mod->data; + res->item_type = SECHK_ITEM_TYPE; + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + if (mod->parent_lib->fc_entries) { + if (mod->parent_lib->fc_path) { + fc_entry_vector = mod->parent_lib->fc_entries; + num_fc_entries = apol_vector_get_size(fc_entry_vector); + } else { + error = ENOENT; + ERR(policy, "%s", "Unable to find file contexts file"); + goto find_file_types_run_fail; + } + } + + /* Get an iterator for the types */ + if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) { + error = errno; + ERR(policy, "%s", "Unable to retrieve types"); + return -1; + } + + for (i = 0; i < apol_vector_get_size(type_vector); i++) { + qpol_iterator_t *file_attr_iter; + + const qpol_type_t *type = apol_vector_get_element(type_vector, i); + qpol_type_get_name(q, type, &type_name); + + if (qpol_type_get_attr_iter(q, type, &file_attr_iter) < 0) { + error = errno; + ERR(policy, "Could not get attributes for %s\n", type_name); + goto find_file_types_run_fail; + } + + for (; !qpol_iterator_end(file_attr_iter); qpol_iterator_next(file_attr_iter)) { + const char *attr_name; + const qpol_type_t *attr; + size_t nfta; + + qpol_iterator_get_item(file_attr_iter, (void **)&attr); + qpol_type_get_name(q, attr, &attr_name); + for (nfta = 0; nfta < apol_vector_get_size(datum->file_type_attribs); nfta++) { + const char *file_type_attrib; + + file_type_attrib = apol_vector_get_element(datum->file_type_attribs, nfta); + if (!strcmp(attr_name, file_type_attrib)) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + proof->type = SECHK_ITEM_ATTRIB; + proof->elem = (void *)attr; + asprintf(&proof->text, "has attribute %s", attr_name); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + } + } + qpol_iterator_destroy(&file_attr_iter); + + /* rule src check filesystem associate */ + if (!(avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", "Could not retrieve AV rules"); + goto find_file_types_run_fail; + } + apol_avrule_query_set_source(policy, avrule_query, type_name, 0); + apol_avrule_query_append_class(policy, avrule_query, "filesystem"); + apol_avrule_query_append_perm(policy, avrule_query, "associate"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (x = 0; x < apol_vector_get_size(avrule_vector); x++) { + qpol_avrule_t *avrule; + avrule = apol_vector_get_element(avrule_vector, x); + if (avrule) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + proof->type = SECHK_ITEM_AVRULE; + proof->elem = avrule; + proof->text = apol_avrule_render(policy, avrule); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + item->test_result = 1; + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + } + apol_vector_destroy(&avrule_vector); + apol_avrule_query_destroy(&avrule_query); + + /* type rule check file object */ + if (!(terule_query = apol_terule_query_create())) { + error = errno; + ERR(policy, "%s", "Could not retrieve TE rules"); + goto find_file_types_run_fail; + } + apol_terule_query_set_default(policy, terule_query, type_name); + apol_terule_get_by_query(policy, terule_query, &terule_vector); + for (x = 0; x < apol_vector_get_size(terule_vector); x++) { + const qpol_terule_t *terule; + const qpol_class_t *objclass; + const char *class_name; + + terule = apol_vector_get_element(terule_vector, x); + qpol_terule_get_object_class(q, terule, &objclass); + qpol_class_get_name(q, objclass, &class_name); + if (strcmp(class_name, "process")) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + proof->type = SECHK_ITEM_TERULE; + proof->elem = (void *)terule; + proof->text = apol_terule_render(policy, terule); + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + item->test_result = 1; + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + } + apol_vector_destroy(&terule_vector); + apol_terule_query_destroy(&terule_query); + + /* assigned in fc check */ + if (fc_entry_vector) { + buff = NULL; + for (j = 0; j < num_fc_entries; j++) { + sefs_entry_t *fc_entry; + const char *fc_type_name = NULL; + fc_entry = apol_vector_get_element(fc_entry_vector, j); + const apol_context_t *context = sefs_entry_get_context(fc_entry); + if (!context) + continue; + fc_type_name = apol_context_get_type(context); + if (!strcmp(type_name, fc_type_name)) { + buff = sefs_entry_to_string(fc_entry); + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + proof->type = SECHK_ITEM_FCENT; + proof->elem = fc_entry; + proof->text = buff; + buff = NULL; + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + } + } + /* insert any results for this type */ + if (item) { + item->item = (void *)type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_file_types_run_fail; + } + } + item = NULL; + type = NULL; + type_name = NULL; + } + apol_vector_destroy(&type_vector); + + /* results are valid at this point */ + mod->result = res; + + return 0; + + find_file_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + free(buff); + apol_vector_destroy(&type_vector); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +void find_file_types_data_free(void *data) +{ + find_file_types_data_t *datum = (find_file_types_data_t *) data; + + if (datum) { + apol_vector_destroy(&datum->file_type_attribs); + } + free(data); +} + +int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + find_file_types_data_t *datum = NULL; + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items = 0; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = (find_file_types_data_t *) mod->data; + outformat = mod->outputformat; + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + if (outformat & SECHK_OUT_STATS) { + num_items = apol_vector_get_size(mod->result->items); + printf("Found %zd file types.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following types are file types.\n\n"); + } + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < apol_vector_get_size(mod->result->items); i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < apol_vector_get_size(mod->result->items); k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg + __attribute__ ((unused))) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} + +find_file_types_data_t *find_file_types_data_new(void) +{ + find_file_types_data_t *datum = NULL; + + datum = (find_file_types_data_t *) calloc(1, sizeof(find_file_types_data_t)); + + return datum; +} diff --git a/sechecker/modules/find_file_types.h b/sechecker/modules/find_file_types.h new file mode 100644 index 0000000..941862b --- /dev/null +++ b/sechecker/modules/find_file_types.h @@ -0,0 +1,60 @@ +/** + * @file + * Defines the interface for the find file types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Randy Wicks rwicks@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_FILE_TYPES +#define FIND_FILE_TYPES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/type-query.h> +#include <apol/avrule-query.h> +#include <apol/terule-query.h> + + typedef struct find_file_types_data + { + apol_vector_t *file_type_attribs; + int num_file_type_attribs; + } find_file_types_data_t; + + void find_file_types_data_free(void *data); + find_file_types_data_t *find_file_types_data_new(void); + + int find_file_types_register(sechk_lib_t * lib); + int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_net_domains.c b/sechecker/modules/find_net_domains.c new file mode 100644 index 0000000..dadd459 --- /dev/null +++ b/sechecker/modules/find_net_domains.c @@ -0,0 +1,501 @@ +/** + * @file + * Implementation of the network domain utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "find_net_domains.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_net_domains"; + +int find_net_domains_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in a policy considered to be network domains. \n" + "A type is considered a network domain if it is the subject of TE rules \n" + "involving certain object classes, which are currently defined as:\n" + " 1) netif\n" + " 2) tcp_socket\n" + " 3) udp_socket\n" + " 4) node\n" " 5) association\n" "These values can be overridden in this module's profile."; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" + " net_obj\n"; + mod->severity = SECHK_SEV_NONE; + + /* assign default options */ + apol_vector_append(mod->options, sechk_name_value_new("net_obj", "netif")); + apol_vector_append(mod->options, sechk_name_value_new("net_obj", "tcp_socket")); + apol_vector_append(mod->options, sechk_name_value_new("net_obj", "udp_socket")); + apol_vector_append(mod->options, sechk_name_value_new("net_obj", "node")); + apol_vector_append(mod->options, sechk_name_value_new("net_obj", "association")); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_net_domains_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_net_domains_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = find_net_domains_data_free; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_net_domains_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_net_domains_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_name_value_t *opt = NULL; + find_net_domains_data_t *datum = NULL; + size_t i; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = find_net_domains_data_new(); + if (!datum) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + if (!(datum->net_objs = apol_vector_create(NULL))) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data = datum; + + for (i = 0; i < apol_vector_get_size(mod->options); i++) { + opt = apol_vector_get_element(mod->options, i); + if (!strcmp(opt->name, "net_obj")) { + if (apol_vector_append(datum->net_objs, (void *)opt->value) < 0) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + } + } + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + find_net_domains_data_t *datum; + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + int error = 0; + size_t i = 0, j = 0, k = 0; + apol_vector_t *avrule_vector; + apol_avrule_query_t *avrule_query = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + datum = (find_net_domains_data_t *) mod->data; + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + + if (!(avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (k = 0; k < apol_vector_get_size(avrule_vector); k++) { + const qpol_avrule_t *avrule; + const qpol_class_t *class; + const char *class_name; + + avrule = apol_vector_get_element(avrule_vector, k); + qpol_avrule_get_object_class(q, avrule, &class); + qpol_class_get_name(q, class, &class_name); + for (i = 0; i < apol_vector_get_size(datum->net_objs); i++) { + const char *net_obj_name; + + net_obj_name = apol_vector_get_element(datum->net_objs, i); + if (!strcmp(class_name, net_obj_name)) { + const qpol_type_t *source; + const char *source_name; + + qpol_avrule_get_source_type(q, avrule, &source); + qpol_type_get_name(q, source, &source_name); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + proof->type = SECHK_ITEM_AVRULE; + proof->elem = (void *)avrule; + proof->text = apol_avrule_render(policy, avrule); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + item = NULL; + + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item = NULL; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(res_type_name, source_name)) + item = res_item; + } + + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + item->test_result = 1; + item->item = (void *)source; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_net_domains_run_fail; + } + item = NULL; + } + } + } + apol_avrule_query_destroy(&avrule_query); + apol_vector_destroy(&avrule_vector); + mod->result = res; + + return 0; + + find_net_domains_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The free function frees the private data of a module */ +void find_net_domains_data_free(void *data) +{ + find_net_domains_data_t *d = data; + apol_vector_destroy(&d->net_objs); + free(data); +} + +/* The print function generates the text and prints the + * results to stdout. */ +int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + find_net_domains_data_t *datum = NULL; + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = (find_net_domains_data_t *) mod->data; + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("\nFound %i network domains.", num_items); + } + + /* The list renode component is a display of all items + * found without any supnodeing proof. The default method + * is to display a comma separated list four items to a line + * this may need to be changed for longer items. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + /* The proof renode component is a display of a list of items + * with an indented list of proof statements supnodeing the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with (or, if long, such as a + * rule, followed by) the severity. Each proof element is then + * displayed in an indented list one per line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} + +/* The find_net_domains_data_new function allocates and returns an + * initialized private data storage structure for this + * module. Initialization expected is as follows: + * all arrays (including strings) are initialized to NULL + * array sizes are set to 0 + * any other pointers should be NULL + * indices into other arrays (such as type or permission indices) + * should be initialized to -1 + * any other data should be initialized as needed by the check logic */ +find_net_domains_data_t *find_net_domains_data_new(void) +{ + find_net_domains_data_t *datum = NULL; + + datum = (find_net_domains_data_t *) calloc(1, sizeof(find_net_domains_data_t)); + + return datum; +} diff --git a/sechecker/modules/find_net_domains.h b/sechecker/modules/find_net_domains.h new file mode 100644 index 0000000..68eeb75 --- /dev/null +++ b/sechecker/modules/find_net_domains.h @@ -0,0 +1,59 @@ +/** + * @file + * Defines the interface for the network domain utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_NET_DOMAINS +#define FIND_NET_DOMAINS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/avrule-query.h> + +/* The find_net_domains_data structure is used to hold the check specific + * private data of a module. */ + typedef struct find_net_domains_data + { + apol_vector_t *net_objs; + } find_net_domains_data_t; + + find_net_domains_data_t *find_net_domains_data_new(void); + void find_net_domains_data_free(void *data); + + int find_net_domains_register(sechk_lib_t * lib); + int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_netif_types.c b/sechecker/modules/find_netif_types.c new file mode 100644 index 0000000..e703687 --- /dev/null +++ b/sechecker/modules/find_netif_types.c @@ -0,0 +1,489 @@ +/** + * @file + * Implementation of the netif types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "find_netif_types.h" +#include <apol/netcon-query.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_netif_types"; + +/* The register function registers all of a module's functions + * with the library. */ +int find_netif_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in a policy treated as a netif type. A type is\n" + "a netif type if it is used in the internace context in a netifcon statement or\n" + "the context of the netif initial sid.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_NONE; + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_netif_types_init; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_netif_types_run; + apol_vector_append(mod->functions, (void *)fn_struct); + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_netif_types_print; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_netif_types_get_list; + apol_vector_append(mod->functions, (void *)fn_struct); + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + char *buff = NULL; + size_t i, buff_sz = 0; + apol_vector_t *netifcon_vector; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + + /* search initial SIDs */ + const qpol_isid_t *isid = NULL; + + buff = NULL; + qpol_policy_get_isid_by_name(q, "netif", &isid); + if (isid) { + const qpol_context_t *context; + apol_context_t *a_context; + const qpol_type_t *context_type; + const char *context_type_name; + char *tmp; + + proof = NULL; + qpol_isid_get_context(q, isid, &context); + qpol_context_get_type(q, context, &context_type); + qpol_type_get_name(q, context_type, &context_type_name); + a_context = apol_context_create_from_qpol_context(policy, context); + + if (apol_str_append(&buff, &buff_sz, "sid netif ") != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + apol_context_destroy(&a_context); + goto find_netif_types_run_fail; + } + + tmp = apol_context_render(policy, a_context); + if (apol_str_append(&buff, &buff_sz, tmp) != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + free(tmp); + apol_context_destroy(&a_context); + goto find_netif_types_run_fail; + } + apol_context_destroy(&a_context); + free(tmp); + tmp = NULL; + + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + item->test_result = 1; + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + + proof->type = SECHK_ITEM_ISID; + proof->elem = (void *)isid; + proof->text = buff; + + item->item = (void *)context_type; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + } + + if (apol_netifcon_get_by_query(policy, NULL, &netifcon_vector) < 0) { + error = errno; + goto find_netif_types_run_fail; + } + + for (i = 0; i < apol_vector_get_size(netifcon_vector); i++) { + const char *msg_con_name = NULL; + const char *if_con_name = NULL; + qpol_netifcon_t *netifcon = NULL; + const qpol_context_t *msg_con = NULL; + const qpol_context_t *if_con = NULL; + const qpol_type_t *msg_type = NULL; + const qpol_type_t *if_type = NULL; + size_t j = 0; + + netifcon = apol_vector_get_element(netifcon_vector, i); + qpol_netifcon_get_msg_con(q, netifcon, &msg_con); + qpol_netifcon_get_if_con(q, netifcon, &if_con); + qpol_context_get_type(q, msg_con, &msg_type); + qpol_context_get_type(q, if_con, &if_type); + qpol_type_get_name(q, msg_type, &msg_con_name); + qpol_type_get_name(q, if_type, &if_con_name); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + proof->type = SECHK_ITEM_NETIFCON; + proof->elem = netifcon; + proof->text = apol_netifcon_render(policy, netifcon); + item = NULL; + + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item = NULL; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = (qpol_type_t *) res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(res_type_name, if_con_name)) + item = res_item; + } + + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + item->test_result = 1; + item->item = (void *)if_type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_netif_types_run_fail; + } + item = NULL; + } + apol_vector_destroy(&netifcon_vector); + + mod->result = res; + + return 0; + + find_netif_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + free(buff); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text and prints the + * results to stdout. The outline below prints + * the standard format of a renetif section. Some modules may + * not have results in a format that can be represented by this + * outline and will need a different specification. It is + * required that each of the flags for output components be + * tested in this function (stats, list, proof, detailed, and brief) */ +int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, num_items = 0; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i netif types.\n", num_items); + } + + /* The list renetif component is a display of all items + * found without any supnetifing proof. The default method + * is to display a comma separated list four items to a line + * this may need to be changed for longer items. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + /* The proof renetif component is a display of a list of items + * with an indented list of proof statements supnetifing the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with (or, if long, such as a + * rule, followed by) the severity. Each proof element is then + * displayed in an indented list one per line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (j = 0; j < num_items; j++) { + item = apol_vector_get_element(mod->result->items, j); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + if (item) { + printf("%s\n", type_name); + for (k = 0; k < apol_vector_get_size(item->proof); k++) { + proof = apol_vector_get_element(item->proof, k); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/find_netif_types.h b/sechecker/modules/find_netif_types.h new file mode 100644 index 0000000..859ee8a --- /dev/null +++ b/sechecker/modules/find_netif_types.h @@ -0,0 +1,53 @@ +/** + * @file + * Defines the interface for the netif types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_NETIF_TYPES_H +#define FIND_NETIF_TYPES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/context-query.h> +#include <apol/netcon-query.h> + +/* Module functions: + * Do not change any of these prototypes or you will not be + * able to run the module in the library */ + int find_netif_types_register(sechk_lib_t * lib); + int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_node_types.c b/sechecker/modules/find_node_types.c new file mode 100644 index 0000000..f10be10 --- /dev/null +++ b/sechecker/modules/find_node_types.c @@ -0,0 +1,479 @@ +/** + * @file + * Implementation of the node types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "find_node_types.h" +#include <apol/netcon-query.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_node_types"; + +/* The register function registers all of a module's functions + * with the library. You should not need to edit this function + * unless you are adding additional functions you need other modules + * to call. See the note at the bottom of this function to do so. */ +int find_node_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Unknown module"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + + /* assign the descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in a policy treated as a node type. A type is\n" + "considered a node type if it is used in the context of a nodecon statement or\n" + "the context of the node initial sid.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_NONE; + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_node_types_init; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_node_types_run; + apol_vector_append(mod->functions, (void *)fn_struct); + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_node_types_print; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_node_types_get_list; + apol_vector_append(mod->functions, (void *)fn_struct); + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. + * Add any option processing logic as indicated below. */ +int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + char *buff = NULL; + size_t i, buff_sz = 0; + apol_vector_t *nodecon_vector = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + + /* search initial SIDs */ + const qpol_isid_t *isid = NULL; + + buff = NULL; + qpol_policy_get_isid_by_name(q, "node", &isid); + if (isid) { + const qpol_context_t *context; + apol_context_t *a_context; + const qpol_type_t *context_type; + const char *context_type_name; + char *tmp; + + proof = NULL; + qpol_isid_get_context(q, isid, &context); + qpol_context_get_type(q, context, &context_type); + qpol_type_get_name(q, context_type, &context_type_name); + a_context = apol_context_create_from_qpol_context(policy, context); + + if (apol_str_append(&buff, &buff_sz, "sid node ") != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + apol_context_destroy(&a_context); + goto find_node_types_run_fail; + } + + tmp = apol_context_render(policy, a_context); + if (apol_str_append(&buff, &buff_sz, tmp) != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + apol_context_destroy(&a_context); + free(tmp); + goto find_node_types_run_fail; + } + apol_context_destroy(&a_context); + free(tmp); + tmp = NULL; + + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + item->test_result = 1; + } + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + + proof->type = SECHK_ITEM_ISID; + proof->elem = (void *)isid; + proof->text = buff; + + item->item = (void *)context_type; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + } + + if (apol_nodecon_get_by_query(policy, NULL, &nodecon_vector) < 0) { + error = errno; + goto find_node_types_run_fail; + } + + for (i = 0; i < apol_vector_get_size(nodecon_vector); i++) { + const char *type_name; + size_t j; + const qpol_context_t *context; + const qpol_type_t *context_type; + qpol_nodecon_t *nodecon = apol_vector_get_element(nodecon_vector, i); + qpol_nodecon_get_context(q, nodecon, &context); + qpol_context_get_type(q, context, &context_type); + qpol_type_get_name(q, context_type, &type_name); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->text = apol_nodecon_render(policy, nodecon); + + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(res_type_name, type_name)) + item = res_item; + } + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + item->test_result = 1; + item->item = (void *)context_type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_node_types_run_fail; + } + item = NULL; + } + apol_vector_destroy(&nodecon_vector); + + mod->result = res; + + return 0; + + find_node_types_run_fail: + apol_vector_destroy(&nodecon_vector); + sechk_proof_free(proof); + sechk_item_free(item); + free(buff); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the results to stdout. */ +int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, num_items = 0; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i node types.\n", num_items); + } + + /* The list renode component is a display of all items + * found without any supnodeing proof. The default method + * is to display a comma separated list four items to a line + * this may need to be changed for longer items. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + /* The proof renode component is a display of a list of items + * with an indented list of proof statements supnodeing the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with (or, if long, such as a + * rule, followed by) the severity. Each proof element is then + * displayed in an indented list one per line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (j = 0; j < num_items; j++) { + item = apol_vector_get_element(mod->result->items, j); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + if (item) { + printf("%s\n", type_name); + for (k = 0; k < apol_vector_get_size(item->proof); k++) { + proof = apol_vector_get_element(item->proof, k); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/find_node_types.h b/sechecker/modules/find_node_types.h new file mode 100644 index 0000000..44ac749 --- /dev/null +++ b/sechecker/modules/find_node_types.h @@ -0,0 +1,53 @@ +/** + * @file + * Defines the interface for the node types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_NODE_TYPES_H +#define FINE_NODE_TYPES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/context-query.h> +#include <apol/netcon-query.h> + +/* Module functions: + * Do not change any of these prototypes or you will not be + * able to run the module in the library */ + int find_node_types_register(sechk_lib_t * lib); + int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/find_port_types.c b/sechecker/modules/find_port_types.c new file mode 100644 index 0000000..8e55bc3 --- /dev/null +++ b/sechecker/modules/find_port_types.c @@ -0,0 +1,513 @@ +/** + * @file + * Implementation of the port types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "find_port_types.h" +#include <apol/netcon-query.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "find_port_types"; + +/* The register function registers all of a module's functions + * with the library. */ +int find_port_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "utility module"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all types in a policy treated as a port type. A type is\n" + "considered a port type if it is used in the context of a a portcon statement or\n" + "the context of the port initial sid.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_NONE; + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_port_types_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_port_types_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = find_port_types_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = &find_port_types_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. + * Add any option processing logic as indicated below. */ +int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + char *buff = NULL; + size_t buff_sz = 0, i, j; + apol_vector_t *portcon_vector; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + + /* search initial SIDs */ + const qpol_isid_t *isid = NULL; + buff = NULL; + qpol_policy_get_isid_by_name(q, "port", &isid); + if (isid) { + const qpol_context_t *context; + apol_context_t *a_context; + const qpol_type_t *context_type; + const char *context_type_name; + char *tmp; + + proof = NULL; + qpol_isid_get_context(q, isid, &context); + qpol_context_get_type(q, context, &context_type); + qpol_type_get_name(q, context_type, &context_type_name); + a_context = apol_context_create_from_qpol_context(policy, context); + + if (apol_str_append(&buff, &buff_sz, "sid port ") != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + apol_context_destroy(&a_context); + goto find_port_types_run_fail; + } + + tmp = apol_context_render(policy, a_context); + if (apol_str_append(&buff, &buff_sz, tmp) != 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + apol_context_destroy(&a_context); + free(tmp); + goto find_port_types_run_fail; + } + free(tmp); + tmp = NULL; + apol_context_destroy(&a_context); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + + proof->type = SECHK_ITEM_ISID; + proof->elem = (void *)isid; + proof->text = buff; + + /* Have we encountered this type before? If so, use that type. */ + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item = NULL; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(res_type_name, context_type_name)) + item = res_item; + } + + /* We have not encountered this type yet */ + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + item->test_result = 1; + item->item = (void *)context_type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + } + + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + } + + if (apol_portcon_get_by_query(policy, NULL, &portcon_vector) < 0) { + error = errno; + goto find_port_types_run_fail; + } + + for (i = 0; i < apol_vector_get_size(portcon_vector); i++) { + const char *portcon_name = NULL; + const qpol_portcon_t *portcon = NULL; + const qpol_context_t *portcon_context = NULL; + const qpol_type_t *portcon_type = NULL; + + portcon = apol_vector_get_element(portcon_vector, i); + qpol_portcon_get_context(q, portcon, &portcon_context); + qpol_context_get_type(q, portcon_context, &portcon_type); + qpol_type_get_name(q, portcon_type, &portcon_name); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + proof->type = SECHK_ITEM_PORTCON; + proof->elem = (void *)portcon; + proof->text = apol_portcon_render(policy, portcon); + item = NULL; + + /* Have we encountered this type before? If so, use that type. */ + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item = NULL; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(res_type_name, portcon_name)) + item = res_item; + } + + /* We have not encountered this type yet */ + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + item->test_result = 1; + item->item = (void *)portcon_type; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + } + + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto find_port_types_run_fail; + } + item = NULL; + } + apol_vector_destroy(&portcon_vector); + + mod->result = res; + + return 0; + + find_port_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + free(buff); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the + * results to stdout. */ +int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, num_items = 0; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i port types.\n", num_items); + } + + /* The list report component is a display of all items + * found without any supporting proof. The default method + * is to display a comma separated list four items to a line + * this may need to be changed for longer items. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + /* The proof report component is a display of a list of items + * with an indented list of proof statements supporting the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with (or, if long, such as a + * rule, followed by) the severity. Each proof element is then + * displayed in an indented list one per line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (j = 0; j < num_items; j++) { + item = apol_vector_get_element(mod->result->items, j); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + if (item) { + printf("%s\n", type_name); + for (k = 0; k < apol_vector_get_size(item->proof); k++) { + proof = apol_vector_get_element(item->proof, k); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} + +int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/find_port_types.h b/sechecker/modules/find_port_types.h new file mode 100644 index 0000000..adb19bf --- /dev/null +++ b/sechecker/modules/find_port_types.h @@ -0,0 +1,50 @@ +/** + * @file + * Defines the interface for the port types utility module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef FIND_PORT_TYPES +#define FIND_PORT_TYPES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/context-query.h> +#include <apol/netcon-query.h> + + int find_port_types_register(sechk_lib_t * lib); + int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/imp_range_trans.c b/sechecker/modules/imp_range_trans.c new file mode 100644 index 0000000..8fbf361 --- /dev/null +++ b/sechecker/modules/imp_range_trans.c @@ -0,0 +1,513 @@ +/** + * @file + * Implementation of the impossible range_transition module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author: David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "imp_range_trans.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#define SECHK_NO_ROLES 0x000002 +#define SECHK_BAD_USER_MLS_LOW 0x000040 +#define SECHK_BAD_USER_MLS_HIGH 0x000600 +#define SECHK_NO_USERS 0x008000 +#define SECHK_NO_EXEC_PERMS 0x020000 + +static const char *const mod_name = "imp_range_trans"; + +int imp_range_trans_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "finds impossible range transitions"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds impossible range transitions in a policy.\n" + "A range transition is possible if and only if all of the following conditions\n" + "are satisfied:\n" + " 1) there exist TE rules allowing the range transition to occur\n" + " 2) there exist RBAC rules allowing the range transition to occur\n" + " 3) at least one user must be able to transition to the target MLS range\n"; + mod->opt_description = + " Module requirements:\n" " MLS policy\n" " Module dependencies:\n" " none\n" " Module options:\n" + " none\n"; + mod->severity = SECHK_SEV_MED; + + /* assign requirements */ + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_MLS)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = imp_range_trans_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = imp_range_trans_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = imp_range_trans_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i, j; + apol_vector_t *range_trans_vector = NULL, *role_vector = NULL, *tmp_v = NULL; + apol_vector_t *user_vector = NULL, *users_w_roles = NULL, *users_w_range = NULL; + apol_vector_t *rule_vector = NULL; + const qpol_range_trans_t *rule; + const qpol_type_t *source = NULL; + const qpol_type_t *target = NULL; + const qpol_role_t *role = NULL; + const char *source_name = NULL, *target_name = NULL, *role_name = NULL; + apol_role_query_t *role_query = NULL; + apol_user_query_t *user_query = NULL; + apol_avrule_query_t *avrule_query = NULL; + apol_mls_range_t *range; + const qpol_mls_range_t *qpol_range; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + res->item_type = SECHK_ITEM_RANGETRANS; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + + if (apol_range_trans_get_by_query(policy, NULL, &range_trans_vector) < 0) { + error = errno; + ERR(policy, "%s", "Unable to retrieve range transitions"); + goto imp_range_trans_run_fail; + } + + for (i = 0; i < apol_vector_get_size(range_trans_vector); i++) { + /* collect information about the rule */ + rule = apol_vector_get_element(range_trans_vector, i); + qpol_range_trans_get_source_type(q, rule, &source); + qpol_range_trans_get_target_type(q, rule, &target); + qpol_type_get_name(q, source, &source_name); + qpol_type_get_name(q, target, &target_name); + qpol_range_trans_get_range(q, rule, &qpol_range); + range = apol_mls_range_create_from_qpol_mls_range(policy, qpol_range); + + /* find roles possible for source */ + role_query = apol_role_query_create(); + apol_role_query_set_type(policy, role_query, source_name); + apol_role_get_by_query(policy, role_query, &role_vector); + apol_role_query_destroy(&role_query); + + /* find users with the possible roles */ + if ((users_w_roles = apol_vector_create(NULL)) == NULL) { + error = errno; + goto imp_range_trans_run_fail; + } + user_query = apol_user_query_create(); + for (j = 0; j < apol_vector_get_size(role_vector); j++) { + role = apol_vector_get_element(role_vector, j); + qpol_role_get_name(q, role, &role_name); + apol_user_query_set_role(policy, user_query, role_name); + apol_user_get_by_query(policy, user_query, &tmp_v); + apol_vector_cat(users_w_roles, tmp_v); + apol_vector_destroy(&tmp_v); + } + apol_vector_sort_uniquify(users_w_roles, NULL, NULL); + apol_user_query_destroy(&user_query); + + /* find users with the transition range */ + user_query = apol_user_query_create(); + apol_user_query_set_range(policy, user_query, range, APOL_QUERY_SUB); + apol_user_get_by_query(policy, user_query, &users_w_range); + apol_user_query_destroy(&user_query); + + /* find intersection of user sets */ + user_vector = apol_vector_create_from_intersection(users_w_roles, users_w_range, NULL, NULL); + + /* find avrules for allow <source> <target> : file execute; */ + avrule_query = apol_avrule_query_create(); + apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW); + apol_avrule_query_set_source(policy, avrule_query, source_name, 1); + apol_avrule_query_set_target(policy, avrule_query, target_name, 1); + apol_avrule_query_append_class(policy, avrule_query, "file"); + apol_avrule_query_append_perm(policy, avrule_query, "execute"); + apol_avrule_get_by_query(policy, avrule_query, &rule_vector); + apol_avrule_query_destroy(&avrule_query); + + /* check avrules */ + if (!apol_vector_get_size(rule_vector)) { + proof = sechk_proof_new(NULL); + if (!proof) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + proof->type = SECHK_ITEM_NONE; + asprintf(&proof->text, "Missing: allow %s %s : file execute;", source_name, target_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + item = sechk_item_new(NULL); + if (!item) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + item->item = (void *)rule; + item->test_result = 1; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + proof = NULL; + } + apol_vector_destroy(&rule_vector); + + /* check RBAC */ + if (!apol_vector_get_size(role_vector)) { + proof = sechk_proof_new(NULL); + if (!proof) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + proof->type = SECHK_ITEM_NONE; + asprintf(&proof->text, "No role associated with type %s", source_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + item->item = (void *)rule; + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + proof = NULL; + } + + /* check users */ + if (!apol_vector_get_size(user_vector)) { + proof = sechk_proof_new(NULL); + if (!proof) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + proof->type = SECHK_ITEM_NONE; + if (!apol_vector_get_size(role_vector)) { + proof->text = strdup("No role also means no user"); + } else if (!apol_vector_get_size(users_w_roles)) { + asprintf(&proof->text, "No users associated with roles for %s", source_name); + } else if (!apol_vector_get_size(users_w_range)) { + proof->text = strdup("No user has access to specified MLS range"); + } else { + proof->text = strdup("No user meets MLS and RBAC requirements."); + } + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + ERR(policy, "%s", strerror(ENOMEM)); + error = ENOMEM; + goto imp_range_trans_run_fail; + } + item->item = (void *)rule; + item->test_result = 1; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto imp_range_trans_run_fail; + } + } + apol_vector_destroy(&role_vector); + apol_vector_destroy(&user_vector); + apol_vector_destroy(&users_w_roles); + apol_vector_destroy(&users_w_range); + + if (item) { + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto imp_range_trans_run_fail; + } + } + item = NULL; + } + apol_vector_destroy(&range_trans_vector); + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + imp_range_trans_run_fail: + apol_vector_destroy(&range_trans_vector); + apol_vector_destroy(&role_vector); + apol_vector_destroy(&rule_vector); + apol_vector_destroy(&user_vector); + apol_vector_destroy(&users_w_roles); + apol_vector_destroy(&users_w_range); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text and prints the + * results to stdout. */ +int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + qpol_range_trans_t *rt; + char *tmp; + size_t i = 0, k = 0, j = 0, num_items; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i impossible range transitions.\n", num_items); + } + + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + item = apol_vector_get_element(mod->result->items, i); + rt = item->item; + printf("%s\n", (tmp = apol_range_trans_render(policy, rt))); + free(tmp); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + rt = item->item; + printf("%s\n", (tmp = apol_range_trans_render(policy, rt))); + free(tmp); + for (j = 0; j < apol_vector_get_size(item->proof); j++) { + proof = apol_vector_get_element(item->proof, j); + printf("\t%s\n", proof->text); + } + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/imp_range_trans.h b/sechecker/modules/imp_range_trans.h new file mode 100644 index 0000000..04ceba0 --- /dev/null +++ b/sechecker/modules/imp_range_trans.h @@ -0,0 +1,52 @@ +/** + * @file + * Defines the interface for the impossible range_transition module. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author: David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef IMP_RANGE_TRANS +#define IMP_RANGE_TRANS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/role-query.h> +#include <apol/user-query.h> +#include <apol/range_trans-query.h> +#include <apol/rbacrule-query.h> +#include <apol/domain-trans-analysis.h> +#include <apol/policy-query.h> + + int imp_range_trans_register(sechk_lib_t * lib); + int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* IMP_RANGE_TRANS */ diff --git a/sechecker/modules/inc_dom_trans.c b/sechecker/modules/inc_dom_trans.c new file mode 100644 index 0000000..fe6957d --- /dev/null +++ b/sechecker/modules/inc_dom_trans.c @@ -0,0 +1,913 @@ +/** + * @file + * Defines the interface for the incomplete domain transition module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "inc_dom_trans.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "inc_dom_trans"; + +/* The register function registers all of a module's functions + * with the library. */ +int inc_dom_trans_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "domains with partial transition permissions"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds potential domain transitions missing key permissions. A valid\n" + "domain transition requires the following.\n" + "\n" + " 1) the starting domain can transition to the end domain for class process\n" + " 2) the end domain has some type as an entrypoint\n" + " 3) the starting domain can execute that extrypoint type\n" + " 4) (optional) a type transition rules specifying these three types\n"; + mod->opt_description = + "Module requirements:\n" + " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + /* assign requirements */ + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + /* Dependencies */ + apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_dom_trans_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_dom_trans_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_dom_trans_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid paramaters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* wrapper for apol_domain_trans_result_destroy() */ +void dtr_free_wrap(void *x) +{ + apol_domain_trans_result_destroy((apol_domain_trans_result_t **) & x); +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. */ +int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL, *tmp_item = NULL; + sechk_proof_t *proof = NULL; + size_t i, j, k, retv; + sechk_module_t *mod_ptr = NULL; + sechk_mod_fn_t run_fn = NULL; + sechk_result_t *find_domains_res = NULL; + apol_domain_trans_analysis_t *domain_trans = NULL; + apol_vector_t *domain_vector = NULL, *role_vector = NULL, *user_vector = NULL, *rbac_vector = NULL; + apol_vector_t *domain_trans_vector = NULL, *role_allow_vector = NULL; + apol_user_query_t *user_query = NULL; + apol_role_query_t *start_role_query = NULL, *end_role_query = NULL; + apol_role_trans_query_t *role_trans_query = NULL; + apol_role_allow_query_t *role_allow_query = NULL; + char *buff = NULL; + int buff_sz, error = 0; + const qpol_type_t *domain = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *domain_name = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = EINVAL; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + res->item_type = SECHK_ITEM_DTR; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (apol_policy_build_domain_trans_table(policy) < 0) { + error = errno; + ERR(policy, "%s", "Unable to build domain transition table"); + goto inc_dom_trans_run_fail; + } + + if (!(domain_trans = apol_domain_trans_analysis_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (!(user_query = apol_user_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (!(role_trans_query = apol_role_trans_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (!(role_allow_query = apol_role_allow_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (!(start_role_query = apol_role_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (!(end_role_query = apol_role_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib); + if (!run_fn) { + error = errno; + goto inc_dom_trans_run_fail; + } + + retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL); + if (retv) { + error = errno; + ERR(policy, "%s", "Unable to find module find_domains"); + goto inc_dom_trans_run_fail; + } + + if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) { + error = errno; + ERR(policy, "%s", "Unable to get results from module find_domains"); + goto inc_dom_trans_run_fail; + } + + domain_vector = (apol_vector_t *) find_domains_res->items; + + for (i = 0; i < apol_vector_get_size(domain_vector); i++) { + tmp_item = apol_vector_get_element(domain_vector, i); + domain = tmp_item->item; + qpol_type_get_name(q, domain, &domain_name); + apol_domain_trans_analysis_set_start_type(policy, domain_trans, domain_name); + apol_domain_trans_analysis_set_direction(policy, domain_trans, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); + apol_domain_trans_analysis_set_valid(policy, domain_trans, APOL_DOMAIN_TRANS_SEARCH_BOTH); + apol_domain_trans_analysis_do(policy, domain_trans, &domain_trans_vector); + + for (j = 0; j < apol_vector_get_size(domain_trans_vector); j++) { + apol_domain_trans_result_t *dtr = NULL; + const qpol_type_t *start; + const qpol_type_t *ep; + const qpol_type_t *end; + const char *start_name; + const char *end_name; + const char *ep_name; + int result; + bool ok; + + ok = false; + dtr = apol_vector_get_element(domain_trans_vector, j); + start = apol_domain_trans_result_get_start_type(dtr); + ep = apol_domain_trans_result_get_entrypoint_type(dtr); + end = apol_domain_trans_result_get_end_type(dtr); + if (start) + qpol_type_get_name(q, start, &start_name); + else + start_name = "<start_type>"; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = "<end_type>"; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = "<entrypoint_type>"; + + result = apol_domain_trans_table_verify_trans(policy, start, ep, end); + if (!result) { + apol_vector_t *start_role_vector, *end_role_vector, *common_role_vector; + apol_role_query_set_type(policy, start_role_query, start_name); + apol_role_get_by_query(policy, start_role_query, &start_role_vector); + apol_role_query_set_type(policy, end_role_query, end_name); + apol_role_get_by_query(policy, end_role_query, &end_role_vector); + if (!apol_vector_get_size(start_role_vector) || !apol_vector_get_size(end_role_vector)) { + item = sechk_item_new(dtr_free_wrap); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item->test_result = 1; + item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr); + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!apol_vector_get_size(start_role_vector)) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + asprintf(&proof->text, "Need role for %s", start_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + if (!apol_vector_get_size(end_role_vector)) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + asprintf(&proof->text, "Need role for %s", end_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + item = NULL; + //if one of the domains has no roles continue; no more can be determined + apol_vector_destroy(&start_role_vector); + apol_vector_destroy(&end_role_vector); + continue; + } + common_role_vector = + apol_vector_create_from_intersection(start_role_vector, end_role_vector, NULL, NULL); + const char *role_name = NULL; + if (apol_vector_get_size(common_role_vector)) { + for (int k = 0; k < apol_vector_get_size(common_role_vector); k++) { + const qpol_role_t *common_role; + + common_role = apol_vector_get_element(common_role_vector, k); + qpol_role_get_name(q, common_role, &role_name); + apol_user_query_set_role(policy, user_query, role_name); + apol_user_get_by_query(policy, user_query, &user_vector); + if (apol_vector_get_size(user_vector)) { + ok = true; + apol_vector_destroy(&user_vector); + break; + } + apol_vector_destroy(&user_vector); + } + if (!ok) { + item = sechk_item_new(dtr_free_wrap); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item->test_result = 1; + item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr); + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + asprintf(&proof->text, "Need user for role %s", role_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item = NULL; + } + } else { + apol_vector_t *role_trans_vector; + bool need_ra = 0, need_user = 0; + char *rastring = NULL, *userstring = NULL; + apol_role_trans_query_set_target(policy, role_trans_query, ep_name, 1); + apol_role_trans_get_by_query(policy, role_trans_query, &role_trans_vector); + const char *source_role_name = NULL, *default_role_name = NULL; + for (k = 0; k < apol_vector_get_size(role_trans_vector); k++) { + qpol_role_trans_t *role_trans; + const qpol_role_t *source_role; + const qpol_role_t *default_role; + int index; + + role_trans = apol_vector_get_element(role_trans_vector, k); + qpol_role_trans_get_source_role(q, role_trans, &source_role); + qpol_role_trans_get_default_role(q, role_trans, &default_role); + if ((apol_vector_get_index(start_role_vector, source_role, NULL, NULL, &index) == 0) + && (apol_vector_get_index(end_role_vector, default_role, NULL, NULL, &index) == + 0)) { + apol_vector_t *source_role_user, *default_role_user, *common_role_user; + + qpol_role_get_name(q, source_role, &source_role_name); + qpol_role_get_name(q, default_role, &default_role_name); + apol_role_allow_query_set_source(policy, role_allow_query, + source_role_name); + apol_role_allow_query_set_target(policy, role_allow_query, + default_role_name); + apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector); + + apol_user_query_set_role(policy, user_query, source_role_name); + apol_user_get_by_query(policy, user_query, &source_role_user); + apol_user_query_set_role(policy, user_query, default_role_name); + apol_user_get_by_query(policy, user_query, &default_role_user); + + common_role_user = + apol_vector_create_from_intersection(source_role_user, + default_role_user, NULL, NULL); + apol_vector_destroy(&source_role_user); + apol_vector_destroy(&default_role_user); + if (apol_vector_get_size(role_allow_vector) && + apol_vector_get_size(common_role_user)) { + ok = true; + apol_vector_destroy(&role_allow_vector); + apol_vector_destroy(&common_role_user); + break; + } + if (!apol_vector_get_size(role_allow_vector)) { + // need role allow; + asprintf(&rastring, "allow %s %s;", source_role_name, + default_role_name); + if (!rastring) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + apol_vector_destroy(&role_allow_vector); + if (!apol_vector_get_size(common_role_user)) { + // need user; + asprintf(&userstring, "need user with roles %s and %s", + source_role_name, default_role_name); + if (!userstring) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + apol_vector_destroy(&common_role_user); + } + } + apol_vector_destroy(&role_trans_vector); + if (!ok) { + if (!need_ra && !need_user) { + const qpol_role_t *source_role = + apol_vector_get_element(start_role_vector, 0); + const qpol_role_t *default_role = + apol_vector_get_element(end_role_vector, 0); + qpol_role_get_name(q, source_role, &source_role_name); + qpol_role_get_name(q, default_role, &default_role_name); + // need role_transition + item = sechk_item_new(dtr_free_wrap); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item->test_result = 1; + item->item = (void *) + apol_domain_trans_result_create_from_domain_trans_result(dtr); + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + asprintf(&proof->text, "role_transition %s %s %s;", source_role_name, + ep_name, default_role_name); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item = NULL; + } else { + //create item + item = sechk_item_new(dtr_free_wrap); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item->test_result = 1; + item->item = (void *) + apol_domain_trans_result_create_from_domain_trans_result(dtr); + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (need_ra) { + //create proof w/ text rastring + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + proof->text = rastring; + rastring = NULL; + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + if (need_user) { + //create proof w/ text userstring + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + proof->text = userstring; + userstring = NULL; + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + item = NULL; + } + } + } + apol_vector_destroy(&start_role_vector); + apol_vector_destroy(&end_role_vector); + apol_vector_destroy(&common_role_vector); + } else { + item = sechk_item_new(dtr_free_wrap); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + item->test_result = 1; + item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr); + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + + if (result & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + buff = NULL; + buff_sz = + 10 + strlen("allow : process transition;") + strlen(start_name) + strlen(end_name); + buff = (char *)calloc(buff_sz, sizeof(char)); + if (!buff) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + snprintf(buff, buff_sz, "allow %s %s : process transition;", start_name, end_name); + proof->text = strdup(buff); + free(buff); + buff = NULL; + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + + if (result & APOL_DOMAIN_TRANS_RULE_EXEC) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + buff = NULL; + buff_sz = 10 + strlen("allow : file execute;") + strlen(start_name) + strlen(ep_name); + buff = (char *)calloc(buff_sz, sizeof(char)); + if (!buff) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + snprintf(buff, buff_sz, "allow %s %s : file execute;", start_name, ep_name); + proof->text = strdup(buff); + free(buff); + buff = NULL; + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + + if (result & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + buff = NULL; + buff_sz = 10 + strlen("allow : file entrypoint;") + strlen(end_name) + strlen(ep_name); + buff = (char *)calloc(buff_sz, sizeof(char)); + if (!buff) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + snprintf(buff, buff_sz, "allow %s %s : file entrypoint;", end_name, ep_name); + proof->text = strdup(buff); + free(buff); + buff = NULL; + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + + if (result & APOL_DOMAIN_TRANS_RULE_TYPE_TRANS) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + buff = NULL; + buff_sz = + 10 + strlen("type_transition :process ;") + strlen(start_name) + strlen(end_name) + + strlen(ep_name); + buff = (char *)calloc(buff_sz, sizeof(char)); + if (!buff) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + snprintf(buff, buff_sz, "type_transition %s %s : process %s;", start_name, ep_name, + end_name); + proof->text = strdup(buff); + free(buff); + buff = NULL; + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + + if (result & APOL_DOMAIN_TRANS_RULE_SETEXEC) { + proof = sechk_proof_new(NULL); + proof->type = SECHK_ITEM_OTHER; + buff = NULL; + buff_sz = 10 + strlen("allow self : process setexec;") + strlen(start_name); + buff = (char *)calloc(buff_sz, sizeof(char)); + if (!buff) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + snprintf(buff, buff_sz, "allow %s self : process setexec;", start_name); + proof->text = strdup(buff); + free(buff); + buff = NULL; + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_dom_trans_run_fail; + } + } + } + } + apol_vector_destroy(&domain_trans_vector); + } + + mod->result = res; + apol_domain_trans_analysis_destroy(&domain_trans); + apol_user_query_destroy(&user_query); + apol_role_trans_query_destroy(&role_trans_query); + apol_role_query_destroy(&start_role_query); + apol_role_query_destroy(&end_role_query); + apol_role_allow_query_destroy(&role_allow_query); + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + inc_dom_trans_run_fail: + sechk_item_free(item); + apol_vector_destroy(&user_vector); + apol_vector_destroy(&domain_trans_vector); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + size_t i = 0, j = 0, num_items; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i incomplete transitions.\n", num_items); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & SECHK_OUT_LIST) { + /* + * printf("\nStart Type\t\tEntrypoint\t\tEnd Type\t\tMissing Rules\n"); + * printf("----------\t\t----------\t\t--------\t\t-------------\n"); + */ + printf("\n"); + for (i = 0; i < num_items; i++) { + const qpol_type_t *start; + const qpol_type_t *end; + const qpol_type_t *ep; + const char *start_name, *end_name, *ep_name; + apol_domain_trans_result_t *dtr; + + item = apol_vector_get_element(mod->result->items, i); + dtr = item->item; + start = apol_domain_trans_result_get_start_type(dtr); + ep = apol_domain_trans_result_get_entrypoint_type(dtr); + end = apol_domain_trans_result_get_end_type(dtr); + if (start) + qpol_type_get_name(q, start, &start_name); + else + start_name = "<start_type>"; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = "<end_type>"; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = "<entrypoint_type>"; + + printf("%s -> %s\tentrypoint: %s\n", start_name, end_name, ep_name); + } + printf("\n"); + } + /* The proof report component is a display of a list of items + * with an indented list of proof statements supporting the result + * of the check for that item (e.g. rules with a given type) */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (i = 0; i < num_items; i++) { + const qpol_type_t *start; + const qpol_type_t *end; + const qpol_type_t *ep; + const char *start_name, *end_name, *ep_name; + apol_domain_trans_result_t *dtr; + + item = apol_vector_get_element(mod->result->items, i); + dtr = item->item; + start = apol_domain_trans_result_get_start_type(dtr); + ep = apol_domain_trans_result_get_entrypoint_type(dtr); + end = apol_domain_trans_result_get_end_type(dtr); + if (start) + qpol_type_get_name(q, start, &start_name); + else + start_name = "<start_type>"; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = "<end_type>"; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = "<entrypoint_type>"; + + printf("%s -> %s\tentrypoint: %s\n\tMissing:\n", start_name, end_name, ep_name); + for (j = 0; j < apol_vector_get_size(item->proof); j++) { + sechk_proof_t *proof; + + proof = apol_vector_get_element(item->proof, j); + if (proof) { + printf("\t%s\n", proof->text); + } + } + } + } + + return 0; +} diff --git a/sechecker/modules/inc_dom_trans.h b/sechecker/modules/inc_dom_trans.h new file mode 100644 index 0000000..02dffbf --- /dev/null +++ b/sechecker/modules/inc_dom_trans.h @@ -0,0 +1,56 @@ +/** + * @file + * Defines the interface for the incomplete domain transition module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef INC_DOM_TRANS +#define INC_DOM_TRANS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/domain-trans-analysis.h> +#include <apol/user-query.h> +#include <apol/rbacrule-query.h> +#include <apol/role-query.h> + +#define SECHK_INC_DOM_TRANS_HAS_TT 0x08 +#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04 +#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02 +#define SECHK_INC_DOM_TRANS_HAS_EP 0x01 +#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC) + + int inc_dom_trans_register(sechk_lib_t * lib); + int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/inc_mount.c b/sechecker/modules/inc_mount.c new file mode 100644 index 0000000..4e9f8b1 --- /dev/null +++ b/sechecker/modules/inc_mount.c @@ -0,0 +1,520 @@ +/** + * @file + * Implementation of the incomplete mount permissions module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "inc_mount.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "inc_mount"; + +/* The register function registers all of a module's functions + * with the library. */ +int inc_mount_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "no library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "domains with partial mount permissions"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds domains that have incomplete mount permissions.\n" + "In order for a mount operation to be allowed by the policy the following rules\n" + "must be present: \n" + "\n" + " 1) allow somedomain_d sometype_t : filesystem { mount };\n" + " 2) allow somedomain_d sometype_t : dir { mounton };\n" + "\n" "This module finds domains that have only one of the rules listed above.\n"; + mod->opt_description = + "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_mount_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_mount_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_mount_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ + +int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i, j; + bool both = false, add_proof = false; + int error = 0; + char *tmp = NULL; + apol_vector_t *mount_vector; + apol_vector_t *mounton_vector; + apol_avrule_query_t *mount_avrule_query = NULL; + apol_avrule_query_t *mounton_avrule_query = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + + if (!(mount_avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + + if (!(mounton_avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + + /* Get avrules for filesystem mount */ + apol_avrule_query_set_rules(policy, mount_avrule_query, QPOL_RULE_ALLOW); + apol_avrule_query_append_class(policy, mount_avrule_query, "filesystem"); + apol_avrule_query_append_perm(policy, mount_avrule_query, "mount"); + apol_avrule_get_by_query(policy, mount_avrule_query, &mount_vector); + + /* Get avrules for dir mounton */ + apol_avrule_query_set_rules(policy, mounton_avrule_query, QPOL_RULE_ALLOW); + apol_avrule_query_append_class(policy, mounton_avrule_query, "dir"); + apol_avrule_query_append_perm(policy, mounton_avrule_query, "mounton"); + apol_avrule_get_by_query(policy, mounton_avrule_query, &mounton_vector); + + for (i = 0; i < apol_vector_get_size(mount_vector); i++) { + const qpol_avrule_t *mount_rule; + const qpol_type_t *mount_source; + const qpol_type_t *mount_target; + const char *mount_source_name, *mount_target_name; + + both = false; + add_proof = true; + mount_rule = apol_vector_get_element(mount_vector, i); + qpol_avrule_get_source_type(q, mount_rule, &mount_source); + qpol_avrule_get_target_type(q, mount_rule, &mount_target); + qpol_type_get_name(q, mount_source, &mount_source_name); + qpol_type_get_name(q, mount_target, &mount_target_name); + + for (j = 0; j < apol_vector_get_size(mounton_vector); j++) { + const qpol_avrule_t *mounton_rule; + const qpol_type_t *mounton_source; + const qpol_type_t *mounton_target; + const char *mounton_source_name, *mounton_target_name; + + mounton_rule = apol_vector_get_element(mounton_vector, j); + qpol_avrule_get_source_type(q, mounton_rule, &mounton_source); + qpol_avrule_get_target_type(q, mounton_rule, &mounton_target); + qpol_type_get_name(q, mounton_source, &mounton_source_name); + qpol_type_get_name(q, mounton_target, &mounton_target_name); + + /* Check to see if they match */ + if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name)) + both = true; + } + if (!both) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + proof->type = SECHK_ITEM_AVRULE; + proof->elem = (void *)mount_rule; + tmp = apol_avrule_render(policy, mount_rule); + asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : dir mounton ;\n", + tmp, mount_source_name, mount_target_name); + free(tmp); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(mount_source_name, res_type_name) || !strcmp(mount_target_name, res_type_name)) + add_proof = false; + } + if (add_proof) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(NULL, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + item->item = (void *)mount_source; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + item = NULL; + proof = NULL; + } + sechk_proof_free(proof); + proof = NULL; + } + } + + for (i = 0; i < apol_vector_get_size(mounton_vector); i++) { + const qpol_avrule_t *mounton_rule; + const qpol_type_t *mounton_source; + const qpol_type_t *mounton_target; + const char *mounton_source_name, *mounton_target_name; + + both = false; + add_proof = true; + mounton_rule = apol_vector_get_element(mounton_vector, i); + qpol_avrule_get_source_type(q, mounton_rule, &mounton_source); + qpol_avrule_get_target_type(q, mounton_rule, &mounton_target); + qpol_type_get_name(q, mounton_source, &mounton_source_name); + qpol_type_get_name(q, mounton_target, &mounton_target_name); + + for (j = 0; j < apol_vector_get_size(mount_vector); j++) { + const qpol_avrule_t *mount_rule; + const qpol_type_t *mount_source; + const qpol_type_t *mount_target; + const char *mount_source_name, *mount_target_name; + + mount_rule = apol_vector_get_element(mount_vector, j); + qpol_avrule_get_source_type(q, mount_rule, &mount_source); + qpol_avrule_get_target_type(q, mount_rule, &mount_target); + qpol_type_get_name(q, mount_source, &mount_source_name); + qpol_type_get_name(q, mount_target, &mount_target_name); + + if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name)) + both = true; + } + if (!both) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + proof->type = SECHK_ITEM_AVRULE; + proof->elem = (void *)mounton_rule; + tmp = apol_avrule_render(policy, mounton_rule); + asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : filesystem mount ;\n", + tmp, mounton_source_name, mounton_target_name); + free(tmp); + for (j = 0; j < apol_vector_get_size(res->items); j++) { + sechk_item_t *res_item; + const qpol_type_t *res_type; + const char *res_type_name; + + res_item = apol_vector_get_element(res->items, j); + res_type = res_item->item; + qpol_type_get_name(q, res_type, &res_type_name); + if (!strcmp(mounton_source_name, res_type_name) || !strcmp(mounton_target_name, res_type_name)) + add_proof = false; + } + if (add_proof) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(NULL, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + item->item = (void *)mounton_source; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_mount_run_fail; + } + item = NULL; + proof = NULL; + } + sechk_proof_free(proof); + proof = NULL; + } + } + apol_vector_destroy(&mount_vector); + apol_vector_destroy(&mounton_vector); + + mod->result = res; + apol_avrule_query_destroy(&mount_avrule_query); + apol_avrule_query_destroy(&mounton_avrule_query); + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + inc_mount_run_fail: + apol_vector_destroy(&mount_vector); + apol_vector_destroy(&mounton_vector); + apol_avrule_query_destroy(&mount_avrule_query); + apol_avrule_query_destroy(&mounton_avrule_query); + sechk_proof_free(proof); + sechk_item_free(item); + free(tmp); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k, l, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd types.\n", num_items); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + /* The proof report component is a display of a list of items + * with an indented list of proof statements supporting the result + * of the check for that item (e.g. rules with a given type) + * this field also lists the computed severity of each item + * (see sechk_item_sev in sechecker.c for details on calculation) + * items are printed on a line either with the severity. + * Each proof element is then displayed in an indented list one per + * line below it. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/inc_mount.h b/sechecker/modules/inc_mount.h new file mode 100644 index 0000000..18d5179 --- /dev/null +++ b/sechecker/modules/inc_mount.h @@ -0,0 +1,54 @@ +/** + * @file + * Defines the interface for the incomplete mount permissions module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef INC_MOUNT +#define INC_MOUNT + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/avrule-query.h> + +#define SECHK_MOUNT_ONLY_MOUNT 0x01 +#define SECHK_MOUNT_ONLY_MOUNTON 0x02 + +/* Module functions: + * NOTE: while using a modular format SEChecker is built + * statically; this means that all modules and their functions + * are in the same namespace. */ + int inc_mount_register(sechk_lib_t * lib); + int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/inc_net_access.c b/sechecker/modules/inc_net_access.c new file mode 100644 index 0000000..a8903ea --- /dev/null +++ b/sechecker/modules/inc_net_access.c @@ -0,0 +1,1852 @@ +/** + * @file + * Defines the interface for the incomplete network access module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 "inc_net_access.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +static const char *const mod_name = "inc_net_access"; + +/* The register function registers all of a module's functions + * with the library. You should not need to edit this function + * unless you are adding additional functions you need other modules + * to call. See the note at the bottom of this function to do so. */ +int inc_net_access_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "finds network domains with inadequate permissions"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all network domains in a policy which do not have the \n" + "required permissions needed to facilitate network communication. For network\n" + "domains to communicate, the following conditions must be true:\n" + " 1) the domain must have read or receive permissions on a socket of the same\n" + " type\n" + " 2) the domain must have send or receive permissions on an IPsec association\n" + " (see find_assoc_types)\n" + " 3) the domain must have send or receive permissions on netif objects for a\n" + " netif type (see find_netif_types)\n" + " 4) the domain must have send or receive permissions on node objects for a\n" + " node type (see find_node_types)\n" + " 5) the domain must have send or receive permissions on port objects for a\n" + " port type (see find_port_types)\n"; + mod->opt_description = + " Module requirements:\n" + " none\n" " Module dependencies:\n" " find_net_domains\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + /* assign dependencies */ + if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_net_domains")) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. + * Add any option processing logic as indicated below. */ +int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* This set of defines represents individual permission bits for + * the permissions needed to have complete network access */ +/* allow domain self : sock_file {read write getattr}; */ +#define PERM_SELF_SOCK_FILE_READ 0x00000001 +#define PERM_SELF_SOCK_FILE_WRITE 0x00000002 +#define PERM_SELF_SOCK_FILE_GETATTR 0x00000004 +/* allow domain self : tcp_socket {create read write}; */ +#define PERM_SELF_TCP_SOC_READ 0x00000008 +#define PERM_SELF_TCP_SOC_WRITE 0x00000010 +#define PERM_SELF_TCP_SOC_CREATE 0x00000020 +/* allow domain self : udp_socket {create read write}; */ +#define PERM_SELF_UDP_SOC_READ 0x00000040 +#define PERM_SELF_UDP_SOC_WRITE 0x00000080 +#define PERM_SELF_UDP_SOC_CREATE 0x00000100 +/* allow domain if_type : netif {tcp_send udp_send tcp_recv tcp_send}; */ +#define PERM_NETIF_TCP_SEND 0x00000200 +#define PERM_NETIF_UDP_SEND 0x00000400 +#define PERM_NETIF_TCP_RECV 0x00000800 +#define PERM_NETIF_UDP_RECV 0x00001000 +/* allow domain node_type : node {tcp_send udp_send tcp_recv tcp_send}; */ +#define PERM_NODE_TCP_SEND 0x00002000 +#define PERM_NODE_UDP_SEND 0x00004000 +#define PERM_NODE_TCP_RECV 0x00008000 +#define PERM_NODE_UDP_RECV 0x00010000 +/* allow domain port_type : tcp_socket {send_msg recv_msg}; */ +#define PERM_PORT_TCP_SEND 0x00020000 +#define PERM_PORT_TCP_RECV 0x00040000 +/* allow domain port_type : udp_socket {send_msg recv_msg}; */ +#define PERM_PORT_UDP_SEND 0x00080000 +#define PERM_PORT_UDP_RECV 0x00100000 +/* allow domain assoc_type : association {sendto recvfrom}; */ +#define PERM_ASSOC_SEND 0x00200000 +#define PERM_ASSOC_RECV 0x00400000 + +/* this set of defines represents masks for individual rules */ +#define RULE_TCP_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_UDPs_SOCK_FILE (PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_UDPr_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_TCP_SELF_SOC (PERM_SELF_TCP_SOC_READ|PERM_SELF_TCP_SOC_WRITE|PERM_SELF_TCP_SOC_CREATE) +#define RULE_UDPs_SELF_SOC (PERM_SELF_UDP_SOC_WRITE|PERM_SELF_UDP_SOC_CREATE) +#define RULE_UDPr_SELF_SOC (PERM_SELF_UDP_SOC_READ|PERM_SELF_UDP_SOC_CREATE) +#define RULE_TCP_NETIF (PERM_NETIF_TCP_SEND|PERM_NETIF_TCP_RECV) +#define RULE_UDPs_NETIF (PERM_NETIF_UDP_SEND) +#define RULE_UDPr_NETIF (PERM_NETIF_UDP_RECV) +#define RULE_TCP_NODE (PERM_NODE_TCP_SEND|PERM_NODE_TCP_RECV) +#define RULE_UDPs_NODE (PERM_NODE_UDP_SEND) +#define RULE_UDPr_NODE (PERM_NODE_UDP_RECV) +#define RULE_TCP_PORT (PERM_PORT_TCP_SEND|PERM_PORT_TCP_RECV) +#define RULE_UDPs_PORT (PERM_PORT_UDP_SEND) +#define RULE_UDPr_PORT (PERM_PORT_UDP_RECV) +#define RULE_TCP_ASSOC (PERM_ASSOC_SEND|PERM_ASSOC_RECV) +#define RULE_UDPs_ASSOC (PERM_ASSOC_SEND) +#define RULE_UDPr_ASSOC (PERM_ASSOC_RECV) + +/* This set of defines represents mask sets to represent access types */ +#define UDP_RECV_PERM_SET (RULE_UDPr_SOCK_FILE|RULE_UDPr_SELF_SOC|RULE_UDPr_NETIF|RULE_UDPr_NODE|RULE_UDPr_PORT|RULE_UDPr_ASSOC) +#define UDP_SEND_PERM_SET (RULE_UDPs_SOCK_FILE|RULE_UDPs_SELF_SOC|RULE_UDPs_NETIF|RULE_UDPs_NODE|RULE_UDPs_PORT|RULE_UDPs_ASSOC) +#define TCP_FULL_PERM_SET (RULE_TCP_SOCK_FILE|RULE_TCP_SELF_SOC|RULE_TCP_NETIF|RULE_TCP_NODE|RULE_TCP_PORT|RULE_TCP_ASSOC) +#define COMMON_ACCESS_SET (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR|PERM_ASSOC_SEND|PERM_ASSOC_RECV) + +typedef struct net_state +{ + uint32_t perms; + apol_vector_t *netifs; + apol_vector_t *nodes; + apol_vector_t *tcpsocs; + apol_vector_t *udpsocs; + apol_vector_t *assocs; +} net_state_t; + +typedef struct name_perm +{ + const char *name; /* will be from policy do not free */ + uint32_t perms; +} name_perm_t; + +static void net_state_destroy(net_state_t ** n) +{ + if (!n || !(*n)) + return; + + apol_vector_destroy(&((*n)->netifs)); + apol_vector_destroy(&((*n)->nodes)); + apol_vector_destroy(&((*n)->tcpsocs)); + apol_vector_destroy(&((*n)->udpsocs)); + apol_vector_destroy(&((*n)->assocs)); + free(*n); + *n = NULL; +} + +static net_state_t *net_state_create(void) +{ + net_state_t *n = NULL; + + n = calloc(1, sizeof(*n)); + n->netifs = apol_vector_create(free); + n->nodes = apol_vector_create(free); + n->tcpsocs = apol_vector_create(free); + n->udpsocs = apol_vector_create(free); + n->assocs = apol_vector_create(free); + + return n; +} + +static int name_perm_comp(const void *a, const void *b, void *arg __attribute__ ((unused))) +{ + const name_perm_t *x = a; + const name_perm_t *y = b; + + return strcmp(x->name, y->name); +} + +static name_perm_t *name_perm_create(const char *name) +{ + name_perm_t *np = NULL; + + np = calloc(1, sizeof(*np)); + np->name = name; + + return np; +} + +static int name_perm_vector_has_incomplete_perms(apol_vector_t * v, uint32_t mask) +{ + uint32_t tmp; + name_perm_t *np = NULL; + size_t i = 0; + + if (!apol_vector_get_size(v)) + return 1; + for (i = 0; i < apol_vector_get_size(v); i++) { + np = apol_vector_get_element(v, i); + tmp = np->perms & mask; + if (tmp != mask) + return 1; + } + + return 0; +} + +static void name_perm_vector_add_perm(apol_vector_t * v, const char *name, uint32_t perm) +{ + name_perm_t *np = NULL; + size_t i = 0; + int retv; + + np = name_perm_create(name); + retv = apol_vector_get_index(v, np, name_perm_comp, NULL, &i); + if (retv) { + np->perms = perm; + apol_vector_append(v, (void *)np); + } else { + free(np); /* already exists free temp one */ + np = apol_vector_get_element(v, i); + np->perms |= perm; + } +} + +static char *generate_tcp_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == TCP_FULL_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has TCP access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete TCP access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SOCK_FILE; + missing = attempt ^ RULE_TCP_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SELF_SOC; + missing = attempt ^ RULE_TCP_SELF_SOC; + asprintf(&tmp, "allow %s self : tcp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_TCP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_TCP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_TCP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_TCP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_TCP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_TCP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_TCP_NETIF; + missing = attempt ^ RULE_TCP_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (attempt & PERM_NETIF_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (missing & PERM_NETIF_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <netif_type> : netif { tcp_send tcp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_TCP_NODE; + missing = attempt ^ RULE_TCP_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (attempt & PERM_NODE_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (missing & PERM_NODE_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <node_type> : node { tcp_send tcp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->tcpsocs); i++) { + np = apol_vector_get_element(state->tcpsocs, i); + attempt = state->perms & RULE_TCP_PORT; + missing = attempt ^ RULE_TCP_PORT; + asprintf(&tmp, "allow %s %s : tcp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (attempt & PERM_PORT_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (missing & PERM_PORT_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->tcpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <port_type> : tcp_socket { send_msg recv_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_TCP_ASSOC; + missing = attempt ^ RULE_TCP_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (missing & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto recvfrom };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_udp_send_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == UDP_SEND_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has UDP send access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP send access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_UDPs_SOCK_FILE; + missing = attempt ^ RULE_UDPs_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_UDPs_SELF_SOC; + missing = attempt ^ RULE_UDPs_SELF_SOC; + asprintf(&tmp, "allow %s self : udp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_UDP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_UDP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_UDPs_NETIF; + missing = attempt ^ RULE_UDPs_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_send };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_UDPs_NODE; + missing = attempt ^ RULE_UDPs_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_send };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) { + np = apol_vector_get_element(state->udpsocs, i); + attempt = state->perms & RULE_UDPs_PORT; + missing = attempt ^ RULE_UDPs_PORT; + asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->udpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { send_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_UDPs_ASSOC; + missing = attempt ^ RULE_UDPs_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_udp_recv_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == UDP_RECV_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has UDP receive access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP receive access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_UDPr_SOCK_FILE; + missing = attempt ^ RULE_UDPr_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_UDPr_SELF_SOC; + missing = attempt ^ RULE_UDPr_SELF_SOC; + asprintf(&tmp, "allow %s self : udp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_UDP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_UDP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_UDPr_NETIF; + missing = attempt ^ RULE_UDPr_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_UDPr_NODE; + missing = attempt ^ RULE_UDPr_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) { + np = apol_vector_get_element(state->udpsocs, i); + attempt = state->perms & RULE_UDPr_PORT; + missing = attempt ^ RULE_UDPr_PORT; + asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->udpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { recv_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_UDPr_ASSOC; + missing = attempt ^ RULE_UDPr_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " <association_type> : association { recvfrom };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_common_only_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0; + name_perm_t *np = NULL; + + if (apol_str_append + (&text, &text_sz, + "Domain has incomplete network access.\n\tDomain has no protocol specific permissions only the following:")) + goto err; + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_TCP_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL, *tmp_item = NULL; + sechk_proof_t *proof = NULL; + sechk_result_t *net_domain_res = NULL; + sechk_name_value_t *dep = NULL; + sechk_mod_fn_t run_fn = NULL; + size_t i = 0, j = 0; + int error = 0; + apol_avrule_query_t *avrule_query = NULL; + apol_vector_t *avrule_vector = NULL, *net_domain_vector = NULL; + const qpol_type_t *net_domain = NULL, *tmp_type = NULL; + const char *net_domain_name = NULL, *tgt_name = NULL; + char *perm_name = NULL; + const qpol_avrule_t *rule = NULL; + qpol_iterator_t *iter = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + net_state_t *state = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_net_access_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_net_access_run_fail; + } + + /* run dependencies */ + for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) { + dep = apol_vector_get_element(mod->dependencies, i); + run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib); + run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL); + } + + net_domain_res = sechk_lib_get_module_result("find_net_domains", mod->parent_lib); + if (!net_domain_res) { + error = errno; + ERR(policy, "%s", "Unable to get results for module find_net_domains"); + goto inc_net_access_run_fail; + } + net_domain_vector = (apol_vector_t *) net_domain_res->items; + + avrule_query = apol_avrule_query_create(); + if (!avrule_query) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW); + + for (i = 0; i < apol_vector_get_size(net_domain_vector); i++) { + tmp_item = apol_vector_get_element(net_domain_vector, i); + net_domain = tmp_item->item; + qpol_type_get_name(q, net_domain, &net_domain_name); + state = net_state_create(); + + /* find any self sock_file perms */ + apol_avrule_query_set_source(policy, avrule_query, net_domain_name, 1); + apol_avrule_query_set_target(policy, avrule_query, net_domain_name, 1); + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "sock_file"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_SOCK_FILE_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_SOCK_FILE_WRITE; + } else if (!strcmp(perm_name, "getattr")) { + state->perms |= PERM_SELF_SOCK_FILE_GETATTR; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any self tcp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "tcp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_TCP_SOC_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_TCP_SOC_WRITE; + } else if (!strcmp(perm_name, "create")) { + state->perms |= PERM_SELF_TCP_SOC_CREATE; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any self udp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "udp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_UDP_SOC_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_UDP_SOC_WRITE; + } else if (!strcmp(perm_name, "create")) { + state->perms |= PERM_SELF_UDP_SOC_CREATE; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any if_t netif perms */ + apol_avrule_query_set_target(policy, avrule_query, NULL, 0); + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "netif"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "tcp_send")) { + state->perms |= PERM_NETIF_TCP_SEND; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_SEND); + } else if (!strcmp(perm_name, "tcp_recv")) { + state->perms |= PERM_NETIF_TCP_RECV; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_RECV); + } else if (!strcmp(perm_name, "udp_send")) { + state->perms |= PERM_NETIF_UDP_SEND; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_SEND); + } else if (!strcmp(perm_name, "udp_recv")) { + state->perms |= PERM_NETIF_UDP_RECV; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any node_t node perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "node"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "tcp_send")) { + state->perms |= PERM_NODE_TCP_SEND; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_SEND); + } else if (!strcmp(perm_name, "tcp_recv")) { + state->perms |= PERM_NODE_TCP_RECV; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_RECV); + } else if (!strcmp(perm_name, "udp_send")) { + state->perms |= PERM_NODE_UDP_SEND; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_SEND); + } else if (!strcmp(perm_name, "udp_recv")) { + state->perms |= PERM_NODE_UDP_RECV; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any port_t tcp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "tcp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + /* skip self */ + if (!strcmp(net_domain_name, tgt_name)) + continue; + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "send_msg")) { + state->perms |= PERM_PORT_TCP_SEND; + name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_SEND); + } else if (!strcmp(perm_name, "recv_msg")) { + state->perms |= PERM_PORT_TCP_RECV; + name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any port_t udp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "udp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + /* skip self */ + if (!strcmp(net_domain_name, tgt_name)) + continue; + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "send_msg")) { + state->perms |= PERM_PORT_UDP_SEND; + name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_SEND); + } else if (!strcmp(perm_name, "recv_msg")) { + state->perms |= PERM_PORT_UDP_RECV; + name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any assoc_t association perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "association"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "sendto")) { + state->perms |= PERM_ASSOC_SEND; + name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_SEND); + } else if (!strcmp(perm_name, "recvfrom")) { + state->perms |= PERM_ASSOC_RECV; + name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* if has tcp perms check for missing ones */ + if ((state->perms & ((~(COMMON_ACCESS_SET)) & (TCP_FULL_PERM_SET))) && + ((state->perms & RULE_TCP_SOCK_FILE) != RULE_TCP_SOCK_FILE || + (state->perms & RULE_TCP_SELF_SOC) != RULE_TCP_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_TCP_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_TCP_NODE) || + name_perm_vector_has_incomplete_perms(state->tcpsocs, RULE_TCP_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_TCP_ASSOC))) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_tcp_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has udp send perms check for missing perms */ + if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_SEND_PERM_SET))) && + ((state->perms & RULE_UDPs_SOCK_FILE) != RULE_UDPs_SOCK_FILE || + (state->perms & RULE_UDPs_SELF_SOC) != RULE_UDPs_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPs_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPs_NODE) || + name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPs_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPs_ASSOC))) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_udp_send_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has udp reveive perms check for missing perms */ + if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_RECV_PERM_SET))) && + ((state->perms & RULE_UDPr_SOCK_FILE) != RULE_UDPr_SOCK_FILE || + (state->perms & RULE_UDPr_SELF_SOC) != RULE_UDPr_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPr_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPr_NODE) || + name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPr_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPr_ASSOC))) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_udp_recv_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has only common access perms report that */ + if (!(state->perms & (~(COMMON_ACCESS_SET)))) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_common_only_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + + if (item) { + if (apol_vector_append(res->items, (void *)item)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item = NULL; + } + net_state_destroy(&state); + } + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + inc_net_access_run_fail: + apol_avrule_query_destroy(&avrule_query); + apol_vector_destroy(&avrule_vector); + qpol_iterator_destroy(&iter); + free(perm_name); + net_state_destroy(&state); + sechk_item_free(item); + sechk_proof_free(proof); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the + * results to stdout. */ +int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i network domains with insufficient permissions.\n", num_items); + } + + /* Print current permissions then the permissions that are missing */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + i = 0; + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/inc_net_access.h b/sechecker/modules/inc_net_access.h new file mode 100644 index 0000000..746db40 --- /dev/null +++ b/sechecker/modules/inc_net_access.h @@ -0,0 +1,51 @@ +/** + * @file + * Defines the interface for the incomplete network access module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef INC_NET_ACCESS_H +#define INC_NET_ACCESS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/avrule-query.h> + +/* Module functions: + * Do not change any of these prototypes or you will not be + * able to run the module in the library */ + int inc_net_access_register(sechk_lib_t * lib); + int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/roles_wo_allow.c b/sechecker/modules/roles_wo_allow.c new file mode 100644 index 0000000..3d55bc8 --- /dev/null +++ b/sechecker/modules/roles_wo_allow.c @@ -0,0 +1,387 @@ +/** + * @file + * Implementation of the roles without allow rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "roles_wo_allow.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "roles_wo_allow"; + +/* The register function registers all of a module's functions + * with the library. */ +int roles_wo_allow_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "roles with no roleallow rules"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds roles defined in the policy that are not used in any role\n" + "allow rules. It is not possible to transition to or from any role that does not\n" "have any role allow rules.\n"; + mod->opt_description = + "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_allow_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_allow_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_allow_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_allow_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *role_vector; + apol_vector_t *role_allow_vector; + apol_role_allow_query_t *role_allow_query = NULL; + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + res->item_type = SECHK_ITEM_ROLE; + + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + + if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + if ((role_allow_query = apol_role_allow_query_create()) == NULL) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + + for (i = 0; i < apol_vector_get_size(role_vector); i++) { + const qpol_role_t *role; + const char *role_name; + + role = apol_vector_get_element(role_vector, i); + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + + if (!strcmp(role_name, "object_r")) + continue; + + apol_role_allow_query_set_source(policy, role_allow_query, role_name); + apol_role_allow_query_set_source_any(policy, role_allow_query, 1); + apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector); + if (apol_vector_get_size(role_allow_vector) > 0) { + apol_vector_destroy(&role_allow_vector); + continue; + } + apol_vector_destroy(&role_allow_vector); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + proof->type = SECHK_ITEM_ROLE; + proof->text = strdup("Role has no allow.\n"); + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + item->item = (void *)role; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_allow_run_fail; + } + item = NULL; + proof = NULL; + } + apol_vector_destroy(&role_vector); + apol_vector_destroy(&role_allow_vector); + apol_role_allow_query_destroy(&role_allow_query); + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + roles_wo_allow_run_fail: + apol_vector_destroy(&role_vector); + apol_vector_destroy(&role_allow_vector); + apol_role_allow_query_destroy(&role_allow_query); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + size_t i = 0, j = 0, num_items; + const qpol_role_t *role; + const char *role_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd roles.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following roles do not appear in any allow rules.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + role = (qpol_role_t *) item->item; + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + return 0; +} + +int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/roles_wo_allow.h b/sechecker/modules/roles_wo_allow.h new file mode 100644 index 0000000..c9dd44e --- /dev/null +++ b/sechecker/modules/roles_wo_allow.h @@ -0,0 +1,49 @@ +/** + * @file + * Defines the interface for the roles without allow rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef ROLES_WO_ALLOW +#define ROLES_WO_ALLOW + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/role-query.h> +#include <apol/rbacrule-query.h> + + int roles_wo_allow_register(sechk_lib_t * lib); + int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/roles_wo_types.c b/sechecker/modules/roles_wo_types.c new file mode 100644 index 0000000..ed38580 --- /dev/null +++ b/sechecker/modules/roles_wo_types.c @@ -0,0 +1,330 @@ +/** + * @file + * Implementation of the roles without types module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "roles_wo_types.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "roles_wo_types"; + +/* The register function registers all of a module's functions + * with the library. */ +int roles_wo_types_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign descriptions */ + mod->brief_description = "roles with no types"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds roles in the policy that have no types. A role with no types \n" + "cannot form a valid context.\n"; + mod->opt_description = + "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_types_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_types_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_types_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Ivalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *role_vector; + qpol_iterator_t *type_iter = NULL; + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Ivalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + res->item_type = SECHK_ITEM_ROLE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + + if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + + for (i = 0; i < apol_vector_get_size(role_vector); i++) { + const qpol_role_t *role; + const char *role_name; + int at_end; + + role = apol_vector_get_element(role_vector, i); + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + + if (!strcmp(role_name, "object_r")) + continue; + + qpol_role_get_type_iter(apol_policy_get_qpol(policy), role, &type_iter); + at_end = qpol_iterator_end(type_iter); + qpol_iterator_destroy(&type_iter); + if (!at_end) + continue; + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + proof->type = SECHK_ITEM_ROLE; + asprintf(&proof->text, "role %s has no types", role_name); + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + item->item = (void *)role; + item->test_result = 1; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_types_run_fail; + } + } + apol_vector_destroy(&role_vector); + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + roles_wo_types_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text printed in the + * report and prints it to stdout. */ +int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + size_t i = 0, j = 0, num_items; + const qpol_role_t *role; + const char *role_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + /* display the statistics of the results */ + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd roles.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following roles have no associated types:\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + role = (qpol_role_t *) item->item; + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/roles_wo_types.h b/sechecker/modules/roles_wo_types.h new file mode 100644 index 0000000..1a241d0 --- /dev/null +++ b/sechecker/modules/roles_wo_types.h @@ -0,0 +1,47 @@ +/** + * @file + * Defines the interface for the roles without types module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef ROLES_WO_TYPES +#define ROLES_WO_TYPES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/role-query.h> + + int roles_wo_types_register(sechk_lib_t * lib); + int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/roles_wo_users.c b/sechecker/modules/roles_wo_users.c new file mode 100644 index 0000000..c590880 --- /dev/null +++ b/sechecker/modules/roles_wo_users.c @@ -0,0 +1,392 @@ +/** + * @file + * Defines the interface for the roles without users module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "roles_wo_users.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "roles_wo_users"; + +/* The register function registers all of a module's functions + * with the library. */ +int roles_wo_users_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "roles not assigned to users"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds roles that are not assigned to users. If a role is not \n" + "assigned to a user it cannot form a valid context.\n"; + mod->opt_description = + "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_users_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_users_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_users_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = roles_wo_users_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *role_vector; + apol_vector_t *user_vector; + apol_user_query_t *user_query = NULL; + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + res->item_type = SECHK_ITEM_ROLE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + + if (!(user_query = apol_user_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + + if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) { + error = errno; + ERR(policy, "%s", "Unable to retrieve roles"); + return -1; + } + + for (i = 0; i < apol_vector_get_size(role_vector); i++) { + const qpol_role_t *role; + const char *role_name; + + role = apol_vector_get_element(role_vector, i); + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + + if (!strcmp(role_name, "object_r")) + continue; + + apol_user_query_set_role(policy, user_query, role_name); + apol_user_get_by_query(policy, user_query, &user_vector); + if (apol_vector_get_size(user_vector) > 0) { + apol_vector_destroy(&user_vector); + continue; + } + apol_vector_destroy(&user_vector); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + item->item = (void *)role; + item->test_result = 1; + proof->type = SECHK_ITEM_ROLE; + proof->text = strdup("This role is not assigned to any user."); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto roles_wo_users_run_fail; + } + item = NULL; + proof = NULL; + } + apol_vector_destroy(&role_vector); + apol_vector_destroy(&user_vector); + apol_user_query_destroy(&user_query); + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + roles_wo_users_run_fail: + apol_vector_destroy(&role_vector); + apol_vector_destroy(&user_vector); + apol_user_query_destroy(&user_query); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text printed in the + * report and prints it to stdout. */ +int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + const qpol_role_t *role; + const char *role_name; + size_t i = 0, j = 0, num_items; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd roles.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following roles are not associated with any users.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + role = (qpol_role_t *) item->item; + qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name); + printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + return 0; +} + +int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + + return 0; +} diff --git a/sechecker/modules/roles_wo_users.h b/sechecker/modules/roles_wo_users.h new file mode 100644 index 0000000..261bebb --- /dev/null +++ b/sechecker/modules/roles_wo_users.h @@ -0,0 +1,53 @@ +/** + * @file + * Defines the interface for the roles without users module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef ROLES_WO_USERS +#define ROLES_WO_USERS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/user-query.h> +#include <apol/role-query.h> + +/* Module functions: + * NOTE: while using a modular format SEChecker is built + * statically; this means that all modules and their functions + * are in the same namespace. */ + int roles_wo_users_register(sechk_lib_t * lib); + int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/spurious_audit.c b/sechecker/modules/spurious_audit.c new file mode 100644 index 0000000..21698df --- /dev/null +++ b/sechecker/modules/spurious_audit.c @@ -0,0 +1,778 @@ +/** + * @file + * Implementation of the spurious audit rule module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Ryan Jordan rjordan@tresys.com + * + * Copyright (C) 2005-2007 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 "spurious_audit.h" +#include <apol/policy-query.h> + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "spurious_audit"; + +/* The register function registers all of a module's functions + * with the library. */ +int spurious_audit_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "no library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s%s%s", "module unknown, \"", mod_name, "\""); + errno = ENOENT; + return -1; + } + + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "audit rules with no effect"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds audit rules in the policy which do not affect the auditing of\n" + "the policy. This could happen in the following situations:\n" + "\n" + " 1) there is an allow rule with the same key and permissions for a dontaudit\n" + " rule\n" + " 2) there is an auditallow rule without an allow rule with the same key or\n" + " with permissions that do not appear in an allow rule with the same key.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(errno)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = spurious_audit_init; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(errno)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = spurious_audit_run; + apol_vector_append(mod->functions, (void *)fn_struct); + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(errno)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = spurious_audit_print; + apol_vector_append(mod->functions, (void *)fn_struct); + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "%s%s%s", "wrong module (", mod->name, ")"); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + int error, rule_found; + apol_avrule_query_t *query = 0; + apol_vector_t *allow_rules = NULL, *auditallow_rules = NULL; + apol_vector_t *dontaudit_rules = NULL, *perm_vector1 = NULL; + apol_vector_t *perm_vector2 = NULL, *perm_intersection = NULL; + apol_vector_t *tmp_v = NULL; + size_t i, j, k, l, tmp_counter; + const qpol_avrule_t *rule1, *rule2; + const qpol_type_t *source, *target; + const qpol_class_t *object; + qpol_iterator_t *perm_iter1, *perm_iter2; + qpol_policy_t *q = apol_policy_get_qpol(policy); + char *string1, *string2, *tmp; + const char *src_name, *tgt_name, *obj_name, *perms; + + error = rule_found = 0; + allow_rules = auditallow_rules = dontaudit_rules = perm_vector1 = perm_vector2 = perm_intersection = NULL; + rule1 = rule2 = 0; + source = target = NULL; + perm_iter1 = perm_iter2 = NULL; + string1 = string2 = tmp = NULL; + src_name = tgt_name = obj_name = perms = NULL; + + if (!mod || !policy) { + ERR(NULL, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "%s%s%s", "wrong module (", mod->name, ")"); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + res->item_type = SECHK_ITEM_AVRULE; + + query = apol_avrule_query_create(); + if (!query) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + apol_avrule_query_set_rules(policy, query, QPOL_RULE_AUDITALLOW); + if (apol_avrule_get_by_query(policy, query, &auditallow_rules)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + apol_avrule_query_set_rules(policy, query, QPOL_RULE_DONTAUDIT); + if (apol_avrule_get_by_query(policy, query, &dontaudit_rules)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* First error case: Allow && Don't Audit */ + for (i = 0; i < apol_vector_get_size(dontaudit_rules); i++) { + /* get first (DONT_AUDIT) rule */ + rule1 = (qpol_avrule_t *) apol_vector_get_element(dontaudit_rules, i); + if (!rule1) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* get source, target, object for Don't Audit rule */ + if (qpol_avrule_get_source_type(q, rule1, &source)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_avrule_get_target_type(q, rule1, &target)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_avrule_get_object_class(q, rule1, &object)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* extract name strings from source, target, object */ + if (qpol_type_get_name(q, source, &src_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_type_get_name(q, target, &tgt_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_class_get_name(q, object, &obj_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* configure Allow rule query to match above Don't Audit rule */ + apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW); + apol_avrule_query_set_source(policy, query, src_name, 1); + apol_avrule_query_set_target(policy, query, tgt_name, 1); + apol_avrule_query_append_class(policy, query, NULL); + apol_avrule_query_append_class(policy, query, obj_name); + + /* get vector of matching ALLOW rules */ + if (apol_avrule_get_by_query(policy, query, &allow_rules)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (apol_vector_get_size(allow_rules) != 0) { + /* Bad News: Allow && Don't Audit */ + for (j = 0; j < apol_vector_get_size(allow_rules); j++) { + /* get second (Allow) rule */ + rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j); + if (!rule2) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* get permission iterators for both rules, and make vectors from them */ + if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + perm_vector1 = apol_vector_create_from_iter(perm_iter1, free); + if (!perm_vector1) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + perm_vector2 = apol_vector_create_from_iter(perm_iter2, free); + if (!perm_vector2) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* create intersection of permissions */ + perm_intersection = apol_vector_create_from_intersection(perm_vector1, + perm_vector2, apol_str_strcmp, NULL); + if (!perm_intersection) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (apol_vector_get_size(perm_intersection) != 0) { + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + proof->elem = (void *)rule2; /* proof is the allow rule */ + proof->type = SECHK_ITEM_AVRULE; + /* text will show the permissions that conflict */ + tmp_counter = 0; + for (k = 0; k < apol_vector_get_size(perm_intersection); k++) { + apol_str_append(&(proof->text), &tmp_counter, + (char *)apol_vector_get_element(perm_intersection, k)); + if (k != (apol_vector_get_size(perm_intersection) - 1)) + apol_str_append(&(proof->text), &tmp_counter, ", "); + } + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + item->item = (void *)rule1; /* item is the dontaudit rule */ + } + if (!item->proof) { + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + apol_vector_append(item->proof, (void *)proof); + + } else { + /* these two rules don't overlap, no problem */ + } + /* clean up */ + rule2 = NULL; + apol_vector_destroy(&perm_vector1); + apol_vector_destroy(&perm_vector2); + apol_vector_destroy(&perm_intersection); + qpol_iterator_destroy(&perm_iter1); + qpol_iterator_destroy(&perm_iter2); + } + apol_vector_destroy(&allow_rules); + if (!res->items) { + res->items = apol_vector_create(sechk_item_free); + if (!res->items) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + if (item) + apol_vector_append(res->items, (void *)item); + + item = NULL; + } + apol_vector_destroy(&allow_rules); + } + apol_vector_destroy(&dontaudit_rules); + + /* Second error case: AuditAllow w/out Allow */ + for (i = 0; i < apol_vector_get_size(auditallow_rules); i++) { + /* get first (AuditAllow) rule */ + rule1 = (qpol_avrule_t *) apol_vector_get_element(auditallow_rules, i); + if (!rule1) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + /* get first rule's source, target, object class */ + if (qpol_avrule_get_source_type(q, rule1, &source)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_avrule_get_target_type(q, rule1, &target)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_avrule_get_object_class(q, rule1, &object)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + /* extract name strings from source, target, object */ + if (qpol_type_get_name(q, source, &src_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_type_get_name(q, target, &tgt_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (qpol_class_get_name(q, object, &obj_name)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* configure ALLOW rule query to match above rule */ + apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW); + apol_avrule_query_set_source(policy, query, src_name, 1); + apol_avrule_query_set_target(policy, query, tgt_name, 1); + apol_avrule_query_append_class(policy, query, obj_name); + + if (apol_avrule_get_by_query(policy, query, &allow_rules)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (!apol_vector_get_size(allow_rules)) { + /* No ALLOW rule for given AUDIT_ALLOW rule */ + + /* Make proof: missing allow rule */ + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + proof->elem = NULL; + proof->type = SECHK_ITEM_AVRULE; + + /* grab permisisons of auditallow rule, and make text */ + if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + perm_vector1 = apol_vector_create_from_iter(perm_iter1, free); + if (!perm_vector1) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + tmp_counter = 0; + for (j = 0; j < apol_vector_get_size(perm_vector1); j++) { + if (apol_str_append(&(proof->text), &tmp_counter, (char *)apol_vector_get_element(perm_vector1, j))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (j != (apol_vector_get_size(perm_vector1) - 1)) { + if (apol_str_append(&(proof->text), &tmp_counter, " ")) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + } + apol_vector_destroy(&perm_vector1); + qpol_iterator_destroy(&perm_iter1); + + /* Make item: inconsistent auditallow rule */ + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + item->item = (void *)rule1; + if (!item->proof) { + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + apol_vector_append(item->proof, (void *)proof); + + /* Add item to test result */ + if (!res->items) { + res->items = apol_vector_create(sechk_item_free); + if (!res->items) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + if (item) + apol_vector_append(res->items, (void *)item); + item = NULL; + apol_vector_destroy(&allow_rules); + continue; + } + + /* Here we have AuditAllow rule and Allow rule(s) with same key */ + /* Checking to make sure they have the same permissions */ + + /* Make vector of AuditAllow permissions */ + if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + perm_vector1 = apol_vector_create_from_iter(perm_iter1, free); + if (!perm_vector1) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + /* Get permissions vector for Allow rule(s) */ + for (j = 0; j < apol_vector_get_size(allow_rules); j++) { + /* get Allow rule */ + rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j); + if (!rule2) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + + if (!perm_vector2) { + perm_vector2 = apol_vector_create(free); + if (!perm_vector2) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + + /* concatenate permissions from this rule, check for errors, all in one go */ + if (apol_vector_cat(perm_vector2, (tmp_v = apol_vector_create_from_iter(perm_iter2, NULL)))) { + error = errno; + ERR(policy, "%s", strerror(error)); + apol_vector_destroy(&tmp_v); + goto spurious_audit_run_fail; + } + apol_vector_destroy(&tmp_v); + } + + /* Find intersection of permission, put into a vector */ + perm_intersection = apol_vector_create_from_intersection(perm_vector1, perm_vector2, apol_str_strcmp, NULL); + + if (apol_vector_get_size(perm_intersection) != apol_vector_get_size(perm_vector1)) { + /* Auditallow rule audits things that are not allowed */ + + /* item for result is the AuditAllow rule */ + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error));; + goto spurious_audit_run_fail; + } + } + item->item = (void *)rule1; + /* proof is the lack of Allow rule */ + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + proof->elem = NULL; + proof->type = SECHK_ITEM_AVRULE; + + /* the next series of if statements prints the following: + * missing: allow <src_name> <tgt_name> : <obj_name> { perms }; */ + tmp_counter = 0; + for (j = 0; j < apol_vector_get_size(perm_vector1); j++) { + string1 = (char *)apol_vector_get_element(perm_vector1, j); + if (apol_vector_get_index(perm_intersection, (void *)string1, apol_str_strcmp, NULL, &l) < 0) { + if (apol_str_append(&(proof->text), &tmp_counter, string1)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + if (apol_str_append(&(proof->text), &tmp_counter, " ")) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + string1 = NULL; + } + + if (!item->proof) { + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + apol_vector_append(item->proof, (void *)proof); + proof = NULL; + if (!res->items) { + res->items = apol_vector_create(sechk_item_free); + if (!res->items) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto spurious_audit_run_fail; + } + } + apol_vector_append(res->items, (void *)item); + item = NULL; + } + + /* clean up */ + apol_vector_destroy(&perm_vector1); + apol_vector_destroy(&perm_vector2); + apol_vector_destroy(&perm_intersection); + apol_vector_destroy(&allow_rules); + qpol_iterator_destroy(&perm_iter1); + qpol_iterator_destroy(&perm_iter2); + } + + apol_vector_destroy(&auditallow_rules); + apol_avrule_query_destroy(&query); + + mod->result = res; + + /* If module finds something that would be considered a fail + * on the policy return 1 here */ + if (apol_vector_get_size(res->items) > 0) + return 1; + + return 0; + + spurious_audit_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + apol_vector_destroy(&allow_rules); + apol_vector_destroy(&auditallow_rules); + apol_vector_destroy(&dontaudit_rules); + apol_vector_destroy(&perm_vector1); + apol_vector_destroy(&perm_vector2); + apol_vector_destroy(&perm_intersection); + qpol_iterator_destroy(&perm_iter1); + qpol_iterator_destroy(&perm_iter2); + apol_avrule_query_destroy(&query); + free(tmp); + tmp = NULL; + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the + * results to stdout. */ +int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0; + uint32_t ruletype; + qpol_policy_t *q = apol_policy_get_qpol(policy); + char *tmp; + + if (!mod || !policy) { + ERR(NULL, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "%s%s%s", "wrong module (", mod->name, ")"); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + + if (!mod->result) { + ERR(policy, "%s%s%s", "module ", mod->name, "has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + i = apol_vector_get_size(mod->result->items); + printf("Found %zd rule%s.\n", i, (i == 1) ? "" : "s"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < apol_vector_get_size(mod->result->items); i++) { + item = apol_vector_get_element(mod->result->items, i); + printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item))); + free(tmp); + } + printf("\n"); + } + /* The proof report component is a display of a list of items + * with an indented list of proof statements supporting the result + * of the check for that item. */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (i = 0; i < apol_vector_get_size(mod->result->items); i++) { + item = apol_vector_get_element(mod->result->items, i); + printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item))); + + qpol_avrule_get_rule_type(q, (qpol_avrule_t *) item->item, &ruletype); + if (ruletype == QPOL_RULE_DONTAUDIT) { + for (j = 0; j < apol_vector_get_size(item->proof); j++) { + proof = apol_vector_get_element(item->proof, j); + printf("\tinconsistent: "); + printf("%s\n", apol_avrule_render(policy, (qpol_avrule_t *) proof->elem)); + printf("\tinconsistent permissions:\n"); + printf("\t%s\n", proof->text); + } + } else if (ruletype == QPOL_RULE_AUDITALLOW) { + printf("\tmissing: "); + printf("%s\n", strstr(apol_avrule_render(policy, (qpol_avrule_t *) item->item), "allow")); + printf("\tmissing permissions:\n"); + for (j = 0; j < apol_vector_get_size(item->proof); j++) { + proof = apol_vector_get_element(item->proof, j); + printf("\t%s\n", proof->text); + } + } + printf("\n"); + } + printf("\n"); + } + + return 0; +} diff --git a/sechecker/modules/spurious_audit.h b/sechecker/modules/spurious_audit.h new file mode 100644 index 0000000..19b93f6 --- /dev/null +++ b/sechecker/modules/spurious_audit.h @@ -0,0 +1,53 @@ +/** + * @file + * Defines the interface for the spurious audit rule module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Ryan Jordan rjordan@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef SPURIOUS_AUDIT +#define SPURIOUS_AUDIT + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> + +#define SECHK_SPUR_AU_AA_MISS 0x01 +#define SECHK_SPUR_AU_AA_PART 0x02 +#define SECHK_SPUR_AU_DA_FULL 0x04 +#define SECHK_SPUR_AU_DA_PART 0x08 + +/* Module functions: */ + int spurious_audit_register(sechk_lib_t * lib); + int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/template/profiles.readme b/sechecker/modules/template/profiles.readme new file mode 100644 index 0000000..f781ee0 --- /dev/null +++ b/sechecker/modules/template/profiles.readme @@ -0,0 +1,142 @@ +How to write a profile for SEChecker +===================================== + +Table of Contents +======================== +1. Use of Profiles +2. Format of the Profile + 2.0 <sechecker> + 2.1 <profile> + 2.2 <module> + 2.3 <output> + 2.4 <option> +3. Example Profile + +1. Use of Profiles +========================== +SEChecker has a wide variety of modules which perform various tests +on the policy and/or system. To make the management and running of +these modules easier, several profiles are defined. + +A profile is used to run a set of modules with options set in a way +that the resulting report reflects a specific security goal. + +To write your own profile, create a new XML file named <profile name>.prof. +The format of the file is detailed below. + +2. Format of the Profile +========================= +A profile is an XML file loaded by SEChecker to run a specific set of tests. +The profile recognizes the following tags + +2.0 <sechecker> +=========================== +The sechecker tag should be the first open tag in the file and the final +tag to be closed. The tag has a single attribute version, which should +be set to the current version of SEChecker you are using. To find your +version number, run: "sechecker --version". + +<sechecker version="1.0"> + +Be sure to remember to close this tag at the end of the file. + +2.1 <profile> +=========================== +The profile tag tells the parser that SEChecker should interpret this +file as a profile. This tag has no attributes. + +<profile> + +Close this tag just before the sechecker tag is closed at the end of the file + +2.2 <module> +=========================== +The module tag tells SEChecker that a particular module should be run for +this profile. The only attribute is name. + +<module name="mod_name"> + +This tag is closed after all other tags related to that module + +2.3 <output> +========================= +The output tag tells SEChecker to use this output format for the module +in which it appears. This tag is optional and has one attribute, value. + +<output value="short"/> + +This tag should close itself. The valid values are: + none - do not print anything in the report; only run this module + as dependency of another module. + quiet - print only the stats and header in the report + short - print the header, stats, and a list of items found by the + module without any accompanying proof + long - print the header, stats, and a list of items found by the + module with proof of the result following each item + verbose - print all possible output including the header, stats, + a list of items and a list of items with proof + +NOTE: any of the above values other than "none" are overridden by the + command line output flags. Setting an output value in a profile + overrides the default setting in the configuration file for this + profile only. + +2.4 <option> +======================= +The option tag allows a profile to specify additional options for a module. +The option tag has two mandatory attributes, "name" and "value". +The values of these attributes is specific to the module for which the +option is specified. Options specified in a profile are used in addition +to those in the configuration file. + +<option name="option_name" value="some_value"/> + +This tag closes itself. As its name implies this tag is optional. + +3. Example Profile +====================== +The following is a brief example of a profile + +<sechecker version="1.0"> +<profile> + + <module name="mod1"> + </module> + + <module name="mod2"> + <output value="none"/> + <option name="attribute" value="my_attrib"/> + </module> + + <module name="mod3"> + <option name="foo" value="bar"/> + </module> + + <module name="mod4"> + <output value="short"/> + </module> + + <module name="mod5"> + <output value="quiet"/> + <option name="type" value="shadow_t"/> + </module> + +</profile> +</sechecker> + +The result of this profile would be: +- run mod1 with default configuration; + print with default settings +- run mod2 with the additional attribute my_attrib, + but don't print its results +- run mod3 with option foo set to bar (in addition to any other settings); + print with default settings +- run mod4; + print in short output +- run mod5 with additional type shadow_t; + print using quiet output + +If there are also modules mod6 and mod7, neither would be run unless +one of the other modules (mod1-5) had a dependency on them. + + diff --git a/sechecker/modules/template/template.howto b/sechecker/modules/template/template.howto new file mode 100644 index 0000000..09151e0 --- /dev/null +++ b/sechecker/modules/template/template.howto @@ -0,0 +1,13 @@ +Instructions for using the template to add new modules +======================================================== +1. copy the xx.c and xx.h files to the modules directory +2. rename the files and replace the text xx with the + module name in both files +3. add the register function for your module xx_register + to the register_list.h and register_list.c entries +4. add options and any requirements or dependencies to + the decription in the register function +5. fill out TODO sections of the template with logic for + your module +6. recompile + diff --git a/sechecker/modules/template/xx.c b/sechecker/modules/template/xx.c new file mode 100644 index 0000000..20f7f5f --- /dev/null +++ b/sechecker/modules/template/xx.c @@ -0,0 +1,393 @@ +/** + * @file + * Implementation of the xx module. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +/* NOTE: TODO This is a module template, which includes all the necessary + * infrastructure to implement a basic SEChecker module. To use this template + * first replace all instances of the string xx with the name of the module, + * then edit or complete all sections marked TODO as instructed. */ + +#include <config.h> + +#include "sechecker.h" +#include <apol/policy.h> +#include "xx.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem of the file + * name; it should also match the prefix of all functions defined in this + * module and the private data storage structure */ +static const char *const mod_name = "xx"; + +/* The register function registers all of a module's functions + * with the library. TODO: Edit the description fields to include all + * options, requirements, and dependencies. Also provide a brief summary + * of the steps performed in this module's checks. If you are adding + * additional functions you need other modules to call, see the note at + * the bottom of this function to do so. */ +int xx_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + sechk_name_value_t *nv = NULL; + + if (!lib) { + ERR(NULL, "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the register list file and their name and options + * are stored in the module vector of the library. The name is looked up to + * determine where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(lib->policy, "Module unknown \"%s\"", mod_name); + errno = ENOENT; + return -1; + } + + mod->parent_lib = lib; + + /* TODO: assign the descriptions */ + mod->brief_description = ""; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "TODO: detailed description for this module.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = "TODO: set proper severity"; + + /* TODO: assign default options (remove if none) + * fill name and value and repeat as needed */ + nv = sechk_name_value_new("", ""); + apol_vector_append(mod->options, (void *)nv); + + /* TODO: assign requirements (remove if none) + * fill name and value and repeat as needed */ + nv = sechk_name_value_new("", ""); + apol_vector_append(mod->requirements, (void *)nv); + + /* TODO: assign dependencies (remove if not needed) + * fill name and value and repeat as needed */ + nv = sechk_name_value_new("", ""); + apol_vector_append(mod->dependencies, (void *)nv); + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = xx_init; + apol_vector_append(mod->functions, (void *)fn_struct); + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = xx_run; + apol_vector_append(mod->functions, (void *)fn_struct); + + /* TODO: if the module does not have a private data structure + * set this function pointer to NULL */ + mod->data_free = xx_data_free; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(lib->policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = xx_print; + apol_vector_append(mod->functions, (void *)fn_struct); + + /* TODO: (optional) add any other functions needed here, + * add a block as above for each additional function */ + + return 0; +} + +/* The init function creates the module's private data storage object and + * initializes its values. Add any option processing logic as indicated below. + * TODO: add options processing logic */ +int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_name_value_t *opt = NULL; + xx_data_t *datum = NULL; + int error = 0; + size_t i = 0; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)\n", mod->name); + errno = EINVAL; + return -1; + } + + /* If the module doesnot have a privte data sturcture replace the following + * block with "mod->data = NULL" */ + datum = xx_data_new(); + if (!datum) { + error = errno; + ERR(policy, "Error: %s\n", strerror(error)); + errno = error; + return -1; + } + mod->data = datum; + + for (i = 0; i < apol_vector_get_size(mod->options); i++) { + opt = apol_vector_get_element(mod->options, i); + /* TODO: check options + * check strings opt->name and opt->value of each option + * to set the members of the private data storage object + * (pointed to by datum). + * i.e. if (!strcmp(...)) {} else if (!strcmp((...)) etc. + * There should be relatively few options for any one module. + * If too many options are needed consider splitting the check + * into multiple modules and using dependencies. It is desirable + * for all checks to be a simple and granular as is possible */ + } + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found + * TODO: add check logic */ +int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + xx_data_t *datum; + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + int error = 0; + + /* TODO: define any aditional variables needed */ + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + datum = (xx_data_t *) mod->data; + res = sechk_result_new(); + if (!res) { + error = errno; + ERR(policy, "%s", strerror(error)); + errno = error; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto xx_run_fail; + } + /* TODO: set res->item_type to indicate which array the item_id indexes + * use values from the sechk_item_type_e enum (see sechecker.h) */ + + /* TODO: check logic here + * Perform check here. Create and initialize items and proof as found, + * appending to the appropriate vectors. + * For examples of the type of code to use here see other modules. */ + + mod->result = res; + + /* If module finds something that would be considered a failure + * of the policy return 1 here */ + if (apol_vector_get_size(res->items) > 0) + return 1; + + return 0; + + xx_run_fail: + /* TODO: free any other memory allocated during check logic */ + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The free function frees the private data of a module + * TODO: be sure to free any allocated space in the private data */ +void xx_data_free(void *data) +{ + xx_data_t *datum = (xx_data_t *) data; + + if (datum) { + /* TODO: free any allocated members of the module's + * private data structure */ + } + + free(data); +} + +/* The print function generates the text and prints the results to stdout. The + * outline below prints the standard format of a report section. Some modules + * may not have results in a format that can be represented by this outline and + * will need a different specification. It is required that each of the flags + * for output components be tested in this function (stats, list, proof, + * detailed, and brief) TODO: fill in the indicated information in the report + * fields as indicated below. Some alteration may be necessary for checks that + * perform different analyses */ +int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + xx_data_t *datum = NULL; + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = (xx_data_t *) mod->data; + outformat = mod->outputformat; + + if (!mod->result) { + ERR(policy, "Module %s has not been run", mod->name); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + /* TODO: display the statistics of the results + * typical text is "Found %i <itemtype>.\n" + * additional information may be printed here depending upon + * the amount of data gathered in the check */ + if (outformat & SECHK_OUT_STATS) { + /* TODO: "Found %i <itemtype>.\n": enter itemtype */ + printf("Found %zd .\n", apol_vector_get_size(mod->result->items)); + /* TODO: any additional generated statistics */ + } + /* The list report component is a display of all items found without any + * supporting proof. The default method is to display a comma separated list + * four items to a line this may need to be changed for longer items. + * TODO: you will need to enter the string representation of + * each item as the second parameter in the printf statement + * in place of the empty string. + * NOTE: if the item is a type of rule print only one per line. */ + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < apol_vector_get_size(mod->result->items); i++) { + item = apol_vector_get_element(mod->result->items, i); + i++; + /* TODO: (optional) change the number below to + * print more or less than 4 items per line */ + i %= 4; + /* TODO: second parameter: item name */ + printf("%s%s", "", (i ? ", " : "\n")); + } + printf("\n"); + } + /* The proof report component is a display of a list of items with an + * indented list of proof statements supporting the result of the check for + * that item (e.g. rules with a given type). Each proof element is then + * displayed in an indented list one per line below it. + * TODO: the name of the item should be entered below. + * NOTE: certain checks may need to further modify this report component if + * the results cannot be presented in this format */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (i = 0; i < apol_vector_get_size(mod->result->items); i++) { + item = apol_vector_get_element(mod->result->items, i); + printf("%s", ""); /* TODO: item name */ + printf(" - severity: %s\n", sechk_item_sev(item)); + for (j = 0; j < apol_vector_get_size(item->proof); j++) { + proof = apol_vector_get_element(item->proof, j); + printf("\t%s\n", proof->text); + } + } + printf("\n"); + } + + return 0; +} + +/* The xx_data_new function allocates and returns an initialized private data + * storage structure for this module. + * TODO: initialize any non-zero/non-null data (if needed) below */ +xx_data_t *xx_data_new(void) +{ + xx_data_t *datum = NULL; + + datum = (xx_data_t *) calloc(1, sizeof(xx_data_t)); + + /* TODO: initialize data */ + + return datum; +} diff --git a/sechecker/modules/template/xx.h b/sechecker/modules/template/xx.h new file mode 100644 index 0000000..d8c18b8 --- /dev/null +++ b/sechecker/modules/template/xx.h @@ -0,0 +1,72 @@ +/** + * @file + * Defines the interface for the xx module. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +/* NOTE: TODO This is a module template, which includes all the necessary + * infrastructure to implement a basic SEChecker module. To use this template + * first replace all instances of the string xx with the name of the module, + * then edit or complete all sections marked TODO as instructed. Do not forget + * to add an entry in the register_list files (see these files for further + * instruction) */ + +#include "sechecker.h" +#include <apol/policy.h> + +/* The xx_data structure is used to hold the check specific + * private data of a module. + * TODO: Add any members you need to perform the check or if the module is not + * going to need private data remove this declaration and the data_new() and + * data_free() functions */ +typedef struct xx_data +{ + /* TODO: define members of this data structure + * for module's private data */ +} xx_data_t; + +/* The following functions are used to allocate and initialize the private data + * storage structure for this module and to free all memory used by it. */ +xx_data_t *xx_data_new(void); +void xx_data_free(void *data); + +/* The register function places the needed information about the module in the + * library, including description fields and the functions available. TODO: be + * sure to add an entry for this function in the register_list files. */ +int xx_register(sechk_lib_t * lib); + +/* Module functions: + * The following three functions (init, run, and print) must exist for all + * modules. NOTE: while using a modular format SEChecker is built statically; + * this means that all modules and their functions are in the same namespace. + * Be sure to choose a unique name for each module and to set the module name + * prefix xx everywhere */ +int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); +int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); +int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +/* TODO: (optional) Declare any other functions needed by other modules here. + * The prototype of the function must be int xx_fn(sechk_module_t *mod, + * apol_policy_t *policy, void *arg). For use by the get_module_function() + * function, be sure to add a block in the xx_register function to register + * your function. + * NOTE: While SEChecker is build statically, it is intended that no module + * directly call a function from another but instead use get_module_function() + * to get the desired function from the library. */ diff --git a/sechecker/modules/types_wo_allow.c b/sechecker/modules/types_wo_allow.c new file mode 100644 index 0000000..2d0112a --- /dev/null +++ b/sechecker/modules/types_wo_allow.c @@ -0,0 +1,442 @@ +/** + * @file + * Implementation of the types without allow rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "types_wo_allow.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "types_wo_allow"; + +/* The register function registers all of a module's functions + * with the library. */ +int types_wo_allow_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "types with no allow rules"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds types defined in the policy that are not used in any allow\n" + "rules. A type that is never granted an allow rule in the policy is a dead type.\n" + "This means that all attempted access to the type will be denied including\n" + "attempts to relabel to a (usable) type. The type may need to be removed from\n" + "the policy or some intended access should be granted to the type.\n"; + mod->opt_description = + "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = types_wo_allow_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = types_wo_allow_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = types_wo_allow_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup("get_list"); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = types_wo_allow_get_list; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. */ +int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + bool used = false; + apol_vector_t *type_vector; + apol_vector_t *avrule_vector; + apol_avrule_query_t *avrule_query = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + + if (!(avrule_query = apol_avrule_query_create())) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + + if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) { + error = errno; + goto types_wo_allow_run_fail; + } + + for (i = 0; i < apol_vector_get_size(type_vector); i++) { + const qpol_type_t *type; + const char *type_name; + size_t j; + + used = false; + type = apol_vector_get_element(type_vector, i); + qpol_type_get_name(q, type, &type_name); + + /* Check source for allow type */ + apol_avrule_query_set_source(policy, avrule_query, type_name, 1); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + uint32_t rule_type; + qpol_avrule_t *rule; + + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_rule_type(q, rule, &rule_type); + if (rule_type == QPOL_RULE_ALLOW) + used = true; + } + apol_vector_destroy(&avrule_vector); + if (used) + continue; + + /* Check target for allow type */ + apol_avrule_query_set_source(policy, avrule_query, NULL, 0); + apol_avrule_query_set_target(policy, avrule_query, type_name, 1); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + uint32_t rule_type; + qpol_avrule_t *rule; + + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_rule_type(q, rule, &rule_type); + if (rule_type == QPOL_RULE_ALLOW) + used = true; + } + apol_vector_destroy(&avrule_vector); + apol_avrule_query_set_target(policy, avrule_query, NULL, 0); + if (used) + continue; + + /* not used anywhere */ + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + item->test_result = 1; + item->item = (void *)type; + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + proof->type = SECHK_ITEM_TYPE; + proof->text = strdup("This type does not appear in any allow rules."); + if (!proof->text) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto types_wo_allow_run_fail; + } + } + apol_vector_destroy(&type_vector); + apol_vector_destroy(&avrule_vector); + apol_avrule_query_destroy(&avrule_query); + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + types_wo_allow_run_fail: + apol_vector_destroy(&type_vector); + apol_vector_destroy(&avrule_vector); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text printed in the + * report and prints it to stdout. */ +int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + /* display the statistics of the results */ + if (outformat & SECHK_OUT_STATS) { + printf("Found %i types.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following types do not appear in any allow rules.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + type = NULL; + type_name = NULL; + + return 0; +} + +int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg) +{ + apol_vector_t **v = arg; + + if (!mod || !arg) { + ERR(NULL, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(NULL, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + if (!mod->result) { + ERR(NULL, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + v = &mod->result->items; + return 0; +} diff --git a/sechecker/modules/types_wo_allow.h b/sechecker/modules/types_wo_allow.h new file mode 100644 index 0000000..325c786 --- /dev/null +++ b/sechecker/modules/types_wo_allow.h @@ -0,0 +1,49 @@ +/** + * @file + * Defines the interface for the types without allow rules module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef TYPES_WO_ALLOW +#define TYPES_WO_ALLOW + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/avrule-query.h> +#include <apol/type-query.h> + + int types_wo_allow_register(sechk_lib_t * lib); + int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sechecker/modules/unreachable_doms.c b/sechecker/modules/unreachable_doms.c new file mode 100644 index 0000000..4653c2d --- /dev/null +++ b/sechecker/modules/unreachable_doms.c @@ -0,0 +1,1053 @@ +/** + * @file + * Implementation of the unreachable domains module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 <config.h> + +#include "unreachable_doms.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <assert.h> + +static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy); +static bool in_isid_ctx(const char *type_name, apol_policy_t * policy); +static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum); +/* for some reason we have to define this here to remove compile warnings */ +extern ssize_t getline(char **lineptr, size_t * n, FILE * stream); + +/* This string is the name f the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "unreachable_doms"; + +int unreachable_doms_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "unreachable domains"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all domains in a policy which are unreachable. A domain is\n" + "unreachable if any of the following apply:\n" + " 1) There is insufficient type enforcement policy to allow a transition,\n" + " 2) There is insufficient RBAC policy to allow a transition,\n" + " 3) There are no users with proper roles to allow a transition.\n" + "However, if any of the above rules indicate an unreachable domain, yet the\n" + "domain appears in the system default contexts file, it is considered reachable.\n"; + mod->opt_description = " Module requirements:\n" " attribute names\n" +#ifdef LIBSELINUX + " default_contexts file\n" +#endif + " Module dependencies:\n" " find_domains module\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + + /* assign requirements */ + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } +#ifdef LIBSELINUX + if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_DEFAULT_CONTEXTS, NULL)) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } +#endif + + /* assign dependencies */ + if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = unreachable_doms_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = unreachable_doms_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = unreachable_doms_data_free; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = unreachable_doms_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unreachable_doms_data_t *datum = NULL; + const char *ctx_file_path = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = unreachable_doms_data_new(); + if (!datum) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + mod->data = datum; + + /* Parse default contexts file */ + if (!(datum->ctx_vector = apol_vector_create(free))) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } +#ifdef LIBSELINUX + ctx_file_path = selinux_default_context_path(); + if (!ctx_file_path) { + ERR(policy, "%s", "Unable to find default contexts file"); + errno = ENOENT; + return -1; + } else { + bool retv = parse_default_contexts(ctx_file_path, datum->ctx_vector, policy); + if (!retv) { + ERR(policy, "%s", "Unable to parse default contexts file"); + errno = EIO; + return -1; + } + } +#endif + + return 0; +} + +typedef enum dom_need +{ + KEEP_SEARCHING = 0, /* keep checking way to reach not found yet */ + USER, /* missing a user for role(s) associated with the type */ + COMMON_USER, /* missing user for the role in a transition to that type */ + ROLE_TRANS, /* transition is valid but need a role transition as well */ + ROLE_ALLOW, /* transition is valid and has a role_transition but not role allow */ + RBAC, /* there is a transition but insufficient RBAC rules to permit or to determie a user */ + VALID_TRANS, /* only transitions to the type are invalid ones needs one or more rules to complete */ + ROLE, /* type has no associated role */ + TRANSITION, /* no transition exists */ + DONE /* done searching a valid way to reach the type has been found */ +} dom_need_e; + +/** + * Finds user witn at least one role from each vector. + * @param policy The policy. + * @param src_roles The first set of roles. + * @param tgt_roles The second set of roles. + * @return 1 if a common user can be found 0 other wise. + */ +static int exists_common_user(apol_policy_t * policy, apol_vector_t * src_roles, apol_vector_t * tgt_roles, + const qpol_role_t ** which_sr, const qpol_role_t ** which_tr, const qpol_user_t ** which_u) +{ + int retv = 0; + apol_user_query_t *uq; + const char *name = NULL; + const qpol_role_t *role = NULL; + const qpol_user_t *user = NULL; + qpol_iterator_t *iter = NULL; + apol_vector_t *user_v = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + size_t i, j, k; + + if (!policy || !src_roles || !tgt_roles) + return 0; + + if (which_sr) + *which_sr = NULL; + if (which_tr) + *which_tr = NULL; + if (which_u) + *which_u = NULL; + + if (!(uq = apol_user_query_create())) + return 0; + + for (i = 0; i < apol_vector_get_size(src_roles); i++) { + role = apol_vector_get_element(src_roles, i); + if (which_sr) + *which_sr = role; + qpol_role_get_name(q, role, &name); + apol_user_query_set_role(policy, uq, name); + apol_user_get_by_query(policy, uq, &user_v); + for (j = 0; j < apol_vector_get_size(user_v); j++) { + user = apol_vector_get_element(user_v, j); + qpol_user_get_role_iter(q, user, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)&role); + if (!apol_vector_get_index(tgt_roles, role, NULL, NULL, &k)) { + retv = 1; + if (which_tr) + *which_tr = role; + if (which_u) + *which_u = user; + goto exists_done; + } + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&user_v); + } + + exists_done: + qpol_iterator_destroy(&iter); + apol_vector_destroy(&user_v); + apol_user_query_destroy(&uq); + return retv; +} + +/* The run function performs the check. This function runs only once even if + * called multiple times. This function allocates the result structure and + * fills in all relevant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unreachable_doms_data_t *datum; + sechk_name_value_t *dep = NULL; + sechk_result_t *res = NULL, *find_domains_res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i, j, k, l; + sechk_mod_fn_t run_fn = NULL; + int error = 0, trans_missing = 0; + apol_vector_t *dom_vector = NULL, *dom_results = NULL, *dom_roles = NULL; + apol_vector_t *valid_rev_trans = NULL, *invalid_rev_trans = NULL; + apol_vector_t *start_roles = NULL, *intersect_roles = NULL; + apol_vector_t *tmp_users = NULL, *role_users = NULL; + apol_vector_t *role_trans_vector = NULL, *role_allow_vector = NULL; + apol_domain_trans_analysis_t *dta = NULL; + apol_domain_trans_result_t *dtr = NULL; + const char *tmp_name = NULL, *cur_dom_name = NULL; + const char *tmp2 = NULL, *tmp3 = NULL; + const qpol_type_t *cur_dom = NULL, *ep_type = NULL, *start_type = NULL; + const qpol_type_t *last_type = NULL; + const qpol_role_t *last_role = NULL, *src_role = NULL, *dflt_role = NULL; + const qpol_role_t *last_dflt = NULL; + const qpol_user_t *last_user = NULL; + dom_need_e need = KEEP_SEARCHING; + apol_role_query_t *role_q = NULL; + apol_user_query_t *user_q = NULL; + apol_role_trans_query_t *rtq = NULL; + apol_role_allow_query_t *raq = NULL; + const qpol_role_trans_t *role_trans = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + datum = (unreachable_doms_data_t *) mod->data; + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto unreachable_doms_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto unreachable_doms_run_fail; + } + + /* run dependencies and get results */ + for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) { + dep = apol_vector_get_element(mod->dependencies, i); + run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib); + run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL); + } + + find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib); + dom_results = find_domains_res->items; + if (!(dom_vector = apol_vector_create(NULL))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + for (i = 0; i < apol_vector_get_size(dom_results); i++) { + item = apol_vector_get_element(dom_results, i); + if (apol_vector_append(dom_vector, (void *)(item->item))) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + } + item = NULL; + dom_results = NULL; /* no need to destroy, belongs to another module. */ + + /* initialize query objects */ + dta = apol_domain_trans_analysis_create(); + if (!dta) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + apol_domain_trans_analysis_set_direction(policy, dta, APOL_DOMAIN_TRANS_DIRECTION_REVERSE); + + role_q = apol_role_query_create(); + if (!role_q) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + + user_q = apol_user_query_create(); + if (!user_q) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + + rtq = apol_role_trans_query_create(); + if (!rtq) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + + raq = apol_role_allow_query_create(); + if (!raq) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + + /* dom_vector now contains all types considered domains */ + for (i = 0; i < apol_vector_get_size(dom_vector); i++) { + cur_dom = apol_vector_get_element(dom_vector, i); + qpol_type_get_name(q, cur_dom, &cur_dom_name); + need = KEEP_SEARCHING; + + if ( +#ifdef LIBSELINUX + in_def_ctx(cur_dom_name, datum) || +#endif + in_isid_ctx(cur_dom_name, policy)) + continue; + + /* collect information about roles and transitions to this domain */ + apol_role_query_set_type(policy, role_q, cur_dom_name); + apol_role_get_by_query(policy, role_q, &dom_roles); + apol_policy_reset_domain_trans_table(policy); + apol_domain_trans_analysis_set_start_type(policy, dta, cur_dom_name); + apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_VALID); + apol_domain_trans_analysis_do(policy, dta, &valid_rev_trans); + apol_policy_reset_domain_trans_table(policy); + apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_INVALID); + apol_domain_trans_analysis_do(policy, dta, &invalid_rev_trans); + + /* for valid transitions - validate RBAC, and then users */ + for (j = 0; j < apol_vector_get_size(valid_rev_trans); j++) { + dtr = apol_vector_get_element(valid_rev_trans, j); + start_type = apol_domain_trans_result_get_start_type(dtr); + ep_type = apol_domain_trans_result_get_entrypoint_type(dtr); + qpol_type_get_name(q, start_type, &tmp_name); + apol_role_query_set_type(policy, role_q, tmp_name); + apol_role_get_by_query(policy, role_q, &start_roles); + intersect_roles = apol_vector_create_from_intersection(dom_roles, start_roles, NULL, NULL); + if (apol_vector_get_size(intersect_roles) > 0) { + /* find user with role in intersect */ + role_users = apol_vector_create(NULL); + for (k = 0; k < apol_vector_get_size(intersect_roles); k++) { + last_role = apol_vector_get_element(intersect_roles, k); + qpol_role_get_name(q, last_role, &tmp_name); + apol_user_query_set_role(policy, user_q, tmp_name); + apol_user_get_by_query(policy, user_q, &tmp_users); + if (apol_vector_cat(role_users, tmp_users)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + apol_vector_destroy(&tmp_users); + } + if (apol_vector_get_size(role_users) > 0) + need = DONE; + else + need = USER; + apol_vector_destroy(&role_users); + } + if (need == DONE) + break; + /* look for role_transitions */ + qpol_type_get_name(q, ep_type, &tmp_name); + apol_role_trans_query_set_target(policy, rtq, tmp_name, 1); + apol_role_trans_get_by_query(policy, rtq, &role_trans_vector); + for (k = 0; need != DONE && k < apol_vector_get_size(role_trans_vector); k++) { + role_trans = apol_vector_get_element(role_trans_vector, k); + qpol_role_trans_get_source_role(q, role_trans, &src_role); + qpol_role_trans_get_default_role(q, role_trans, &dflt_role); + if (apol_vector_get_index(start_roles, src_role, NULL, NULL, &l) + || apol_vector_get_index(dom_roles, dflt_role, NULL, NULL, &l)) + continue; /* start domain must have the source role and cur_dom must have default role or transition does not apply */ + if (exists_common_user(policy, start_roles, dom_roles, NULL, NULL, NULL)) { + qpol_role_get_name(q, src_role, &tmp_name); + apol_role_allow_query_set_source(policy, raq, tmp_name); + qpol_role_get_name(q, dflt_role, &tmp_name); + apol_role_allow_query_set_target(policy, raq, tmp_name); + apol_role_allow_get_by_query(policy, raq, &role_allow_vector); + if (apol_vector_get_size(role_allow_vector) > 0) { + need = DONE; + } else { + need = ROLE_ALLOW; + last_role = src_role; + last_dflt = dflt_role; + } + apol_vector_destroy(&role_allow_vector); + } else { + need = COMMON_USER; + last_role = src_role; + last_dflt = dflt_role; + } + } + /* no roles usable in intersection and no transitions so pick first set with common user */ + if (apol_vector_get_size(role_trans_vector) == 0) { + if (exists_common_user(policy, start_roles, dom_roles, &src_role, &dflt_role, &last_user)) { + need = ROLE_TRANS; + last_role = src_role; + last_dflt = dflt_role; + last_type = ep_type; + } else { + need = RBAC; + } + } + apol_vector_destroy(&role_trans_vector); + if (need == DONE) + break; + } + /* if no valid transition found - check what is needed to complete invalid ones */ + if (need == KEEP_SEARCHING) { + for (j = 0; j < apol_vector_get_size(invalid_rev_trans); j++) { + dtr = apol_vector_get_element(invalid_rev_trans, j); + start_type = apol_domain_trans_result_get_start_type(dtr); + ep_type = apol_domain_trans_result_get_entrypoint_type(dtr); + trans_missing = apol_domain_trans_table_verify_trans(policy, start_type, ep_type, cur_dom); + need = VALID_TRANS; + /* since incomplete transitions can be missing types break if we + * found one with all three types specified, else keep the last one */ + if (start_type && ep_type) + break; + } + } + /* if no transition exists (valid or otherwise) check that at least one role and user pair is valid */ + if (need == KEEP_SEARCHING) { + role_users = apol_vector_create(NULL); + for (j = 0; j < apol_vector_get_size(dom_roles); j++) { + last_role = apol_vector_get_element(dom_roles, j); + qpol_role_get_name(q, last_role, &tmp_name); + apol_user_query_set_role(policy, user_q, tmp_name); + apol_user_get_by_query(policy, user_q, &tmp_users); + apol_vector_cat(role_users, tmp_users); + apol_vector_destroy(&tmp_users); + } + if (apol_vector_get_size(dom_roles) == 0) { + need = ROLE; + } else if (apol_vector_get_size(role_users) == 0) { + need = USER; + } else { + need = TRANSITION; + } + apol_vector_destroy(&role_users); + } + /* if something needs to be reported do so now */ + if (need != DONE) { + assert(need != KEEP_SEARCHING); + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + item->item = (void *)cur_dom; + item->test_result = (unsigned char)need; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + switch (need) { + case USER: + { + qpol_role_get_name(q, last_role, &tmp_name); + if (asprintf(&proof->text, "No user associated with role %s for %s", tmp_name, cur_dom_name) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case COMMON_USER: + { + qpol_role_get_name(q, last_role, &tmp_name); + qpol_role_get_name(q, last_dflt, &tmp2); + if (asprintf + (&proof->text, "Role transition required but no user associated with role %s and %s", + tmp_name, tmp2) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case ROLE_TRANS: + { + qpol_role_get_name(q, last_role, &tmp_name); + qpol_role_get_name(q, last_dflt, &tmp2); + qpol_type_get_name(q, last_type, &tmp3); + if (asprintf(&proof->text, "Missing: role_transition %s %s %s;", tmp_name, tmp3, tmp2) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case ROLE_ALLOW: + { + qpol_role_get_name(q, last_role, &tmp_name); + qpol_role_get_name(q, last_dflt, &tmp2); + if (asprintf + (&proof->text, + "Role transition required but missing role allow rule.\n\tMissing: allow %s %s;", + tmp_name, tmp2) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case RBAC: + { + if (asprintf + (&proof->text, + "Valid domain transition to %s exists but indufficient RBAC rules to permit it.", + cur_dom_name) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case VALID_TRANS: + { + if (start_type) + qpol_type_get_name(q, start_type, &tmp2); + else + tmp2 = "<start_type>"; + if (ep_type) + qpol_type_get_name(q, ep_type, &tmp3); + else + tmp3 = "<entrypont>"; + if (asprintf + (&proof->text, + "Partial transition to %s found:\n\t%s: allow %s %s : process transition;\n\t%s: allow %s %s : file execute;\n\t%s: allow %s %s : file entrypoint;\n\t%s one of:\n\tallow %s self : process setexec;\n\ttype_transition %s %s : process %s;", + cur_dom_name, + ((trans_missing & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) ? "Missing" : "Has"), tmp2, + cur_dom_name, ((trans_missing & APOL_DOMAIN_TRANS_RULE_EXEC) ? "Missing" : "Has"), + tmp2, tmp3, ((trans_missing & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) ? "Missing" : "Has"), + cur_dom_name, tmp3, + ((trans_missing & (APOL_DOMAIN_TRANS_RULE_TYPE_TRANS | APOL_DOMAIN_TRANS_RULE_SETEXEC)) + ? "May need" : "Has"), cur_dom_name, tmp2, tmp3, cur_dom_name) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case ROLE: + { + if (asprintf(&proof->text, "No role associated with domain %s", cur_dom_name) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case TRANSITION: + { + if (asprintf(&proof->text, "There are no transitions to domain %s", cur_dom_name) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + break; + } + case DONE: + case KEEP_SEARCHING: + default: + { + assert(0); + error = EDOM; + goto unreachable_doms_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + proof = NULL; + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto unreachable_doms_run_fail; + } + item = NULL; + } + apol_vector_destroy(&dom_roles); + apol_vector_destroy(&valid_rev_trans); + apol_vector_destroy(&invalid_rev_trans); + } + + apol_vector_destroy(&dom_vector); + apol_domain_trans_analysis_destroy(&dta); + apol_role_query_destroy(&role_q); + apol_user_query_destroy(&user_q); + apol_role_trans_query_destroy(&rtq); + apol_role_allow_query_destroy(&raq); + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + unreachable_doms_run_fail: + apol_vector_destroy(&dom_vector); + apol_domain_trans_analysis_destroy(&dta); + apol_role_query_destroy(&role_q); + apol_user_query_destroy(&user_q); + apol_role_trans_query_destroy(&rtq); + apol_role_allow_query_destroy(&raq); + apol_vector_destroy(&dom_roles); + apol_vector_destroy(&valid_rev_trans); + apol_vector_destroy(&invalid_rev_trans); + apol_vector_destroy(&tmp_users); + apol_vector_destroy(&role_users); + apol_vector_destroy(&role_trans_vector); + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The free function frees the private data of a module */ +void unreachable_doms_data_free(void *data) +{ + unreachable_doms_data_t *d = data; + if (!data) + return; + + free(d->ctx_file_path); + apol_vector_destroy(&d->ctx_vector); + free(data); +} + +/* The print function generates the text and prints the results to stdout. */ +int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unreachable_doms_data_t *datum = NULL; + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k, l, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + datum = (unreachable_doms_data_t *) mod->data; + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd unreachable domains.\n", num_items); + } + + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + type = (qpol_type_t *) item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + if (outformat & SECHK_OUT_PROOF) { + if (apol_vector_get_size(datum->ctx_vector) > 0) { + printf("Found %zd domains in %s:\n", apol_vector_get_size(datum->ctx_vector), + selinux_default_context_path()); + for (j = 0; j < apol_vector_get_size(datum->ctx_vector); j++) { + type_name = apol_vector_get_element(datum->ctx_vector, j); + printf("\t%s\n", type_name); + } + } + + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + printf("\n"); + } + } + + return 0; +} + +/* The unreachable_doms_data_new function allocates and returns an initialized + * private data storage structure for this module. */ +unreachable_doms_data_t *unreachable_doms_data_new(void) +{ + unreachable_doms_data_t *datum = NULL; + + datum = (unreachable_doms_data_t *) calloc(1, sizeof(unreachable_doms_data_t)); + + return datum; +} + +/* Parses default_contexts and adds source domains to datum->ctx_list. + * The vector will contain newly allocated strings. */ +static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy) +{ + int str_sz, i, charno, error = 0, retv; + FILE *ctx_file; + char *line = NULL, *src_role = NULL, *src_dom = NULL, *dst_role = NULL, *dst_dom = NULL; + size_t line_len = 0; + bool uses_mls = false; + + printf("Using default contexts: %s\n", ctx_file_path); + ctx_file = fopen(ctx_file_path, "r"); + if (!ctx_file) { + error = errno; + ERR(policy, "Opening default contexts file %s", ctx_file_path); + goto parse_default_contexts_fail; + } + + while (!feof(ctx_file)) { + retv = getline(&line, &line_len, ctx_file); + if (retv == -1) { + if (feof(ctx_file)) { + break; + } else { + error = errno; + ERR(policy, "%s", "Reading default contexts file"); + goto parse_default_contexts_fail; + } + } + + uses_mls = false; + str_sz = APOL_STR_SZ + 128; + i = 0; + + /* source role */ + src_role = malloc(str_sz); + if (!src_role) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto parse_default_contexts_fail; + } + + memset(src_role, 0x0, str_sz); + charno = 0; + while (line[i] != ':') { + if (!isspace(line[i])) { + src_role[i] = line[i]; + charno++; + } + i++; + } + i++; /* skip ':' */ + + /* source type */ + src_dom = malloc(str_sz); + if (!src_dom) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto parse_default_contexts_fail; + } + memset(src_dom, 0x0, str_sz); + charno = 0; + while (1) { + if (isspace(line[i])) + break; + /* Check for MLS */ + if (line[i] == ':') { + uses_mls = true; + i++; /* skip ':' */ + while (!isspace(line[i])) + i++; + } + if (uses_mls) + break; + + src_dom[charno] = line[i]; + charno++; + i++; + } + + /* dest role */ + dst_role = malloc(str_sz); + if (!dst_role) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto parse_default_contexts_fail; + } + memset(dst_role, 0x0, str_sz); + charno = 0; + while (line[i] != ':') { + if (!isspace(line[i])) { + dst_role[charno] = line[i]; + charno++; + } + + i++; + } + i++; /* skip ':' */ + + /* dest type */ + dst_dom = malloc(str_sz); + if (!dst_dom) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto parse_default_contexts_fail; + } + memset(dst_dom, 0x0, str_sz); + charno = 0; + while (line[i]) { + if (uses_mls) + if (line[i] == ':') + break; + + if (!isspace(line[i])) + dst_dom[charno] = line[i]; + + charno++; + i++; + } + + if (apol_vector_append(ctx_vector, (void *)strdup(src_dom)) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto parse_default_contexts_fail; + } + free(line); + line = NULL; + free(src_role); + free(src_dom); + free(dst_role); + free(dst_dom); + } + free(line); + fclose(ctx_file); + return true; + parse_default_contexts_fail: + if (ctx_file != NULL) { + fclose(ctx_file); + } + free(line); + free(src_role); + free(src_dom); + free(dst_role); + free(dst_dom); + errno = error; + return false; +} + +/* Returns true if type_idx is in datum->ctx_list */ +static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum) +{ + size_t i; + if (apol_vector_get_index(datum->ctx_vector, type_name, apol_str_strcmp, NULL, &i) < 0) { + return false; + } + return true; +} + +/* Returns true if type is a type assigned to an isid */ +static bool in_isid_ctx(const char *type_name, apol_policy_t * policy) +{ + qpol_iterator_t *iter = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + qpol_policy_get_isid_iter(q, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + const qpol_isid_t *isid; + const qpol_context_t *ocon; + const qpol_type_t *context_type; + const char *context_type_name; + + qpol_iterator_get_item(iter, (void **)&isid); + qpol_isid_get_context(q, isid, &ocon); + qpol_context_get_type(q, ocon, &context_type); + qpol_type_get_name(q, context_type, &context_type_name); + if (!strcmp(type_name, context_type_name)) { + qpol_iterator_destroy(&iter); + return true; + } + } + qpol_iterator_destroy(&iter); + return false; +} diff --git a/sechecker/modules/unreachable_doms.h b/sechecker/modules/unreachable_doms.h new file mode 100644 index 0000000..660de76 --- /dev/null +++ b/sechecker/modules/unreachable_doms.h @@ -0,0 +1,73 @@ +/** + * @file + * Defines the interface for the unreachable domains module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef UNREACHABLE_DOMS +#define UNREACHABLE_DOMS + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/user-query.h> +#include <apol/role-query.h> +#include <apol/isid-query.h> +#include <apol/rbacrule-query.h> +#include <apol/domain-trans-analysis.h> +#include <selinux/selinux.h> + +#define SECHK_INC_DOM_TRANS_HAS_TT 0x08 +#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04 +#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02 +#define SECHK_INC_DOM_TRANS_HAS_EP 0x01 +#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC) + +#define APOL_STR_SZ 128 + +/* The unreachable_doms_data structure is used to hold the check specific + * private data of a module. */ + typedef struct unreachable_doms_data + { + char *ctx_file_path; + /* vector of strings, read from default contexts file */ + apol_vector_t *ctx_vector; + } unreachable_doms_data_t; + + unreachable_doms_data_t *unreachable_doms_data_new(void); + void unreachable_doms_data_free(void *data); + + int unreachable_doms_register(sechk_lib_t * lib); + int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* UNREACHABLE_DOMS */ diff --git a/sechecker/modules/users_wo_roles.c b/sechecker/modules/users_wo_roles.c new file mode 100644 index 0000000..a98d94d --- /dev/null +++ b/sechecker/modules/users_wo_roles.c @@ -0,0 +1,321 @@ +/** + * @file + * Implementation of the users without roles module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 "users_wo_roles.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* This string is the name of the module and should match the stem + * of the file name; it should also match the prefix of all functions + * defined in this module and the private data storage structure */ +static const char *const mod_name = "users_wo_roles"; + +/* The register function registers all of a module's functions + * with the library. */ +int users_wo_roles_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "users with no roles"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all the SELinux users in the policy that have no associated\n" + "roles. Users without roles may appear in the label of a file system object;\n" + "however, these users cannot login to the system or run any process. Since these\n" + "users cannot be used on the system, a policy change is recomended to remove the\n" + "users or provide some intended access.\n"; + mod->opt_description = + " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_LOW; + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = users_wo_roles_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = users_wo_roles_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = users_wo_roles_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. */ +int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. All test logic should be placed below + * as instructed. This function allocates the result structure and fills + * in all relavant item and proof data. */ +int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i; + apol_vector_t *user_vector; + int error = 0; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + res->item_type = SECHK_ITEM_USER; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + + apol_user_get_by_query(policy, NULL, &user_vector); + for (i = 0; i < apol_vector_get_size(user_vector); i++) { + qpol_user_t *user; + qpol_iterator_t *role_iter; + + user = apol_vector_get_element(user_vector, i); + qpol_user_get_role_iter(apol_policy_get_qpol(policy), user, &role_iter); + if (!qpol_iterator_end(role_iter)) { + qpol_iterator_destroy(&role_iter); + continue; + } + qpol_iterator_destroy(&role_iter); + + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + proof->type = SECHK_ITEM_USER; + proof->text = "User has no roles.\n"; + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + item->item = (void *)user; + if (!item->proof) { + if (!(item->proof = apol_vector_create(sechk_proof_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + } + if (apol_vector_append(item->proof, (void *)proof) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + if (apol_vector_append(res->items, (void *)item) < 0) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto users_wo_roles_run_fail; + } + } + apol_vector_destroy(&user_vector); + + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + users_wo_roles_run_fail: + sechk_proof_free(proof); + sechk_item_free(item); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print output function generates the text printed in the + * report and prints it to stdout. */ +int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + size_t i = 0, j = 0, num_items; + const qpol_user_t *user; + const char *user_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + /* display the statistics of the results */ + if (outformat & SECHK_OUT_STATS) { + printf("Found %zd users.\n", num_items); + } + if (outformat & SECHK_OUT_PROOF) { + printf("\nThe following users have no associated roles.\n"); + } + /* The list report component is a display of all items + * found without any supporting proof. */ + if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + j %= 4; + item = apol_vector_get_element(mod->result->items, i); + user = (qpol_user_t *) item->item; + qpol_user_get_name(apol_policy_get_qpol(policy), user, &user_name); + printf("%s%s", user_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + return 0; +} diff --git a/sechecker/modules/users_wo_roles.h b/sechecker/modules/users_wo_roles.h new file mode 100644 index 0000000..dd1ee42 --- /dev/null +++ b/sechecker/modules/users_wo_roles.h @@ -0,0 +1,47 @@ +/** + * @file + * Defines the interface for the users without roles module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2005-2007 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 + */ + +#ifndef USERS_WO_ROLES +#define USERS_WO_ROLES + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sechecker.h" +#include <apol/policy.h> +#include <apol/user-query.h> + + int users_wo_roles_register(sechk_lib_t * lib); + int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg); + int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif |