From 47be9ff57e72906660bb62a515222f482131e1fb Mon Sep 17 00:00:00 2001 From: Miroslav Grepl Date: Fri, 11 Apr 2014 09:37:53 +0200 Subject: Create setools-3.3.7 git repo --- sechecker/Makefile.am | 67 + sechecker/modules/attribs_wo_rules.c | 520 +++++++ sechecker/modules/attribs_wo_rules.h | 63 + sechecker/modules/attribs_wo_types.c | 399 +++++ sechecker/modules/attribs_wo_types.h | 48 + sechecker/modules/domain_and_file.c | 398 +++++ sechecker/modules/domain_and_file.h | 46 + sechecker/modules/domains_wo_roles.c | 386 +++++ sechecker/modules/domains_wo_roles.h | 47 + sechecker/modules/find_assoc_types.c | 407 ++++++ sechecker/modules/find_assoc_types.h | 51 + sechecker/modules/find_domains.c | 633 ++++++++ sechecker/modules/find_domains.h | 60 + sechecker/modules/find_file_types.c | 636 ++++++++ sechecker/modules/find_file_types.h | 60 + sechecker/modules/find_net_domains.c | 501 +++++++ sechecker/modules/find_net_domains.h | 59 + sechecker/modules/find_netif_types.c | 489 +++++++ sechecker/modules/find_netif_types.h | 53 + sechecker/modules/find_node_types.c | 479 ++++++ sechecker/modules/find_node_types.h | 53 + sechecker/modules/find_port_types.c | 513 +++++++ sechecker/modules/find_port_types.h | 50 + sechecker/modules/imp_range_trans.c | 513 +++++++ sechecker/modules/imp_range_trans.h | 52 + sechecker/modules/inc_dom_trans.c | 913 ++++++++++++ sechecker/modules/inc_dom_trans.h | 56 + sechecker/modules/inc_mount.c | 520 +++++++ sechecker/modules/inc_mount.h | 54 + sechecker/modules/inc_net_access.c | 1852 ++++++++++++++++++++++++ sechecker/modules/inc_net_access.h | 51 + sechecker/modules/roles_wo_allow.c | 387 +++++ sechecker/modules/roles_wo_allow.h | 49 + sechecker/modules/roles_wo_types.c | 330 +++++ sechecker/modules/roles_wo_types.h | 47 + sechecker/modules/roles_wo_users.c | 392 +++++ sechecker/modules/roles_wo_users.h | 53 + sechecker/modules/spurious_audit.c | 778 ++++++++++ sechecker/modules/spurious_audit.h | 53 + sechecker/modules/template/profiles.readme | 142 ++ sechecker/modules/template/template.howto | 13 + sechecker/modules/template/xx.c | 393 +++++ sechecker/modules/template/xx.h | 72 + sechecker/modules/types_wo_allow.c | 442 ++++++ sechecker/modules/types_wo_allow.h | 49 + sechecker/modules/unreachable_doms.c | 1053 ++++++++++++++ sechecker/modules/unreachable_doms.h | 73 + sechecker/modules/users_wo_roles.c | 321 ++++ sechecker/modules/users_wo_roles.h | 47 + sechecker/profiles/all-checks-no-mls.sechecker | 98 ++ sechecker/profiles/all-checks.sechecker | 102 ++ sechecker/profiles/analysis-checks.sechecker | 78 + sechecker/profiles/devel-checks.sechecker | 74 + sechecker/profiles/sechecker.dtd | 19 + sechecker/register_list.c | 102 ++ sechecker/register_list.h | 64 + sechecker/sechecker.c | 1230 ++++++++++++++++ sechecker/sechecker.h | 695 +++++++++ sechecker/sechecker_cli.c | 361 +++++ sechecker/sechecker_help.txt | 86 ++ sechecker/sechk_parse.c | 285 ++++ sechecker/sechk_parse.h | 44 + 62 files changed, 17961 insertions(+) create mode 100644 sechecker/Makefile.am create mode 100644 sechecker/modules/attribs_wo_rules.c create mode 100644 sechecker/modules/attribs_wo_rules.h create mode 100644 sechecker/modules/attribs_wo_types.c create mode 100644 sechecker/modules/attribs_wo_types.h create mode 100644 sechecker/modules/domain_and_file.c create mode 100644 sechecker/modules/domain_and_file.h create mode 100644 sechecker/modules/domains_wo_roles.c create mode 100644 sechecker/modules/domains_wo_roles.h create mode 100644 sechecker/modules/find_assoc_types.c create mode 100644 sechecker/modules/find_assoc_types.h create mode 100644 sechecker/modules/find_domains.c create mode 100644 sechecker/modules/find_domains.h create mode 100644 sechecker/modules/find_file_types.c create mode 100644 sechecker/modules/find_file_types.h create mode 100644 sechecker/modules/find_net_domains.c create mode 100644 sechecker/modules/find_net_domains.h create mode 100644 sechecker/modules/find_netif_types.c create mode 100644 sechecker/modules/find_netif_types.h create mode 100644 sechecker/modules/find_node_types.c create mode 100644 sechecker/modules/find_node_types.h create mode 100644 sechecker/modules/find_port_types.c create mode 100644 sechecker/modules/find_port_types.h create mode 100644 sechecker/modules/imp_range_trans.c create mode 100644 sechecker/modules/imp_range_trans.h create mode 100644 sechecker/modules/inc_dom_trans.c create mode 100644 sechecker/modules/inc_dom_trans.h create mode 100644 sechecker/modules/inc_mount.c create mode 100644 sechecker/modules/inc_mount.h create mode 100644 sechecker/modules/inc_net_access.c create mode 100644 sechecker/modules/inc_net_access.h create mode 100644 sechecker/modules/roles_wo_allow.c create mode 100644 sechecker/modules/roles_wo_allow.h create mode 100644 sechecker/modules/roles_wo_types.c create mode 100644 sechecker/modules/roles_wo_types.h create mode 100644 sechecker/modules/roles_wo_users.c create mode 100644 sechecker/modules/roles_wo_users.h create mode 100644 sechecker/modules/spurious_audit.c create mode 100644 sechecker/modules/spurious_audit.h create mode 100644 sechecker/modules/template/profiles.readme create mode 100644 sechecker/modules/template/template.howto create mode 100644 sechecker/modules/template/xx.c create mode 100644 sechecker/modules/template/xx.h create mode 100644 sechecker/modules/types_wo_allow.c create mode 100644 sechecker/modules/types_wo_allow.h create mode 100644 sechecker/modules/unreachable_doms.c create mode 100644 sechecker/modules/unreachable_doms.h create mode 100644 sechecker/modules/users_wo_roles.c create mode 100644 sechecker/modules/users_wo_roles.h create mode 100644 sechecker/profiles/all-checks-no-mls.sechecker create mode 100644 sechecker/profiles/all-checks.sechecker create mode 100644 sechecker/profiles/analysis-checks.sechecker create mode 100644 sechecker/profiles/devel-checks.sechecker create mode 100644 sechecker/profiles/sechecker.dtd create mode 100644 sechecker/register_list.c create mode 100644 sechecker/register_list.h create mode 100644 sechecker/sechecker.c create mode 100644 sechecker/sechecker.h create mode 100644 sechecker/sechecker_cli.c create mode 100644 sechecker/sechecker_help.txt create mode 100644 sechecker/sechk_parse.c create mode 100644 sechecker/sechk_parse.h (limited to 'sechecker') diff --git a/sechecker/Makefile.am b/sechecker/Makefile.am new file mode 100644 index 0000000..c7d8e7c --- /dev/null +++ b/sechecker/Makefile.am @@ -0,0 +1,67 @@ +setoolsdir = @setoolsdir@ +bin_PROGRAMS = sechecker + +dist_setools_DATA = \ + sechecker_help.txt + +profilesdir = @profile_install_dir@ +dist_profiles_DATA = \ + profiles/all-checks.sechecker \ + profiles/all-checks-no-mls.sechecker \ + profiles/analysis-checks.sechecker \ + profiles/devel-checks.sechecker \ + profiles/sechecker.dtd + +dist_noinst_DATA = \ + modules/template/profiles.readme \ + modules/template/template.howto \ + modules/template/xx.c \ + modules/template/xx.h + +AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \ + @QPOL_CFLAGS@ @APOL_CFLAGS@ @SEFS_CFLAGS@ @XML_CFLAGS@ \ + -DPROFILE_INSTALL_DIR='"${profile_install_dir}"' +AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ + +LDADD = @SELINUX_LIB_FLAG@ @SEFS_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ @XML_LIBS@ -lstdc++ +sechecker_DEPENDENCIES = \ + $(top_builddir)/libsefs/src/libsefs.so \ + $(top_builddir)/libapol/src/libapol.so \ + $(top_builddir)/libqpol/src/libqpol.so + +sechecker_SOURCES = \ + sechecker.c sechecker.h \ + register_list.c register_list.h \ + sechk_parse.c sechk_parse.h \ + sechecker_cli.c \ + modules/attribs_wo_rules.c modules/attribs_wo_rules.h \ + modules/attribs_wo_types.c modules/attribs_wo_types.h \ + modules/domain_and_file.c modules/domain_and_file.h \ + modules/domains_wo_roles.c modules/domains_wo_roles.h \ + modules/find_assoc_types.c modules/find_assoc_types.h \ + modules/find_domains.c modules/find_domains.h \ + modules/find_file_types.c modules/find_file_types.h \ + modules/find_net_domains.c modules/find_net_domains.h \ + modules/find_netif_types.c modules/find_netif_types.h \ + modules/find_node_types.c modules/find_node_types.h \ + modules/find_port_types.c modules/find_port_types.h \ + modules/imp_range_trans.c modules/imp_range_trans.h \ + modules/inc_dom_trans.c modules/inc_dom_trans.h \ + modules/inc_mount.c modules/inc_mount.h \ + modules/inc_net_access.c modules/inc_net_access.h \ + modules/roles_wo_allow.c modules/roles_wo_allow.h \ + modules/roles_wo_types.c modules/roles_wo_types.h \ + modules/roles_wo_users.c modules/roles_wo_users.h \ + modules/spurious_audit.c modules/spurious_audit.h \ + modules/types_wo_allow.c modules/types_wo_allow.h \ + modules/unreachable_doms.c modules/unreachable_doms.h \ + modules/users_wo_roles.c modules/users_wo_roles.h + +$(top_builddir)/libapol/src/libapol.so: + $(MAKE) -C $(top_builddir)/libapol/src $(notdir $@) + +$(top_builddir)/libqpol/src/libqpol.so: + $(MAKE) -C $(top_builddir)/libqpol/src $(notdir $@) + +$(top_builddir)/libsefs/src/libsefs.so: + $(MAKE) -C $(top_builddir)/libsefs/src $(notdir $@) 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 + +#include +#include +#include + +/* 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 +#include +#include +#include +#include + +/* 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 +#include +#include + +/* 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 +#include + + 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 +#include +#include + +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 + + 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 +#include +#include + +/* 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 +#include + + 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 +#include +#include + +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 + +/* 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 +#include +#include + +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 +#include +#include +#include +#include + + 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 + +#include +#include +#include +#include + +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 +#include +#include +#include + + 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 +#include +#include + +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 +#include + +/* 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 + +#include +#include +#include + +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 +#include +#include + +/* 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 + +#include +#include +#include + +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 +#include +#include + +/* 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 + +#include +#include +#include + +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 +#include +#include + + 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 +#include +#include + +#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 : 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 +#include +#include +#include +#include +#include +#include + + 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 +#include +#include + +/* 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 = ""; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = ""; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = ""; + + 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 = ""; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = ""; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = ""; + + 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 = ""; + if (end) + qpol_type_get_name(q, end, &end_name); + else + end_name = ""; + if (ep) + qpol_type_get_name(q, ep, &ep_name); + else + ep_name = ""; + + 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 +#include +#include +#include +#include + +#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 +#include +#include + +/* 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 +#include + +#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 +#include +#include + +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 { 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 { 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, " : 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 { 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 { 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 { 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, " : 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 { 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 { 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 { 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, " : 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 { 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 +#include + +/* 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 +#include +#include + +/* 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 +#include +#include + + 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 +#include +#include + +/* 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 +#include + + 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 +#include +#include + +/* 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 +#include +#include + +/* 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 + +#include +#include +#include + +/* 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 : { 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 + +#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 + 2.1 + 2.2 + 2.3 + 2.4