summaryrefslogtreecommitdiffstats
path: root/sechecker
diff options
context:
space:
mode:
Diffstat (limited to 'sechecker')
-rw-r--r--sechecker/Makefile.am67
-rw-r--r--sechecker/modules/attribs_wo_rules.c520
-rw-r--r--sechecker/modules/attribs_wo_rules.h63
-rw-r--r--sechecker/modules/attribs_wo_types.c399
-rw-r--r--sechecker/modules/attribs_wo_types.h48
-rw-r--r--sechecker/modules/domain_and_file.c398
-rw-r--r--sechecker/modules/domain_and_file.h46
-rw-r--r--sechecker/modules/domains_wo_roles.c386
-rw-r--r--sechecker/modules/domains_wo_roles.h47
-rw-r--r--sechecker/modules/find_assoc_types.c407
-rw-r--r--sechecker/modules/find_assoc_types.h51
-rw-r--r--sechecker/modules/find_domains.c633
-rw-r--r--sechecker/modules/find_domains.h60
-rw-r--r--sechecker/modules/find_file_types.c636
-rw-r--r--sechecker/modules/find_file_types.h60
-rw-r--r--sechecker/modules/find_net_domains.c501
-rw-r--r--sechecker/modules/find_net_domains.h59
-rw-r--r--sechecker/modules/find_netif_types.c489
-rw-r--r--sechecker/modules/find_netif_types.h53
-rw-r--r--sechecker/modules/find_node_types.c479
-rw-r--r--sechecker/modules/find_node_types.h53
-rw-r--r--sechecker/modules/find_port_types.c513
-rw-r--r--sechecker/modules/find_port_types.h50
-rw-r--r--sechecker/modules/imp_range_trans.c513
-rw-r--r--sechecker/modules/imp_range_trans.h52
-rw-r--r--sechecker/modules/inc_dom_trans.c913
-rw-r--r--sechecker/modules/inc_dom_trans.h56
-rw-r--r--sechecker/modules/inc_mount.c520
-rw-r--r--sechecker/modules/inc_mount.h54
-rw-r--r--sechecker/modules/inc_net_access.c1852
-rw-r--r--sechecker/modules/inc_net_access.h51
-rw-r--r--sechecker/modules/roles_wo_allow.c387
-rw-r--r--sechecker/modules/roles_wo_allow.h49
-rw-r--r--sechecker/modules/roles_wo_types.c330
-rw-r--r--sechecker/modules/roles_wo_types.h47
-rw-r--r--sechecker/modules/roles_wo_users.c392
-rw-r--r--sechecker/modules/roles_wo_users.h53
-rw-r--r--sechecker/modules/spurious_audit.c778
-rw-r--r--sechecker/modules/spurious_audit.h53
-rw-r--r--sechecker/modules/template/profiles.readme142
-rw-r--r--sechecker/modules/template/template.howto13
-rw-r--r--sechecker/modules/template/xx.c393
-rw-r--r--sechecker/modules/template/xx.h72
-rw-r--r--sechecker/modules/types_wo_allow.c442
-rw-r--r--sechecker/modules/types_wo_allow.h49
-rw-r--r--sechecker/modules/unreachable_doms.c1053
-rw-r--r--sechecker/modules/unreachable_doms.h73
-rw-r--r--sechecker/modules/users_wo_roles.c321
-rw-r--r--sechecker/modules/users_wo_roles.h47
-rw-r--r--sechecker/profiles/all-checks-no-mls.sechecker98
-rw-r--r--sechecker/profiles/all-checks.sechecker102
-rw-r--r--sechecker/profiles/analysis-checks.sechecker78
-rw-r--r--sechecker/profiles/devel-checks.sechecker74
-rw-r--r--sechecker/profiles/sechecker.dtd19
-rw-r--r--sechecker/register_list.c102
-rw-r--r--sechecker/register_list.h64
-rw-r--r--sechecker/sechecker.c1230
-rw-r--r--sechecker/sechecker.h695
-rw-r--r--sechecker/sechecker_cli.c361
-rw-r--r--sechecker/sechecker_help.txt86
-rw-r--r--sechecker/sechk_parse.c285
-rw-r--r--sechecker/sechk_parse.h44
62 files changed, 17961 insertions, 0 deletions
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 <apol/type-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "attribs_wo_rules";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int attribs_wo_rules_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "attributes not used in any rule";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds attributes in the policy that are not used in any rules; These\n"
+ "attributes will get thrown out by the compiler and have no effect on the \n"
+ "security environment. They are unnecessary and should be removed.\n";
+ mod->opt_description =
+ "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &attribs_wo_rules_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data. */
+int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *attr_vector;
+ apol_role_query_t *role_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_vector_t *avrule_vector;
+ apol_vector_t *terule_vector;
+ apol_vector_t *role_vector;
+ qpol_iterator_t *constraint_iter;
+ qpol_iterator_t *node_iter = NULL;
+ qpol_iterator_t *name_iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int found = 0, error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ATTRIB;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+
+ apol_attr_get_by_query(policy, NULL, &attr_vector);
+ for (i = 0; i < apol_vector_get_size(attr_vector); i++) {
+ qpol_type_t *attr;
+ const char *attr_name;
+ attr = apol_vector_get_element(attr_vector, i);
+ qpol_type_get_name(q, attr, &attr_name);
+
+ /* access rules */
+ apol_avrule_query_set_source(policy, avrule_query, attr_name, 0);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ if (apol_vector_get_size(avrule_vector) > 0) {
+ apol_vector_destroy(&avrule_vector);
+ continue;
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ apol_avrule_query_set_source(policy, avrule_query, NULL, 0);
+ apol_avrule_query_set_target(policy, avrule_query, attr_name, 0);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ if (apol_vector_get_size(avrule_vector) > 0) {
+ apol_vector_destroy(&avrule_vector);
+ continue;
+ }
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ apol_vector_destroy(&avrule_vector);
+
+ /* type rules */
+ apol_terule_query_set_source(policy, terule_query, attr_name, 0);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ if (apol_vector_get_size(terule_vector) > 0) {
+ apol_vector_destroy(&terule_vector);
+ continue;
+ }
+ apol_vector_destroy(&terule_vector);
+
+ apol_terule_query_set_source(policy, terule_query, NULL, 0);
+ apol_terule_query_set_target(policy, terule_query, attr_name, 0);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ if (apol_vector_get_size(terule_vector) > 0) {
+ apol_vector_destroy(&terule_vector);
+ continue;
+ }
+ apol_terule_query_set_target(policy, terule_query, NULL, 0);
+ apol_vector_destroy(&terule_vector);
+
+ /* role trans */
+ apol_role_query_set_type(policy, role_query, attr_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ if (apol_vector_get_size(role_vector) > 0) {
+ apol_vector_destroy(&role_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_vector);
+
+ /* Check constraints */
+ constraint_iter = NULL;
+ node_iter = NULL;
+ name_iter = NULL;
+ found = 0;
+ qpol_policy_get_constraint_iter(q, &constraint_iter);
+ for (; !qpol_iterator_end(constraint_iter); qpol_iterator_next(constraint_iter)) {
+ qpol_constraint_t *constraint;
+
+ qpol_iterator_get_item(constraint_iter, (void **)&constraint);
+ qpol_constraint_get_expr_iter(q, constraint, &node_iter);
+
+ for (; !qpol_iterator_end(node_iter); qpol_iterator_next(node_iter)) {
+ qpol_constraint_expr_node_t *constraint_node;
+ uint32_t node_type;
+
+ qpol_iterator_get_item(node_iter, (void **)&constraint_node);
+ qpol_constraint_expr_node_get_expr_type(q, constraint_node, &node_type);
+
+ if (node_type == QPOL_CEXPR_TYPE_NAMES) {
+ qpol_constraint_expr_node_get_names_iter(q, constraint_node, &name_iter);
+
+ for (; !qpol_iterator_end(name_iter); qpol_iterator_next(name_iter)) {
+ char *name;
+
+ qpol_iterator_get_item(name_iter, (void **)&name);
+ if (!strcmp(name, attr_name)) {
+ found = 1;
+ free(name);
+ name = NULL;
+ break;
+ }
+ free(name);
+ name = NULL;
+ }
+ qpol_iterator_destroy(&name_iter);
+ if (found)
+ break;
+ }
+ }
+ qpol_iterator_destroy(&node_iter);
+ free(constraint);
+ if (found)
+ break;
+ }
+ qpol_iterator_destroy(&constraint_iter);
+ if (found)
+ continue;
+
+ /* if we get here then the attrib was not found anywhere in a rule so add it */
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)attr;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->text = strdup("attribute was not used in any rules.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ }
+ apol_avrule_query_destroy(&avrule_query);
+ apol_role_query_destroy(&role_query);
+ apol_terule_query_destroy(&terule_query);
+ apol_vector_destroy(&attr_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ attribs_wo_rules_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd attributes.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following attributes do not appear in any rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/attribs_wo_rules.h b/sechecker/modules/attribs_wo_rules.h
new file mode 100644
index 0000000..e2869d5
--- /dev/null
+++ b/sechecker/modules/attribs_wo_rules.h
@@ -0,0 +1,63 @@
+/**
+ * @file
+ * Defines the interface for the attributes without rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ATTRIBS_WO_RULES
+#define ATTRIBS_WO_RULES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/avrule-query.h>
+#include <apol/terule-query.h>
+#include <apol/type-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int attribs_wo_rules_register(sechk_lib_t * lib);
+ int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+/* NOTE: While SEChecker is build statically, it is
+ * intended that no module directly call a function
+ * from another but instead use get_module_function()
+ * to get the desired function from the library. */
+
+ int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/attribs_wo_types.c b/sechecker/modules/attribs_wo_types.c
new file mode 100644
index 0000000..edac010
--- /dev/null
+++ b/sechecker/modules/attribs_wo_types.c
@@ -0,0 +1,399 @@
+/**
+ * @file
+ * Implementation of the attributes without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "attribs_wo_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "attribs_wo_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int attribs_wo_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "attributes with no types";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds attributes in the policy that are not associated with any\n"
+ "types. Attributes without types can cause type fields in rules to expand to\n"
+ "empty sets and thus become unreachable. This makes for misleading policy source\n" "files.\n";
+ mod->opt_description =
+ "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *attr_vector = NULL;
+ qpol_iterator_t *types = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ATTRIB;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+
+ apol_attr_get_by_query(policy, NULL, &attr_vector);
+ for (i = 0; i < apol_vector_get_size(attr_vector); i++) {
+ qpol_type_t *attr;
+ const char *attr_name;
+ int at_end;
+
+ attr = apol_vector_get_element(attr_vector, i);
+ qpol_type_get_name(q, attr, &attr_name);
+ qpol_type_get_type_iter(q, attr, &types);
+ at_end = qpol_iterator_end(types);
+ qpol_iterator_destroy(&types);
+ if (!at_end)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->text = (char *)calloc(strlen("attribute has no types") + strlen(attr_name) + 1, sizeof(char));
+ sprintf(proof->text, "attribute %s has no types", attr_name);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ }
+ item->item = (void *)attr;
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ }
+ qpol_iterator_destroy(&types);
+ apol_vector_destroy(&attr_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ attribs_wo_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd attributes.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following attributes are not associated with any types.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * polciy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/attribs_wo_types.h b/sechecker/modules/attribs_wo_types.h
new file mode 100644
index 0000000..da11801
--- /dev/null
+++ b/sechecker/modules/attribs_wo_types.h
@@ -0,0 +1,48 @@
+/**
+ * @file
+ * Defines the interface for the attributes without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ATTRIBS_WO_TYPES
+#define ATTRIBS_WO_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+
+ int attribs_wo_types_register(sechk_lib_t * lib);
+ int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/domain_and_file.c b/sechecker/modules/domain_and_file.c
new file mode 100644
index 0000000..418e2a5
--- /dev/null
+++ b/sechecker/modules/domain_and_file.c
@@ -0,0 +1,398 @@
+/**
+ * @file
+ * Implementation of the domain and file type module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "domain_and_file.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "domain_and_file";
+
+int domain_and_file_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "types treated as a domain and file type";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in the policy treated as both a domain and a file \n"
+ "type. See find_domains and find_file_types modules for details about the \n"
+ "heuristics used to determine these types. It is considered bad security\n"
+ "practice to use the same type for a domain and its data objects because it \n"
+ "requires that less restrictive access be granted to these types.\n";
+ mod->opt_description = "Module requirements:\n" " attribute names\n"
+ " file_contexts\n"
+ "Module dependencies:\n" " find_domains module\n" " find_file_types module\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES);
+ apol_vector_append(mod->requirements, (void *)nv);
+ nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL);
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* assign dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_file_types"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &domain_and_file_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domain_and_file_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domain_and_file_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *domain_res = NULL, *file_type_res = NULL;
+ size_t i, j, k;
+ sechk_mod_fn_t run_fn = NULL;
+ sechk_name_value_t *dep = NULL;
+ apol_vector_t *domain_vector;
+ apol_vector_t *type_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+
+ /* run dependencies */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ /* get results */
+ domain_res = sechk_lib_get_module_result("find_domains", mod->parent_lib);
+ if (!domain_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_domains");
+ goto domain_and_file_run_fail;
+ }
+ file_type_res = sechk_lib_get_module_result("find_file_types", mod->parent_lib);
+ if (!file_type_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_file_types");
+ goto domain_and_file_run_fail;
+ }
+
+ /* get lists */
+ domain_vector = (apol_vector_t *) domain_res->items;
+ type_vector = (apol_vector_t *) file_type_res->items;
+
+ /* build the both list */
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ sechk_item_t *type_item;
+ qpol_type_t *type;
+ const char *type_name;
+
+ type_item = apol_vector_get_element(type_vector, i);
+ type = type_item->item;
+ qpol_type_get_name(q, type, &type_name);
+ for (j = 0; j < apol_vector_get_size(domain_vector); j++) {
+ sechk_item_t *domain_item;
+ qpol_type_t *domain;
+ const char *domain_name;
+
+ domain_item = apol_vector_get_element(domain_vector, j);
+ domain = domain_item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+ if (!strcmp(domain_name, type_name)) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ item->item = (void *)domain;
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ for (k = 0; k < apol_vector_get_size(domain_item->proof); k++) {
+ sechk_proof_t *domain_proof;
+
+ domain_proof = apol_vector_get_element(domain_item->proof, k);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup(domain_proof->text);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ for (k = 0; k < apol_vector_get_size(type_item->proof); k++) {
+ sechk_proof_t *type_proof;
+
+ type_proof = apol_vector_get_element(type_item->proof, k);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup(type_proof->text);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ }
+ }
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ domain_and_file_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/domain_and_file.h b/sechecker/modules/domain_and_file.h
new file mode 100644
index 0000000..81b82c1
--- /dev/null
+++ b/sechecker/modules/domain_and_file.h
@@ -0,0 +1,46 @@
+/**
+ * @file
+ * Defines the interface for the domain and file type module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DOMAIN_AND_FILE
+#define DOMAIN_AND_FILE
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+ int domain_and_file_register(sechk_lib_t * lib);
+ int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/domains_wo_roles.c b/sechecker/modules/domains_wo_roles.c
new file mode 100644
index 0000000..38b42a8
--- /dev/null
+++ b/sechecker/modules/domains_wo_roles.c
@@ -0,0 +1,386 @@
+/**
+ * @file
+ * Implementation of the domains without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "domains_wo_roles.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "domains_wo_roles";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int domains_wo_roles_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with no roles";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all domains in the policy not associated with a role. These \n"
+ "domains cannot have a valid security context. The object_r role is not \n" "considered in this check.\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign requirements */
+ apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES));
+
+ /* assign dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. */
+int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int retv, error;
+ size_t i;
+ sechk_module_t *mod_ptr = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ apol_vector_t *domain_vector;
+ apol_vector_t *role_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ apol_role_query_t *role_query = NULL;
+ sechk_result_t *find_domains_res = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto domains_wo_roles_run_fail;
+ }
+
+ run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib);
+ if (!run_fn) {
+ error = errno;
+ ERR(policy, "%s", "Unable to find run function for module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL);
+ if (retv) {
+ error = errno;
+ ERR(policy, "%s", "Unable to run module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ domain_vector = (apol_vector_t *) find_domains_res->items;
+
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto domains_wo_roles_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ qpol_type_t *domain;
+ const char *domain_name;
+
+ item = apol_vector_get_element(domain_vector, i);
+ domain = item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+
+ apol_role_query_set_type(policy, role_query, domain_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ if (apol_vector_get_size(role_vector) > 0) {
+ apol_vector_destroy(&role_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->text = strdup("Domain has no role.\n");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ item->item = (void *)domain;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ }
+ apol_role_query_destroy(&role_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ domains_wo_roles_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are domains but not associated with any roles.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
diff --git a/sechecker/modules/domains_wo_roles.h b/sechecker/modules/domains_wo_roles.h
new file mode 100644
index 0000000..e46a9b3
--- /dev/null
+++ b/sechecker/modules/domains_wo_roles.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the domains without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DOMAINS_WO_ROLES
+#define DOMAINS_WO_ROLES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+
+ int domains_wo_roles_register(sechk_lib_t * lib);
+ int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_assoc_types.c b/sechecker/modules/find_assoc_types.c
new file mode 100644
index 0000000..0e72801
--- /dev/null
+++ b/sechecker/modules/find_assoc_types.c
@@ -0,0 +1,407 @@
+/**
+ * @file
+ * Implementation of the association types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_assoc_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_assoc_types";
+
+int find_assoc_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds types with an unlabeled initial sid. \n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t buff_sz = 0;
+ const qpol_isid_t *isid;
+ const char *type_name = NULL;
+ const qpol_type_t *type;
+ const qpol_context_t *context;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto find_assoc_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+
+ /* Initialize vectors */
+
+ qpol_policy_get_isid_by_name(q, "unlabeled", &isid);
+ if (!isid) {
+ error = errno;
+ goto find_assoc_types_run_fail;
+ }
+
+ if (apol_str_append(&buff, &buff_sz, "sid unlabeled ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &type);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (apol_str_append(&buff, &buff_sz, type_name) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ }
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ item->test_result = 1;
+ item->item = (void *)type;
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = buff;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ mod->result = res;
+
+ return 0;
+
+ find_assoc_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Error: wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd assoc type(s).\n", num_items);
+ }
+ /* The list reassoc component is a display of all items
+ * found without any supassocing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ i++;
+ i %= 4;
+ item = apol_vector_get_element(mod->result->items, j);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item)
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof reassoc component is a display of a list of items
+ * with an indented list of proof statements supassocing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < apol_vector_get_size(mod->result->items); j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_assoc_types.h b/sechecker/modules/find_assoc_types.h
new file mode 100644
index 0000000..23cda10
--- /dev/null
+++ b/sechecker/modules/find_assoc_types.h
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * Defines the interface for the association types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_ASSOC_TYPES
+#define FIND_ASSOC_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_assoc_types_register(sechk_lib_t * lib);
+ int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_domains.c b/sechecker/modules/find_domains.c
new file mode 100644
index 0000000..b59abac
--- /dev/null
+++ b/sechecker/modules/find_domains.c
@@ -0,0 +1,633 @@
+/**
+ * @file
+ * Implementation of the find domains utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_domains.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_domains";
+
+int find_domains_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This is a utility module which finds types in a policy that are treated as a \n"
+ "domain. A type is considered a domain if any of the following is true:\n"
+ "\n"
+ " 1) it has an attribute associated with domains\n"
+ " 2) it is the source of a TE rule for object class other than filesystem\n"
+ " 3) it is the default type in a type_transition rule for object class process \n"
+ " 4) it is associated with a role other than object_r\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n"
+ "Module dependencies:\n" " none\n" "Module options:\n" " domain_attributes can be set in a profile\n";
+ mod->severity = SECHK_SEV_NONE;
+ /* assign requirements */
+ apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES));
+
+ /* assign options */
+ apol_vector_append(mod->options, sechk_name_value_new("domain_attribute", "domain"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_init;
+ apol_vector_append(mod->functions, fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_run;
+ apol_vector_append(mod->functions, fn_struct);
+
+ mod->data_free = find_domains_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_print;
+ apol_vector_append(mod->functions, fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_get_list;
+ apol_vector_append(mod->functions, fn_struct);
+
+ return 0;
+}
+
+int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_domains_data_t *datum = NULL;
+ size_t i, j;
+ qpol_type_t *attr = NULL;
+ apol_vector_t *attr_vector = NULL;
+ apol_attr_query_t *attr_query = apol_attr_query_create();
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_domains_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!(datum->domain_attribs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "domain_attribute")) {
+ apol_attr_query_set_attr(policy, attr_query, opt->value);
+ apol_attr_get_by_query(policy, attr_query, &attr_vector);
+ for (j = 0; j < apol_vector_get_size(attr_vector); j++) {
+ const char *domain_attrib;
+ attr = apol_vector_get_element(attr_vector, j);
+ qpol_type_get_name(q, attr, &domain_attrib);
+ if (apol_vector_append(datum->domain_attribs, (void *)domain_attrib) < 0) {
+ apol_vector_destroy(&attr_vector);
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+
+ }
+ }
+ apol_vector_destroy(&attr_vector);
+ }
+ }
+ apol_attr_query_destroy(&attr_query);
+ return 0;
+}
+
+int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ int error = 0;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ const char *type_name = NULL;
+ find_domains_data_t *datum = NULL;
+ size_t i, j, proof_idx;
+ apol_vector_t *domain_vector = NULL, *avrule_vector = NULL, *terule_vector = NULL, *role_vector = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_role_query_t *role_query = NULL;
+ qpol_iterator_t *domain_attr_iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (find_domains_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return -1;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+
+ if (apol_type_get_by_query(policy, NULL, &domain_vector) < 0) {
+ goto find_domains_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ qpol_type_t *type = apol_vector_get_element(domain_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (qpol_type_get_attr_iter(q, type, &domain_attr_iter) < 0) {
+ error = errno;
+ ERR(policy, "Can't get attributes for type %s", type_name);
+ goto find_domains_run_fail;
+ }
+
+ for (; !qpol_iterator_end(domain_attr_iter); qpol_iterator_next(domain_attr_iter)) {
+ const char *attr_name;
+ const qpol_type_t *attr;
+ size_t nfta;
+
+ qpol_iterator_get_item(domain_attr_iter, (void **)&attr);
+ qpol_type_get_name(q, attr, &attr_name);
+ for (nfta = 0; nfta < apol_vector_get_size(datum->domain_attribs); nfta++) {
+ const char *domain_attrib;
+
+ domain_attrib = apol_vector_get_element(datum->domain_attribs, nfta);
+ if (!strcmp(attr_name, domain_attrib)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->elem = (void *)attr;
+ asprintf(&proof->text, "%s has attribute %s", type_name, attr_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ }
+ }
+ qpol_iterator_destroy(&domain_attr_iter);
+
+ /* rule src check !filesystem associate */
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 0);
+ if (apol_avrule_get_by_query(policy, avrule_query, &avrule_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve AV rules");
+ goto find_domains_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ const qpol_avrule_t *avrule = NULL;
+ const qpol_class_t *class = NULL;
+ const char *class_name = NULL;
+
+ avrule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_object_class(q, avrule, &class);
+ qpol_class_get_name(q, class, &class_name);
+ if (strcmp("filesystem", class_name)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* type rule check file object */
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_terule_query_set_default(policy, terule_query, type_name);
+ apol_terule_query_append_class(policy, terule_query, "process");
+ if (apol_terule_get_by_query(policy, terule_query, &terule_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve TE rules");
+ goto find_domains_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(terule_vector); j++) {
+ qpol_terule_t *terule = NULL;
+ terule = apol_vector_get_element(terule_vector, j);
+
+ if (apol_vector_get_index(item->proof, terule, sechk_proof_with_element_compare, NULL, &proof_idx) == 0)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_TERULE;
+ proof->elem = terule;
+ proof->text = apol_terule_render(policy, terule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ apol_vector_destroy(&terule_vector);
+ apol_terule_query_destroy(&terule_query);
+
+ /* Check Roles */
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_role_query_set_type(policy, role_query, type_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ for (j = 0; j < apol_vector_get_size(role_vector); j++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = (qpol_role_t *) apol_vector_get_element(role_vector, j);
+ qpol_role_get_name(q, role, &role_name);
+ if (!strcmp("object_r", role_name))
+ continue;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ proof->elem = (void *)role;
+ asprintf(&proof->text, "role %s types %s;", role_name, type_name);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto find_domains_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+ apol_role_query_destroy(&role_query);
+
+ /* insert any results for this type */
+ if (item) {
+ item->item = type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ item = NULL;
+ type = NULL;
+ type_name = NULL;
+ }
+ apol_vector_destroy(&domain_vector);
+
+ /* results are valid at this point */
+ mod->result = res;
+ return 0;
+
+ find_domains_run_fail:
+ qpol_iterator_destroy(&domain_attr_iter);
+ apol_vector_destroy(&domain_vector);
+ apol_vector_destroy(&avrule_vector);
+ apol_vector_destroy(&terule_vector);
+ apol_vector_destroy(&role_vector);
+ apol_avrule_query_destroy(&avrule_query);
+ apol_terule_query_destroy(&terule_query);
+ apol_role_query_destroy(&role_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+void find_domains_data_free(void *data)
+{
+ find_domains_data_t *datum = (find_domains_data_t *) data;
+
+ if (datum) {
+ apol_vector_destroy(&datum->domain_attribs);
+ }
+ free(data);
+}
+
+int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_domains_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ sechk_proof_t *proof = NULL;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp("find_domains", mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_domains_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET)) {
+ return 0; /* not an error - no output is requested */
+ }
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i domain types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are domains.\n");
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+find_domains_data_t *find_domains_data_new(void)
+{
+ find_domains_data_t *datum = NULL;
+
+ datum = (find_domains_data_t *) calloc(1, sizeof(find_domains_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_domains.h b/sechecker/modules/find_domains.h
new file mode 100644
index 0000000..917cd41
--- /dev/null
+++ b/sechecker/modules/find_domains.h
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Defines the interface for the find domains utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_DOMAINS
+#define FIND_DOMAINS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+#include <apol/role-query.h>
+#include <apol/terule-query.h>
+#include <apol/avrule-query.h>
+
+ typedef struct find_domains_data
+ {
+ apol_vector_t *domain_attribs;
+ int num_domain_attribs;
+ } find_domains_data_t;
+
+ void find_domains_data_free(void *data);
+ find_domains_data_t *find_domains_data_new(void);
+
+ int find_domains_register(sechk_lib_t * lib);
+ int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_file_types.c b/sechecker/modules/find_file_types.c
new file mode 100644
index 0000000..193e3f3
--- /dev/null
+++ b/sechecker/modules/find_file_types.c
@@ -0,0 +1,636 @@
+/**
+ * @file
+ * Implementation of the find file types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Randy Wicks rwicks@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_file_types.h"
+
+#include <qpol/genfscon_query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_file_types";
+
+int find_file_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in the policy treated as a file type. A type is \n"
+ "considered a file type if any of the following is true:\n"
+ "\n"
+ " 1) it has an attribute associated with file types\n"
+ " 2) it is the source of a rule to allow filesystem associate permission\n"
+ " 3) it is the default type of a type transition rule with an object class\n" " other than process\n"
+ " 4) it is specified in a context in the file_contexts file\n";
+ mod->opt_description = "Module requirements:\n" " attribute names\n"
+ " file_contexts\n"
+ "Module dependencies:\n" " none\n" "Module options:\n" " file_type_attribute can be modified in a profile\n";
+ mod->severity = SECHK_SEV_NONE;
+ /* assign requirements */
+ nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES);
+ apol_vector_append(mod->requirements, (void *)nv);
+ nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL);
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* assign options */
+ nv = sechk_name_value_new("file_type_attribute", "file_type");
+ apol_vector_append(mod->options, (void *)nv);
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = find_file_types_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_file_types_data_t *datum = NULL;
+ apol_vector_t *attr_vector = NULL;
+ apol_attr_query_t *attr_query = apol_attr_query_create();
+ qpol_type_t *attr = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i = 0, j = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_file_types_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ if (!(datum->file_type_attribs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "file_type_attribute")) {
+ apol_attr_query_set_attr(policy, attr_query, opt->value);
+ apol_attr_get_by_query(policy, attr_query, &attr_vector);
+ for (j = 0; j < apol_vector_get_size(attr_vector); j++) {
+ const char *file_attrib;
+ attr = apol_vector_get_element(attr_vector, j);
+ qpol_type_get_name(q, attr, &file_attrib);
+ if (apol_vector_append(datum->file_type_attribs, (void *)file_attrib) < 0) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ apol_vector_destroy(&attr_vector);
+ }
+ }
+ apol_attr_query_destroy(&attr_query);
+ return 0;
+}
+
+int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_file_types_data_t *datum;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *res = NULL;
+ const char *type_name = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_vector_t *avrule_vector = NULL;
+ apol_vector_t *terule_vector = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, j, x;
+ char *buff = NULL;
+ int error = 0;
+
+ /* NEW */
+ size_t num_fc_entries = 0;
+ apol_vector_t *type_vector = NULL;
+ apol_vector_t *fc_entry_vector = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ datum = (find_file_types_data_t *) mod->data;
+ res->item_type = SECHK_ITEM_TYPE;
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ if (mod->parent_lib->fc_entries) {
+ if (mod->parent_lib->fc_path) {
+ fc_entry_vector = mod->parent_lib->fc_entries;
+ num_fc_entries = apol_vector_get_size(fc_entry_vector);
+ } else {
+ error = ENOENT;
+ ERR(policy, "%s", "Unable to find file contexts file");
+ goto find_file_types_run_fail;
+ }
+ }
+
+ /* Get an iterator for the types */
+ if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve types");
+ return -1;
+ }
+
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ qpol_iterator_t *file_attr_iter;
+
+ const qpol_type_t *type = apol_vector_get_element(type_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (qpol_type_get_attr_iter(q, type, &file_attr_iter) < 0) {
+ error = errno;
+ ERR(policy, "Could not get attributes for %s\n", type_name);
+ goto find_file_types_run_fail;
+ }
+
+ for (; !qpol_iterator_end(file_attr_iter); qpol_iterator_next(file_attr_iter)) {
+ const char *attr_name;
+ const qpol_type_t *attr;
+ size_t nfta;
+
+ qpol_iterator_get_item(file_attr_iter, (void **)&attr);
+ qpol_type_get_name(q, attr, &attr_name);
+ for (nfta = 0; nfta < apol_vector_get_size(datum->file_type_attribs); nfta++) {
+ const char *file_type_attrib;
+
+ file_type_attrib = apol_vector_get_element(datum->file_type_attribs, nfta);
+ if (!strcmp(attr_name, file_type_attrib)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->elem = (void *)attr;
+ asprintf(&proof->text, "has attribute %s", attr_name);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ }
+ qpol_iterator_destroy(&file_attr_iter);
+
+ /* rule src check filesystem associate */
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", "Could not retrieve AV rules");
+ goto find_file_types_run_fail;
+ }
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 0);
+ apol_avrule_query_append_class(policy, avrule_query, "filesystem");
+ apol_avrule_query_append_perm(policy, avrule_query, "associate");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (x = 0; x < apol_vector_get_size(avrule_vector); x++) {
+ qpol_avrule_t *avrule;
+ avrule = apol_vector_get_element(avrule_vector, x);
+ if (avrule) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = avrule;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* type rule check file object */
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", "Could not retrieve TE rules");
+ goto find_file_types_run_fail;
+ }
+ apol_terule_query_set_default(policy, terule_query, type_name);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ for (x = 0; x < apol_vector_get_size(terule_vector); x++) {
+ const qpol_terule_t *terule;
+ const qpol_class_t *objclass;
+ const char *class_name;
+
+ terule = apol_vector_get_element(terule_vector, x);
+ qpol_terule_get_object_class(q, terule, &objclass);
+ qpol_class_get_name(q, objclass, &class_name);
+ if (strcmp(class_name, "process")) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_TERULE;
+ proof->elem = (void *)terule;
+ proof->text = apol_terule_render(policy, terule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&terule_vector);
+ apol_terule_query_destroy(&terule_query);
+
+ /* assigned in fc check */
+ if (fc_entry_vector) {
+ buff = NULL;
+ for (j = 0; j < num_fc_entries; j++) {
+ sefs_entry_t *fc_entry;
+ const char *fc_type_name = NULL;
+ fc_entry = apol_vector_get_element(fc_entry_vector, j);
+ const apol_context_t *context = sefs_entry_get_context(fc_entry);
+ if (!context)
+ continue;
+ fc_type_name = apol_context_get_type(context);
+ if (!strcmp(type_name, fc_type_name)) {
+ buff = sefs_entry_to_string(fc_entry);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_FCENT;
+ proof->elem = fc_entry;
+ proof->text = buff;
+ buff = NULL;
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ }
+ /* insert any results for this type */
+ if (item) {
+ item->item = (void *)type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item = NULL;
+ type = NULL;
+ type_name = NULL;
+ }
+ apol_vector_destroy(&type_vector);
+
+ /* results are valid at this point */
+ mod->result = res;
+
+ return 0;
+
+ find_file_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ apol_vector_destroy(&type_vector);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+void find_file_types_data_free(void *data)
+{
+ find_file_types_data_t *datum = (find_file_types_data_t *) data;
+
+ if (datum) {
+ apol_vector_destroy(&datum->file_type_attribs);
+ }
+ free(data);
+}
+
+int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_file_types_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_file_types_data_t *) mod->data;
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+ if (outformat & SECHK_OUT_STATS) {
+ num_items = apol_vector_get_size(mod->result->items);
+ printf("Found %zd file types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are file types.\n\n");
+ }
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < apol_vector_get_size(mod->result->items); k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg
+ __attribute__ ((unused)))
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+find_file_types_data_t *find_file_types_data_new(void)
+{
+ find_file_types_data_t *datum = NULL;
+
+ datum = (find_file_types_data_t *) calloc(1, sizeof(find_file_types_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_file_types.h b/sechecker/modules/find_file_types.h
new file mode 100644
index 0000000..941862b
--- /dev/null
+++ b/sechecker/modules/find_file_types.h
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Defines the interface for the find file types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Randy Wicks rwicks@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_FILE_TYPES
+#define FIND_FILE_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+#include <apol/avrule-query.h>
+#include <apol/terule-query.h>
+
+ typedef struct find_file_types_data
+ {
+ apol_vector_t *file_type_attribs;
+ int num_file_type_attribs;
+ } find_file_types_data_t;
+
+ void find_file_types_data_free(void *data);
+ find_file_types_data_t *find_file_types_data_new(void);
+
+ int find_file_types_register(sechk_lib_t * lib);
+ int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_net_domains.c b/sechecker/modules/find_net_domains.c
new file mode 100644
index 0000000..dadd459
--- /dev/null
+++ b/sechecker/modules/find_net_domains.c
@@ -0,0 +1,501 @@
+/**
+ * @file
+ * Implementation of the network domain utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_net_domains.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_net_domains";
+
+int find_net_domains_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy considered to be network domains. \n"
+ "A type is considered a network domain if it is the subject of TE rules \n"
+ "involving certain object classes, which are currently defined as:\n"
+ " 1) netif\n"
+ " 2) tcp_socket\n"
+ " 3) udp_socket\n"
+ " 4) node\n" " 5) association\n" "These values can be overridden in this module's profile.";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n"
+ " net_obj\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* assign default options */
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "netif"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "tcp_socket"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "udp_socket"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "node"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "association"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = find_net_domains_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_net_domains_data_t *datum = NULL;
+ size_t i;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_net_domains_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!(datum->net_objs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "net_obj")) {
+ if (apol_vector_append(datum->net_objs, (void *)opt->value) < 0) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_net_domains_data_t *datum;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error = 0;
+ size_t i = 0, j = 0, k = 0;
+ apol_vector_t *avrule_vector;
+ apol_avrule_query_t *avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (find_net_domains_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (k = 0; k < apol_vector_get_size(avrule_vector); k++) {
+ const qpol_avrule_t *avrule;
+ const qpol_class_t *class;
+ const char *class_name;
+
+ avrule = apol_vector_get_element(avrule_vector, k);
+ qpol_avrule_get_object_class(q, avrule, &class);
+ qpol_class_get_name(q, class, &class_name);
+ for (i = 0; i < apol_vector_get_size(datum->net_objs); i++) {
+ const char *net_obj_name;
+
+ net_obj_name = apol_vector_get_element(datum->net_objs, i);
+ if (!strcmp(class_name, net_obj_name)) {
+ const qpol_type_t *source;
+ const char *source_name;
+
+ qpol_avrule_get_source_type(q, avrule, &source);
+ qpol_type_get_name(q, source, &source_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)avrule;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item = NULL;
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, source_name))
+ item = res_item;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)source;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item = NULL;
+ }
+ }
+ }
+ apol_avrule_query_destroy(&avrule_query);
+ apol_vector_destroy(&avrule_vector);
+ mod->result = res;
+
+ return 0;
+
+ find_net_domains_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module */
+void find_net_domains_data_free(void *data)
+{
+ find_net_domains_data_t *d = data;
+ apol_vector_destroy(&d->net_objs);
+ free(data);
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_net_domains_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_net_domains_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("\nFound %i network domains.", num_items);
+ }
+
+ /* The list renode component is a display of all items
+ * found without any supnodeing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renode component is a display of a list of items
+ * with an indented list of proof statements supnodeing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+/* The find_net_domains_data_new function allocates and returns an
+ * initialized private data storage structure for this
+ * module. Initialization expected is as follows:
+ * all arrays (including strings) are initialized to NULL
+ * array sizes are set to 0
+ * any other pointers should be NULL
+ * indices into other arrays (such as type or permission indices)
+ * should be initialized to -1
+ * any other data should be initialized as needed by the check logic */
+find_net_domains_data_t *find_net_domains_data_new(void)
+{
+ find_net_domains_data_t *datum = NULL;
+
+ datum = (find_net_domains_data_t *) calloc(1, sizeof(find_net_domains_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_net_domains.h b/sechecker/modules/find_net_domains.h
new file mode 100644
index 0000000..68eeb75
--- /dev/null
+++ b/sechecker/modules/find_net_domains.h
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * Defines the interface for the network domain utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NET_DOMAINS
+#define FIND_NET_DOMAINS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+/* The find_net_domains_data structure is used to hold the check specific
+ * private data of a module. */
+ typedef struct find_net_domains_data
+ {
+ apol_vector_t *net_objs;
+ } find_net_domains_data_t;
+
+ find_net_domains_data_t *find_net_domains_data_new(void);
+ void find_net_domains_data_free(void *data);
+
+ int find_net_domains_register(sechk_lib_t * lib);
+ int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_netif_types.c b/sechecker/modules/find_netif_types.c
new file mode 100644
index 0000000..e703687
--- /dev/null
+++ b/sechecker/modules/find_netif_types.c
@@ -0,0 +1,489 @@
+/**
+ * @file
+ * Implementation of the netif types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_netif_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_netif_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int find_netif_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a netif type. A type is\n"
+ "a netif type if it is used in the internace context in a netifcon statement or\n"
+ "the context of the netif initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t i, buff_sz = 0;
+ apol_vector_t *netifcon_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "netif", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid netif ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_netif_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ free(tmp);
+ apol_context_destroy(&a_context);
+ goto find_netif_types_run_fail;
+ }
+ apol_context_destroy(&a_context);
+ free(tmp);
+ tmp = NULL;
+
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item->test_result = 1;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ item->item = (void *)context_type;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+
+ if (apol_netifcon_get_by_query(policy, NULL, &netifcon_vector) < 0) {
+ error = errno;
+ goto find_netif_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(netifcon_vector); i++) {
+ const char *msg_con_name = NULL;
+ const char *if_con_name = NULL;
+ qpol_netifcon_t *netifcon = NULL;
+ const qpol_context_t *msg_con = NULL;
+ const qpol_context_t *if_con = NULL;
+ const qpol_type_t *msg_type = NULL;
+ const qpol_type_t *if_type = NULL;
+ size_t j = 0;
+
+ netifcon = apol_vector_get_element(netifcon_vector, i);
+ qpol_netifcon_get_msg_con(q, netifcon, &msg_con);
+ qpol_netifcon_get_if_con(q, netifcon, &if_con);
+ qpol_context_get_type(q, msg_con, &msg_type);
+ qpol_context_get_type(q, if_con, &if_type);
+ qpol_type_get_name(q, msg_type, &msg_con_name);
+ qpol_type_get_name(q, if_type, &if_con_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_NETIFCON;
+ proof->elem = netifcon;
+ proof->text = apol_netifcon_render(policy, netifcon);
+ item = NULL;
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = (qpol_type_t *) res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, if_con_name))
+ item = res_item;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)if_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&netifcon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_netif_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text and prints the
+ * results to stdout. The outline below prints
+ * the standard format of a renetif section. Some modules may
+ * not have results in a format that can be represented by this
+ * outline and will need a different specification. It is
+ * required that each of the flags for output components be
+ * tested in this function (stats, list, proof, detailed, and brief) */
+int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i netif types.\n", num_items);
+ }
+
+ /* The list renetif component is a display of all items
+ * found without any supnetifing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renetif component is a display of a list of items
+ * with an indented list of proof statements supnetifing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_netif_types.h b/sechecker/modules/find_netif_types.h
new file mode 100644
index 0000000..859ee8a
--- /dev/null
+++ b/sechecker/modules/find_netif_types.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the netif types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NETIF_TYPES_H
+#define FIND_NETIF_TYPES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_netif_types_register(sechk_lib_t * lib);
+ int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_node_types.c b/sechecker/modules/find_node_types.c
new file mode 100644
index 0000000..f10be10
--- /dev/null
+++ b/sechecker/modules/find_node_types.c
@@ -0,0 +1,479 @@
+/**
+ * @file
+ * Implementation of the node types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_node_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_node_types";
+
+/* The register function registers all of a module's functions
+ * with the library. You should not need to edit this function
+ * unless you are adding additional functions you need other modules
+ * to call. See the note at the bottom of this function to do so. */
+int find_node_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Unknown module");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a node type. A type is\n"
+ "considered a node type if it is used in the context of a nodecon statement or\n"
+ "the context of the node initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t i, buff_sz = 0;
+ apol_vector_t *nodecon_vector = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "node", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid node ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_node_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ free(tmp);
+ goto find_node_types_run_fail;
+ }
+ apol_context_destroy(&a_context);
+ free(tmp);
+ tmp = NULL;
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ item->item = (void *)context_type;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+
+ if (apol_nodecon_get_by_query(policy, NULL, &nodecon_vector) < 0) {
+ error = errno;
+ goto find_node_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(nodecon_vector); i++) {
+ const char *type_name;
+ size_t j;
+ const qpol_context_t *context;
+ const qpol_type_t *context_type;
+ qpol_nodecon_t *nodecon = apol_vector_get_element(nodecon_vector, i);
+ qpol_nodecon_get_context(q, nodecon, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &type_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->text = apol_nodecon_render(policy, nodecon);
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, type_name))
+ item = res_item;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)context_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&nodecon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_node_types_run_fail:
+ apol_vector_destroy(&nodecon_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the results to stdout. */
+int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i node types.\n", num_items);
+ }
+
+ /* The list renode component is a display of all items
+ * found without any supnodeing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renode component is a display of a list of items
+ * with an indented list of proof statements supnodeing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_node_types.h b/sechecker/modules/find_node_types.h
new file mode 100644
index 0000000..44ac749
--- /dev/null
+++ b/sechecker/modules/find_node_types.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the node types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NODE_TYPES_H
+#define FINE_NODE_TYPES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_node_types_register(sechk_lib_t * lib);
+ int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_port_types.c b/sechecker/modules/find_port_types.c
new file mode 100644
index 0000000..8e55bc3
--- /dev/null
+++ b/sechecker/modules/find_port_types.c
@@ -0,0 +1,513 @@
+/**
+ * @file
+ * Implementation of the port types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_port_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_port_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int find_port_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a port type. A type is\n"
+ "considered a port type if it is used in the context of a a portcon statement or\n"
+ "the context of the port initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &find_port_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t buff_sz = 0, i, j;
+ apol_vector_t *portcon_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "port", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid port ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_port_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ free(tmp);
+ goto find_port_types_run_fail;
+ }
+ free(tmp);
+ tmp = NULL;
+ apol_context_destroy(&a_context);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ /* Have we encountered this type before? If so, use that type. */
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, context_type_name))
+ item = res_item;
+ }
+
+ /* We have not encountered this type yet */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)context_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (apol_portcon_get_by_query(policy, NULL, &portcon_vector) < 0) {
+ error = errno;
+ goto find_port_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(portcon_vector); i++) {
+ const char *portcon_name = NULL;
+ const qpol_portcon_t *portcon = NULL;
+ const qpol_context_t *portcon_context = NULL;
+ const qpol_type_t *portcon_type = NULL;
+
+ portcon = apol_vector_get_element(portcon_vector, i);
+ qpol_portcon_get_context(q, portcon, &portcon_context);
+ qpol_context_get_type(q, portcon_context, &portcon_type);
+ qpol_type_get_name(q, portcon_type, &portcon_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_PORTCON;
+ proof->elem = (void *)portcon;
+ proof->text = apol_portcon_render(policy, portcon);
+ item = NULL;
+
+ /* Have we encountered this type before? If so, use that type. */
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, portcon_name))
+ item = res_item;
+ }
+
+ /* We have not encountered this type yet */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)portcon_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&portcon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_port_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i port types.\n", num_items);
+ }
+
+ /* The list report component is a display of all items
+ * found without any supporting proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_port_types.h b/sechecker/modules/find_port_types.h
new file mode 100644
index 0000000..adb19bf
--- /dev/null
+++ b/sechecker/modules/find_port_types.h
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * Defines the interface for the port types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_PORT_TYPES
+#define FIND_PORT_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+ int find_port_types_register(sechk_lib_t * lib);
+ int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/imp_range_trans.c b/sechecker/modules/imp_range_trans.c
new file mode 100644
index 0000000..8fbf361
--- /dev/null
+++ b/sechecker/modules/imp_range_trans.c
@@ -0,0 +1,513 @@
+/**
+ * @file
+ * Implementation of the impossible range_transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author: David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "imp_range_trans.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define SECHK_NO_ROLES 0x000002
+#define SECHK_BAD_USER_MLS_LOW 0x000040
+#define SECHK_BAD_USER_MLS_HIGH 0x000600
+#define SECHK_NO_USERS 0x008000
+#define SECHK_NO_EXEC_PERMS 0x020000
+
+static const char *const mod_name = "imp_range_trans";
+
+int imp_range_trans_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "finds impossible range transitions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds impossible range transitions in a policy.\n"
+ "A range transition is possible if and only if all of the following conditions\n"
+ "are satisfied:\n"
+ " 1) there exist TE rules allowing the range transition to occur\n"
+ " 2) there exist RBAC rules allowing the range transition to occur\n"
+ " 3) at least one user must be able to transition to the target MLS range\n";
+ mod->opt_description =
+ " Module requirements:\n" " MLS policy\n" " Module dependencies:\n" " none\n" " Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_MED;
+
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_MLS)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j;
+ apol_vector_t *range_trans_vector = NULL, *role_vector = NULL, *tmp_v = NULL;
+ apol_vector_t *user_vector = NULL, *users_w_roles = NULL, *users_w_range = NULL;
+ apol_vector_t *rule_vector = NULL;
+ const qpol_range_trans_t *rule;
+ const qpol_type_t *source = NULL;
+ const qpol_type_t *target = NULL;
+ const qpol_role_t *role = NULL;
+ const char *source_name = NULL, *target_name = NULL, *role_name = NULL;
+ apol_role_query_t *role_query = NULL;
+ apol_user_query_t *user_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_mls_range_t *range;
+ const qpol_mls_range_t *qpol_range;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ res->item_type = SECHK_ITEM_RANGETRANS;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+
+ if (apol_range_trans_get_by_query(policy, NULL, &range_trans_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve range transitions");
+ goto imp_range_trans_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(range_trans_vector); i++) {
+ /* collect information about the rule */
+ rule = apol_vector_get_element(range_trans_vector, i);
+ qpol_range_trans_get_source_type(q, rule, &source);
+ qpol_range_trans_get_target_type(q, rule, &target);
+ qpol_type_get_name(q, source, &source_name);
+ qpol_type_get_name(q, target, &target_name);
+ qpol_range_trans_get_range(q, rule, &qpol_range);
+ range = apol_mls_range_create_from_qpol_mls_range(policy, qpol_range);
+
+ /* find roles possible for source */
+ role_query = apol_role_query_create();
+ apol_role_query_set_type(policy, role_query, source_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ apol_role_query_destroy(&role_query);
+
+ /* find users with the possible roles */
+ if ((users_w_roles = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ goto imp_range_trans_run_fail;
+ }
+ user_query = apol_user_query_create();
+ for (j = 0; j < apol_vector_get_size(role_vector); j++) {
+ role = apol_vector_get_element(role_vector, j);
+ qpol_role_get_name(q, role, &role_name);
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &tmp_v);
+ apol_vector_cat(users_w_roles, tmp_v);
+ apol_vector_destroy(&tmp_v);
+ }
+ apol_vector_sort_uniquify(users_w_roles, NULL, NULL);
+ apol_user_query_destroy(&user_query);
+
+ /* find users with the transition range */
+ user_query = apol_user_query_create();
+ apol_user_query_set_range(policy, user_query, range, APOL_QUERY_SUB);
+ apol_user_get_by_query(policy, user_query, &users_w_range);
+ apol_user_query_destroy(&user_query);
+
+ /* find intersection of user sets */
+ user_vector = apol_vector_create_from_intersection(users_w_roles, users_w_range, NULL, NULL);
+
+ /* find avrules for allow <source> <target> : file execute; */
+ avrule_query = apol_avrule_query_create();
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, avrule_query, source_name, 1);
+ apol_avrule_query_set_target(policy, avrule_query, target_name, 1);
+ apol_avrule_query_append_class(policy, avrule_query, "file");
+ apol_avrule_query_append_perm(policy, avrule_query, "execute");
+ apol_avrule_get_by_query(policy, avrule_query, &rule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* check avrules */
+ if (!apol_vector_get_size(rule_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ asprintf(&proof->text, "Missing: allow %s %s : file execute;", source_name, target_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ proof = NULL;
+ }
+ apol_vector_destroy(&rule_vector);
+
+ /* check RBAC */
+ if (!apol_vector_get_size(role_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ asprintf(&proof->text, "No role associated with type %s", source_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ proof = NULL;
+ }
+
+ /* check users */
+ if (!apol_vector_get_size(user_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ if (!apol_vector_get_size(role_vector)) {
+ proof->text = strdup("No role also means no user");
+ } else if (!apol_vector_get_size(users_w_roles)) {
+ asprintf(&proof->text, "No users associated with roles for %s", source_name);
+ } else if (!apol_vector_get_size(users_w_range)) {
+ proof->text = strdup("No user has access to specified MLS range");
+ } else {
+ proof->text = strdup("No user meets MLS and RBAC requirements.");
+ }
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&users_w_roles);
+ apol_vector_destroy(&users_w_range);
+
+ if (item) {
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&range_trans_vector);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ imp_range_trans_run_fail:
+ apol_vector_destroy(&range_trans_vector);
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&rule_vector);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&users_w_roles);
+ apol_vector_destroy(&users_w_range);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text and prints the
+ * results to stdout. */
+int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ qpol_range_trans_t *rt;
+ char *tmp;
+ size_t i = 0, k = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i impossible range transitions.\n", num_items);
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ rt = item->item;
+ printf("%s\n", (tmp = apol_range_trans_render(policy, rt)));
+ free(tmp);
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ rt = item->item;
+ printf("%s\n", (tmp = apol_range_trans_render(policy, rt)));
+ free(tmp);
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/imp_range_trans.h b/sechecker/modules/imp_range_trans.h
new file mode 100644
index 0000000..04ceba0
--- /dev/null
+++ b/sechecker/modules/imp_range_trans.h
@@ -0,0 +1,52 @@
+/**
+ * @file
+ * Defines the interface for the impossible range_transition module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author: David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IMP_RANGE_TRANS
+#define IMP_RANGE_TRANS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/user-query.h>
+#include <apol/range_trans-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/domain-trans-analysis.h>
+#include <apol/policy-query.h>
+
+ int imp_range_trans_register(sechk_lib_t * lib);
+ int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IMP_RANGE_TRANS */
diff --git a/sechecker/modules/inc_dom_trans.c b/sechecker/modules/inc_dom_trans.c
new file mode 100644
index 0000000..fe6957d
--- /dev/null
+++ b/sechecker/modules/inc_dom_trans.c
@@ -0,0 +1,913 @@
+/**
+ * @file
+ * Defines the interface for the incomplete domain transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_dom_trans.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "inc_dom_trans";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int inc_dom_trans_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with partial transition permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds potential domain transitions missing key permissions. A valid\n"
+ "domain transition requires the following.\n"
+ "\n"
+ " 1) the starting domain can transition to the end domain for class process\n"
+ " 2) the end domain has some type as an entrypoint\n"
+ " 3) the starting domain can execute that extrypoint type\n"
+ " 4) (optional) a type transition rules specifying these three types\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ /* Dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid paramaters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* wrapper for apol_domain_trans_result_destroy() */
+void dtr_free_wrap(void *x)
+{
+ apol_domain_trans_result_destroy((apol_domain_trans_result_t **) & x);
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. */
+int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL, *tmp_item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j, k, retv;
+ sechk_module_t *mod_ptr = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ sechk_result_t *find_domains_res = NULL;
+ apol_domain_trans_analysis_t *domain_trans = NULL;
+ apol_vector_t *domain_vector = NULL, *role_vector = NULL, *user_vector = NULL, *rbac_vector = NULL;
+ apol_vector_t *domain_trans_vector = NULL, *role_allow_vector = NULL;
+ apol_user_query_t *user_query = NULL;
+ apol_role_query_t *start_role_query = NULL, *end_role_query = NULL;
+ apol_role_trans_query_t *role_trans_query = NULL;
+ apol_role_allow_query_t *role_allow_query = NULL;
+ char *buff = NULL;
+ int buff_sz, error = 0;
+ const qpol_type_t *domain = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *domain_name = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = EINVAL;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ res->item_type = SECHK_ITEM_DTR;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (apol_policy_build_domain_trans_table(policy) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to build domain transition table");
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(domain_trans = apol_domain_trans_analysis_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(user_query = apol_user_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(role_trans_query = apol_role_trans_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(role_allow_query = apol_role_allow_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(start_role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(end_role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib);
+ if (!run_fn) {
+ error = errno;
+ goto inc_dom_trans_run_fail;
+ }
+
+ retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL);
+ if (retv) {
+ error = errno;
+ ERR(policy, "%s", "Unable to find module find_domains");
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results from module find_domains");
+ goto inc_dom_trans_run_fail;
+ }
+
+ domain_vector = (apol_vector_t *) find_domains_res->items;
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ tmp_item = apol_vector_get_element(domain_vector, i);
+ domain = tmp_item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+ apol_domain_trans_analysis_set_start_type(policy, domain_trans, domain_name);
+ apol_domain_trans_analysis_set_direction(policy, domain_trans, APOL_DOMAIN_TRANS_DIRECTION_FORWARD);
+ apol_domain_trans_analysis_set_valid(policy, domain_trans, APOL_DOMAIN_TRANS_SEARCH_BOTH);
+ apol_domain_trans_analysis_do(policy, domain_trans, &domain_trans_vector);
+
+ for (j = 0; j < apol_vector_get_size(domain_trans_vector); j++) {
+ apol_domain_trans_result_t *dtr = NULL;
+ const qpol_type_t *start;
+ const qpol_type_t *ep;
+ const qpol_type_t *end;
+ const char *start_name;
+ const char *end_name;
+ const char *ep_name;
+ int result;
+ bool ok;
+
+ ok = false;
+ dtr = apol_vector_get_element(domain_trans_vector, j);
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ result = apol_domain_trans_table_verify_trans(policy, start, ep, end);
+ if (!result) {
+ apol_vector_t *start_role_vector, *end_role_vector, *common_role_vector;
+ apol_role_query_set_type(policy, start_role_query, start_name);
+ apol_role_get_by_query(policy, start_role_query, &start_role_vector);
+ apol_role_query_set_type(policy, end_role_query, end_name);
+ apol_role_get_by_query(policy, end_role_query, &end_role_vector);
+ if (!apol_vector_get_size(start_role_vector) || !apol_vector_get_size(end_role_vector)) {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!apol_vector_get_size(start_role_vector)) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need role for %s", start_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ if (!apol_vector_get_size(end_role_vector)) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need role for %s", end_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ item = NULL;
+ //if one of the domains has no roles continue; no more can be determined
+ apol_vector_destroy(&start_role_vector);
+ apol_vector_destroy(&end_role_vector);
+ continue;
+ }
+ common_role_vector =
+ apol_vector_create_from_intersection(start_role_vector, end_role_vector, NULL, NULL);
+ const char *role_name = NULL;
+ if (apol_vector_get_size(common_role_vector)) {
+ for (int k = 0; k < apol_vector_get_size(common_role_vector); k++) {
+ const qpol_role_t *common_role;
+
+ common_role = apol_vector_get_element(common_role_vector, k);
+ qpol_role_get_name(q, common_role, &role_name);
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &user_vector);
+ if (apol_vector_get_size(user_vector)) {
+ ok = true;
+ apol_vector_destroy(&user_vector);
+ break;
+ }
+ apol_vector_destroy(&user_vector);
+ }
+ if (!ok) {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need user for role %s", role_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item = NULL;
+ }
+ } else {
+ apol_vector_t *role_trans_vector;
+ bool need_ra = 0, need_user = 0;
+ char *rastring = NULL, *userstring = NULL;
+ apol_role_trans_query_set_target(policy, role_trans_query, ep_name, 1);
+ apol_role_trans_get_by_query(policy, role_trans_query, &role_trans_vector);
+ const char *source_role_name = NULL, *default_role_name = NULL;
+ for (k = 0; k < apol_vector_get_size(role_trans_vector); k++) {
+ qpol_role_trans_t *role_trans;
+ const qpol_role_t *source_role;
+ const qpol_role_t *default_role;
+ int index;
+
+ role_trans = apol_vector_get_element(role_trans_vector, k);
+ qpol_role_trans_get_source_role(q, role_trans, &source_role);
+ qpol_role_trans_get_default_role(q, role_trans, &default_role);
+ if ((apol_vector_get_index(start_role_vector, source_role, NULL, NULL, &index) == 0)
+ && (apol_vector_get_index(end_role_vector, default_role, NULL, NULL, &index) ==
+ 0)) {
+ apol_vector_t *source_role_user, *default_role_user, *common_role_user;
+
+ qpol_role_get_name(q, source_role, &source_role_name);
+ qpol_role_get_name(q, default_role, &default_role_name);
+ apol_role_allow_query_set_source(policy, role_allow_query,
+ source_role_name);
+ apol_role_allow_query_set_target(policy, role_allow_query,
+ default_role_name);
+ apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector);
+
+ apol_user_query_set_role(policy, user_query, source_role_name);
+ apol_user_get_by_query(policy, user_query, &source_role_user);
+ apol_user_query_set_role(policy, user_query, default_role_name);
+ apol_user_get_by_query(policy, user_query, &default_role_user);
+
+ common_role_user =
+ apol_vector_create_from_intersection(source_role_user,
+ default_role_user, NULL, NULL);
+ apol_vector_destroy(&source_role_user);
+ apol_vector_destroy(&default_role_user);
+ if (apol_vector_get_size(role_allow_vector) &&
+ apol_vector_get_size(common_role_user)) {
+ ok = true;
+ apol_vector_destroy(&role_allow_vector);
+ apol_vector_destroy(&common_role_user);
+ break;
+ }
+ if (!apol_vector_get_size(role_allow_vector)) {
+ // need role allow;
+ asprintf(&rastring, "allow %s %s;", source_role_name,
+ default_role_name);
+ if (!rastring) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_allow_vector);
+ if (!apol_vector_get_size(common_role_user)) {
+ // need user;
+ asprintf(&userstring, "need user with roles %s and %s",
+ source_role_name, default_role_name);
+ if (!userstring) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&common_role_user);
+ }
+ }
+ apol_vector_destroy(&role_trans_vector);
+ if (!ok) {
+ if (!need_ra && !need_user) {
+ const qpol_role_t *source_role =
+ apol_vector_get_element(start_role_vector, 0);
+ const qpol_role_t *default_role =
+ apol_vector_get_element(end_role_vector, 0);
+ qpol_role_get_name(q, source_role, &source_role_name);
+ qpol_role_get_name(q, default_role, &default_role_name);
+ // need role_transition
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)
+ apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "role_transition %s %s %s;", source_role_name,
+ ep_name, default_role_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item = NULL;
+ } else {
+ //create item
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)
+ apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (need_ra) {
+ //create proof w/ text rastring
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ proof->text = rastring;
+ rastring = NULL;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ if (need_user) {
+ //create proof w/ text userstring
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ proof->text = userstring;
+ userstring = NULL;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ item = NULL;
+ }
+ }
+ }
+ apol_vector_destroy(&start_role_vector);
+ apol_vector_destroy(&end_role_vector);
+ apol_vector_destroy(&common_role_vector);
+ } else {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz =
+ 10 + strlen("allow : process transition;") + strlen(start_name) + strlen(end_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : process transition;", start_name, end_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_EXEC) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow : file execute;") + strlen(start_name) + strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : file execute;", start_name, ep_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow : file entrypoint;") + strlen(end_name) + strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : file entrypoint;", end_name, ep_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_TYPE_TRANS) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz =
+ 10 + strlen("type_transition :process ;") + strlen(start_name) + strlen(end_name) +
+ strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "type_transition %s %s : process %s;", start_name, ep_name,
+ end_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_SETEXEC) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow self : process setexec;") + strlen(start_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s self : process setexec;", start_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ }
+ }
+ apol_vector_destroy(&domain_trans_vector);
+ }
+
+ mod->result = res;
+ apol_domain_trans_analysis_destroy(&domain_trans);
+ apol_user_query_destroy(&user_query);
+ apol_role_trans_query_destroy(&role_trans_query);
+ apol_role_query_destroy(&start_role_query);
+ apol_role_query_destroy(&end_role_query);
+ apol_role_allow_query_destroy(&role_allow_query);
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_dom_trans_run_fail:
+ sechk_item_free(item);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&domain_trans_vector);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i incomplete transitions.\n", num_items);
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ /*
+ * printf("\nStart Type\t\tEntrypoint\t\tEnd Type\t\tMissing Rules\n");
+ * printf("----------\t\t----------\t\t--------\t\t-------------\n");
+ */
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ const qpol_type_t *start;
+ const qpol_type_t *end;
+ const qpol_type_t *ep;
+ const char *start_name, *end_name, *ep_name;
+ apol_domain_trans_result_t *dtr;
+
+ item = apol_vector_get_element(mod->result->items, i);
+ dtr = item->item;
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ printf("%s -> %s\tentrypoint: %s\n", start_name, end_name, ep_name);
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type) */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ const qpol_type_t *start;
+ const qpol_type_t *end;
+ const qpol_type_t *ep;
+ const char *start_name, *end_name, *ep_name;
+ apol_domain_trans_result_t *dtr;
+
+ item = apol_vector_get_element(mod->result->items, i);
+ dtr = item->item;
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ printf("%s -> %s\tentrypoint: %s\n\tMissing:\n", start_name, end_name, ep_name);
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ sechk_proof_t *proof;
+
+ proof = apol_vector_get_element(item->proof, j);
+ if (proof) {
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_dom_trans.h b/sechecker/modules/inc_dom_trans.h
new file mode 100644
index 0000000..02dffbf
--- /dev/null
+++ b/sechecker/modules/inc_dom_trans.h
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * Defines the interface for the incomplete domain transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_DOM_TRANS
+#define INC_DOM_TRANS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/domain-trans-analysis.h>
+#include <apol/user-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/role-query.h>
+
+#define SECHK_INC_DOM_TRANS_HAS_TT 0x08
+#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04
+#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02
+#define SECHK_INC_DOM_TRANS_HAS_EP 0x01
+#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC)
+
+ int inc_dom_trans_register(sechk_lib_t * lib);
+ int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/inc_mount.c b/sechecker/modules/inc_mount.c
new file mode 100644
index 0000000..4e9f8b1
--- /dev/null
+++ b/sechecker/modules/inc_mount.c
@@ -0,0 +1,520 @@
+/**
+ * @file
+ * Implementation of the incomplete mount permissions module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_mount.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "inc_mount";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int inc_mount_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "no library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with partial mount permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds domains that have incomplete mount permissions.\n"
+ "In order for a mount operation to be allowed by the policy the following rules\n"
+ "must be present: \n"
+ "\n"
+ " 1) allow somedomain_d sometype_t : filesystem { mount };\n"
+ " 2) allow somedomain_d sometype_t : dir { mounton };\n"
+ "\n" "This module finds domains that have only one of the rules listed above.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+
+int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j;
+ bool both = false, add_proof = false;
+ int error = 0;
+ char *tmp = NULL;
+ apol_vector_t *mount_vector;
+ apol_vector_t *mounton_vector;
+ apol_avrule_query_t *mount_avrule_query = NULL;
+ apol_avrule_query_t *mounton_avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ if (!(mount_avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ if (!(mounton_avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ /* Get avrules for filesystem mount */
+ apol_avrule_query_set_rules(policy, mount_avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_append_class(policy, mount_avrule_query, "filesystem");
+ apol_avrule_query_append_perm(policy, mount_avrule_query, "mount");
+ apol_avrule_get_by_query(policy, mount_avrule_query, &mount_vector);
+
+ /* Get avrules for dir mounton */
+ apol_avrule_query_set_rules(policy, mounton_avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_append_class(policy, mounton_avrule_query, "dir");
+ apol_avrule_query_append_perm(policy, mounton_avrule_query, "mounton");
+ apol_avrule_get_by_query(policy, mounton_avrule_query, &mounton_vector);
+
+ for (i = 0; i < apol_vector_get_size(mount_vector); i++) {
+ const qpol_avrule_t *mount_rule;
+ const qpol_type_t *mount_source;
+ const qpol_type_t *mount_target;
+ const char *mount_source_name, *mount_target_name;
+
+ both = false;
+ add_proof = true;
+ mount_rule = apol_vector_get_element(mount_vector, i);
+ qpol_avrule_get_source_type(q, mount_rule, &mount_source);
+ qpol_avrule_get_target_type(q, mount_rule, &mount_target);
+ qpol_type_get_name(q, mount_source, &mount_source_name);
+ qpol_type_get_name(q, mount_target, &mount_target_name);
+
+ for (j = 0; j < apol_vector_get_size(mounton_vector); j++) {
+ const qpol_avrule_t *mounton_rule;
+ const qpol_type_t *mounton_source;
+ const qpol_type_t *mounton_target;
+ const char *mounton_source_name, *mounton_target_name;
+
+ mounton_rule = apol_vector_get_element(mounton_vector, j);
+ qpol_avrule_get_source_type(q, mounton_rule, &mounton_source);
+ qpol_avrule_get_target_type(q, mounton_rule, &mounton_target);
+ qpol_type_get_name(q, mounton_source, &mounton_source_name);
+ qpol_type_get_name(q, mounton_target, &mounton_target_name);
+
+ /* Check to see if they match */
+ if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name))
+ both = true;
+ }
+ if (!both) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)mount_rule;
+ tmp = apol_avrule_render(policy, mount_rule);
+ asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : dir mounton ;\n",
+ tmp, mount_source_name, mount_target_name);
+ free(tmp);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(mount_source_name, res_type_name) || !strcmp(mount_target_name, res_type_name))
+ add_proof = false;
+ }
+ if (add_proof) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item->item = (void *)mount_source;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ sechk_proof_free(proof);
+ proof = NULL;
+ }
+ }
+
+ for (i = 0; i < apol_vector_get_size(mounton_vector); i++) {
+ const qpol_avrule_t *mounton_rule;
+ const qpol_type_t *mounton_source;
+ const qpol_type_t *mounton_target;
+ const char *mounton_source_name, *mounton_target_name;
+
+ both = false;
+ add_proof = true;
+ mounton_rule = apol_vector_get_element(mounton_vector, i);
+ qpol_avrule_get_source_type(q, mounton_rule, &mounton_source);
+ qpol_avrule_get_target_type(q, mounton_rule, &mounton_target);
+ qpol_type_get_name(q, mounton_source, &mounton_source_name);
+ qpol_type_get_name(q, mounton_target, &mounton_target_name);
+
+ for (j = 0; j < apol_vector_get_size(mount_vector); j++) {
+ const qpol_avrule_t *mount_rule;
+ const qpol_type_t *mount_source;
+ const qpol_type_t *mount_target;
+ const char *mount_source_name, *mount_target_name;
+
+ mount_rule = apol_vector_get_element(mount_vector, j);
+ qpol_avrule_get_source_type(q, mount_rule, &mount_source);
+ qpol_avrule_get_target_type(q, mount_rule, &mount_target);
+ qpol_type_get_name(q, mount_source, &mount_source_name);
+ qpol_type_get_name(q, mount_target, &mount_target_name);
+
+ if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name))
+ both = true;
+ }
+ if (!both) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)mounton_rule;
+ tmp = apol_avrule_render(policy, mounton_rule);
+ asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : filesystem mount ;\n",
+ tmp, mounton_source_name, mounton_target_name);
+ free(tmp);
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(mounton_source_name, res_type_name) || !strcmp(mounton_target_name, res_type_name))
+ add_proof = false;
+ }
+ if (add_proof) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item->item = (void *)mounton_source;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ sechk_proof_free(proof);
+ proof = NULL;
+ }
+ }
+ apol_vector_destroy(&mount_vector);
+ apol_vector_destroy(&mounton_vector);
+
+ mod->result = res;
+ apol_avrule_query_destroy(&mount_avrule_query);
+ apol_avrule_query_destroy(&mounton_avrule_query);
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_mount_run_fail:
+ apol_vector_destroy(&mount_vector);
+ apol_vector_destroy(&mounton_vector);
+ apol_avrule_query_destroy(&mount_avrule_query);
+ apol_avrule_query_destroy(&mounton_avrule_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(tmp);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k, l, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with the severity.
+ * Each proof element is then displayed in an indented list one per
+ * line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_mount.h b/sechecker/modules/inc_mount.h
new file mode 100644
index 0000000..18d5179
--- /dev/null
+++ b/sechecker/modules/inc_mount.h
@@ -0,0 +1,54 @@
+/**
+ * @file
+ * Defines the interface for the incomplete mount permissions module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_MOUNT
+#define INC_MOUNT
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+#define SECHK_MOUNT_ONLY_MOUNT 0x01
+#define SECHK_MOUNT_ONLY_MOUNTON 0x02
+
+/* Module functions:
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int inc_mount_register(sechk_lib_t * lib);
+ int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/inc_net_access.c b/sechecker/modules/inc_net_access.c
new file mode 100644
index 0000000..a8903ea
--- /dev/null
+++ b/sechecker/modules/inc_net_access.c
@@ -0,0 +1,1852 @@
+/**
+ * @file
+ * Defines the interface for the incomplete network access module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_net_access.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "inc_net_access";
+
+/* The register function registers all of a module's functions
+ * with the library. You should not need to edit this function
+ * unless you are adding additional functions you need other modules
+ * to call. See the note at the bottom of this function to do so. */
+int inc_net_access_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "finds network domains with inadequate permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all network domains in a policy which do not have the \n"
+ "required permissions needed to facilitate network communication. For network\n"
+ "domains to communicate, the following conditions must be true:\n"
+ " 1) the domain must have read or receive permissions on a socket of the same\n"
+ " type\n"
+ " 2) the domain must have send or receive permissions on an IPsec association\n"
+ " (see find_assoc_types)\n"
+ " 3) the domain must have send or receive permissions on netif objects for a\n"
+ " netif type (see find_netif_types)\n"
+ " 4) the domain must have send or receive permissions on node objects for a\n"
+ " node type (see find_node_types)\n"
+ " 5) the domain must have send or receive permissions on port objects for a\n"
+ " port type (see find_port_types)\n";
+ mod->opt_description =
+ " Module requirements:\n"
+ " none\n" " Module dependencies:\n" " find_net_domains\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign dependencies */
+ if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_net_domains")) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* This set of defines represents individual permission bits for
+ * the permissions needed to have complete network access */
+/* allow domain self : sock_file {read write getattr}; */
+#define PERM_SELF_SOCK_FILE_READ 0x00000001
+#define PERM_SELF_SOCK_FILE_WRITE 0x00000002
+#define PERM_SELF_SOCK_FILE_GETATTR 0x00000004
+/* allow domain self : tcp_socket {create read write}; */
+#define PERM_SELF_TCP_SOC_READ 0x00000008
+#define PERM_SELF_TCP_SOC_WRITE 0x00000010
+#define PERM_SELF_TCP_SOC_CREATE 0x00000020
+/* allow domain self : udp_socket {create read write}; */
+#define PERM_SELF_UDP_SOC_READ 0x00000040
+#define PERM_SELF_UDP_SOC_WRITE 0x00000080
+#define PERM_SELF_UDP_SOC_CREATE 0x00000100
+/* allow domain if_type : netif {tcp_send udp_send tcp_recv tcp_send}; */
+#define PERM_NETIF_TCP_SEND 0x00000200
+#define PERM_NETIF_UDP_SEND 0x00000400
+#define PERM_NETIF_TCP_RECV 0x00000800
+#define PERM_NETIF_UDP_RECV 0x00001000
+/* allow domain node_type : node {tcp_send udp_send tcp_recv tcp_send}; */
+#define PERM_NODE_TCP_SEND 0x00002000
+#define PERM_NODE_UDP_SEND 0x00004000
+#define PERM_NODE_TCP_RECV 0x00008000
+#define PERM_NODE_UDP_RECV 0x00010000
+/* allow domain port_type : tcp_socket {send_msg recv_msg}; */
+#define PERM_PORT_TCP_SEND 0x00020000
+#define PERM_PORT_TCP_RECV 0x00040000
+/* allow domain port_type : udp_socket {send_msg recv_msg}; */
+#define PERM_PORT_UDP_SEND 0x00080000
+#define PERM_PORT_UDP_RECV 0x00100000
+/* allow domain assoc_type : association {sendto recvfrom}; */
+#define PERM_ASSOC_SEND 0x00200000
+#define PERM_ASSOC_RECV 0x00400000
+
+/* this set of defines represents masks for individual rules */
+#define RULE_TCP_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_UDPs_SOCK_FILE (PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_UDPr_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_TCP_SELF_SOC (PERM_SELF_TCP_SOC_READ|PERM_SELF_TCP_SOC_WRITE|PERM_SELF_TCP_SOC_CREATE)
+#define RULE_UDPs_SELF_SOC (PERM_SELF_UDP_SOC_WRITE|PERM_SELF_UDP_SOC_CREATE)
+#define RULE_UDPr_SELF_SOC (PERM_SELF_UDP_SOC_READ|PERM_SELF_UDP_SOC_CREATE)
+#define RULE_TCP_NETIF (PERM_NETIF_TCP_SEND|PERM_NETIF_TCP_RECV)
+#define RULE_UDPs_NETIF (PERM_NETIF_UDP_SEND)
+#define RULE_UDPr_NETIF (PERM_NETIF_UDP_RECV)
+#define RULE_TCP_NODE (PERM_NODE_TCP_SEND|PERM_NODE_TCP_RECV)
+#define RULE_UDPs_NODE (PERM_NODE_UDP_SEND)
+#define RULE_UDPr_NODE (PERM_NODE_UDP_RECV)
+#define RULE_TCP_PORT (PERM_PORT_TCP_SEND|PERM_PORT_TCP_RECV)
+#define RULE_UDPs_PORT (PERM_PORT_UDP_SEND)
+#define RULE_UDPr_PORT (PERM_PORT_UDP_RECV)
+#define RULE_TCP_ASSOC (PERM_ASSOC_SEND|PERM_ASSOC_RECV)
+#define RULE_UDPs_ASSOC (PERM_ASSOC_SEND)
+#define RULE_UDPr_ASSOC (PERM_ASSOC_RECV)
+
+/* This set of defines represents mask sets to represent access types */
+#define UDP_RECV_PERM_SET (RULE_UDPr_SOCK_FILE|RULE_UDPr_SELF_SOC|RULE_UDPr_NETIF|RULE_UDPr_NODE|RULE_UDPr_PORT|RULE_UDPr_ASSOC)
+#define UDP_SEND_PERM_SET (RULE_UDPs_SOCK_FILE|RULE_UDPs_SELF_SOC|RULE_UDPs_NETIF|RULE_UDPs_NODE|RULE_UDPs_PORT|RULE_UDPs_ASSOC)
+#define TCP_FULL_PERM_SET (RULE_TCP_SOCK_FILE|RULE_TCP_SELF_SOC|RULE_TCP_NETIF|RULE_TCP_NODE|RULE_TCP_PORT|RULE_TCP_ASSOC)
+#define COMMON_ACCESS_SET (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR|PERM_ASSOC_SEND|PERM_ASSOC_RECV)
+
+typedef struct net_state
+{
+ uint32_t perms;
+ apol_vector_t *netifs;
+ apol_vector_t *nodes;
+ apol_vector_t *tcpsocs;
+ apol_vector_t *udpsocs;
+ apol_vector_t *assocs;
+} net_state_t;
+
+typedef struct name_perm
+{
+ const char *name; /* will be from policy do not free */
+ uint32_t perms;
+} name_perm_t;
+
+static void net_state_destroy(net_state_t ** n)
+{
+ if (!n || !(*n))
+ return;
+
+ apol_vector_destroy(&((*n)->netifs));
+ apol_vector_destroy(&((*n)->nodes));
+ apol_vector_destroy(&((*n)->tcpsocs));
+ apol_vector_destroy(&((*n)->udpsocs));
+ apol_vector_destroy(&((*n)->assocs));
+ free(*n);
+ *n = NULL;
+}
+
+static net_state_t *net_state_create(void)
+{
+ net_state_t *n = NULL;
+
+ n = calloc(1, sizeof(*n));
+ n->netifs = apol_vector_create(free);
+ n->nodes = apol_vector_create(free);
+ n->tcpsocs = apol_vector_create(free);
+ n->udpsocs = apol_vector_create(free);
+ n->assocs = apol_vector_create(free);
+
+ return n;
+}
+
+static int name_perm_comp(const void *a, const void *b, void *arg __attribute__ ((unused)))
+{
+ const name_perm_t *x = a;
+ const name_perm_t *y = b;
+
+ return strcmp(x->name, y->name);
+}
+
+static name_perm_t *name_perm_create(const char *name)
+{
+ name_perm_t *np = NULL;
+
+ np = calloc(1, sizeof(*np));
+ np->name = name;
+
+ return np;
+}
+
+static int name_perm_vector_has_incomplete_perms(apol_vector_t * v, uint32_t mask)
+{
+ uint32_t tmp;
+ name_perm_t *np = NULL;
+ size_t i = 0;
+
+ if (!apol_vector_get_size(v))
+ return 1;
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ np = apol_vector_get_element(v, i);
+ tmp = np->perms & mask;
+ if (tmp != mask)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void name_perm_vector_add_perm(apol_vector_t * v, const char *name, uint32_t perm)
+{
+ name_perm_t *np = NULL;
+ size_t i = 0;
+ int retv;
+
+ np = name_perm_create(name);
+ retv = apol_vector_get_index(v, np, name_perm_comp, NULL, &i);
+ if (retv) {
+ np->perms = perm;
+ apol_vector_append(v, (void *)np);
+ } else {
+ free(np); /* already exists free temp one */
+ np = apol_vector_get_element(v, i);
+ np->perms |= perm;
+ }
+}
+
+static char *generate_tcp_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == TCP_FULL_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has TCP access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete TCP access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SOCK_FILE;
+ missing = attempt ^ RULE_TCP_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SELF_SOC;
+ missing = attempt ^ RULE_TCP_SELF_SOC;
+ asprintf(&tmp, "allow %s self : tcp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_TCP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_TCP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_TCP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_TCP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_TCP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_TCP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_TCP_NETIF;
+ missing = attempt ^ RULE_TCP_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (attempt & PERM_NETIF_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (missing & PERM_NETIF_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { tcp_send tcp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_TCP_NODE;
+ missing = attempt ^ RULE_TCP_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (attempt & PERM_NODE_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (missing & PERM_NODE_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { tcp_send tcp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->tcpsocs); i++) {
+ np = apol_vector_get_element(state->tcpsocs, i);
+ attempt = state->perms & RULE_TCP_PORT;
+ missing = attempt ^ RULE_TCP_PORT;
+ asprintf(&tmp, "allow %s %s : tcp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (attempt & PERM_PORT_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (missing & PERM_PORT_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->tcpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : tcp_socket { send_msg recv_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_TCP_ASSOC;
+ missing = attempt ^ RULE_TCP_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (missing & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto recvfrom };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_udp_send_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == UDP_SEND_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has UDP send access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP send access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPs_SOCK_FILE;
+ missing = attempt ^ RULE_UDPs_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPs_SELF_SOC;
+ missing = attempt ^ RULE_UDPs_SELF_SOC;
+ asprintf(&tmp, "allow %s self : udp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_UDP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_UDP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_UDPs_NETIF;
+ missing = attempt ^ RULE_UDPs_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_send };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_UDPs_NODE;
+ missing = attempt ^ RULE_UDPs_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_send };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) {
+ np = apol_vector_get_element(state->udpsocs, i);
+ attempt = state->perms & RULE_UDPs_PORT;
+ missing = attempt ^ RULE_UDPs_PORT;
+ asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->udpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { send_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_UDPs_ASSOC;
+ missing = attempt ^ RULE_UDPs_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_udp_recv_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == UDP_RECV_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has UDP receive access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP receive access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPr_SOCK_FILE;
+ missing = attempt ^ RULE_UDPr_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPr_SELF_SOC;
+ missing = attempt ^ RULE_UDPr_SELF_SOC;
+ asprintf(&tmp, "allow %s self : udp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_UDP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_UDP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_UDPr_NETIF;
+ missing = attempt ^ RULE_UDPr_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_UDPr_NODE;
+ missing = attempt ^ RULE_UDPr_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) {
+ np = apol_vector_get_element(state->udpsocs, i);
+ attempt = state->perms & RULE_UDPr_PORT;
+ missing = attempt ^ RULE_UDPr_PORT;
+ asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->udpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { recv_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_UDPr_ASSOC;
+ missing = attempt ^ RULE_UDPr_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { recvfrom };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_common_only_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0;
+ name_perm_t *np = NULL;
+
+ if (apol_str_append
+ (&text, &text_sz,
+ "Domain has incomplete network access.\n\tDomain has no protocol specific permissions only the following:"))
+ goto err;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_TCP_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL, *tmp_item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *net_domain_res = NULL;
+ sechk_name_value_t *dep = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ size_t i = 0, j = 0;
+ int error = 0;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_vector_t *avrule_vector = NULL, *net_domain_vector = NULL;
+ const qpol_type_t *net_domain = NULL, *tmp_type = NULL;
+ const char *net_domain_name = NULL, *tgt_name = NULL;
+ char *perm_name = NULL;
+ const qpol_avrule_t *rule = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ net_state_t *state = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_net_access_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_net_access_run_fail;
+ }
+
+ /* run dependencies */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ net_domain_res = sechk_lib_get_module_result("find_net_domains", mod->parent_lib);
+ if (!net_domain_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_net_domains");
+ goto inc_net_access_run_fail;
+ }
+ net_domain_vector = (apol_vector_t *) net_domain_res->items;
+
+ avrule_query = apol_avrule_query_create();
+ if (!avrule_query) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+
+ for (i = 0; i < apol_vector_get_size(net_domain_vector); i++) {
+ tmp_item = apol_vector_get_element(net_domain_vector, i);
+ net_domain = tmp_item->item;
+ qpol_type_get_name(q, net_domain, &net_domain_name);
+ state = net_state_create();
+
+ /* find any self sock_file perms */
+ apol_avrule_query_set_source(policy, avrule_query, net_domain_name, 1);
+ apol_avrule_query_set_target(policy, avrule_query, net_domain_name, 1);
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "sock_file");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_SOCK_FILE_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_SOCK_FILE_WRITE;
+ } else if (!strcmp(perm_name, "getattr")) {
+ state->perms |= PERM_SELF_SOCK_FILE_GETATTR;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any self tcp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "tcp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_TCP_SOC_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_TCP_SOC_WRITE;
+ } else if (!strcmp(perm_name, "create")) {
+ state->perms |= PERM_SELF_TCP_SOC_CREATE;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any self udp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "udp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_UDP_SOC_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_UDP_SOC_WRITE;
+ } else if (!strcmp(perm_name, "create")) {
+ state->perms |= PERM_SELF_UDP_SOC_CREATE;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any if_t netif perms */
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "netif");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "tcp_send")) {
+ state->perms |= PERM_NETIF_TCP_SEND;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_SEND);
+ } else if (!strcmp(perm_name, "tcp_recv")) {
+ state->perms |= PERM_NETIF_TCP_RECV;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_RECV);
+ } else if (!strcmp(perm_name, "udp_send")) {
+ state->perms |= PERM_NETIF_UDP_SEND;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_SEND);
+ } else if (!strcmp(perm_name, "udp_recv")) {
+ state->perms |= PERM_NETIF_UDP_RECV;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any node_t node perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "node");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "tcp_send")) {
+ state->perms |= PERM_NODE_TCP_SEND;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_SEND);
+ } else if (!strcmp(perm_name, "tcp_recv")) {
+ state->perms |= PERM_NODE_TCP_RECV;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_RECV);
+ } else if (!strcmp(perm_name, "udp_send")) {
+ state->perms |= PERM_NODE_UDP_SEND;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_SEND);
+ } else if (!strcmp(perm_name, "udp_recv")) {
+ state->perms |= PERM_NODE_UDP_RECV;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any port_t tcp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "tcp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ /* skip self */
+ if (!strcmp(net_domain_name, tgt_name))
+ continue;
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "send_msg")) {
+ state->perms |= PERM_PORT_TCP_SEND;
+ name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_SEND);
+ } else if (!strcmp(perm_name, "recv_msg")) {
+ state->perms |= PERM_PORT_TCP_RECV;
+ name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any port_t udp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "udp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ /* skip self */
+ if (!strcmp(net_domain_name, tgt_name))
+ continue;
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "send_msg")) {
+ state->perms |= PERM_PORT_UDP_SEND;
+ name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_SEND);
+ } else if (!strcmp(perm_name, "recv_msg")) {
+ state->perms |= PERM_PORT_UDP_RECV;
+ name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any assoc_t association perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "association");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "sendto")) {
+ state->perms |= PERM_ASSOC_SEND;
+ name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_SEND);
+ } else if (!strcmp(perm_name, "recvfrom")) {
+ state->perms |= PERM_ASSOC_RECV;
+ name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* if has tcp perms check for missing ones */
+ if ((state->perms & ((~(COMMON_ACCESS_SET)) & (TCP_FULL_PERM_SET))) &&
+ ((state->perms & RULE_TCP_SOCK_FILE) != RULE_TCP_SOCK_FILE ||
+ (state->perms & RULE_TCP_SELF_SOC) != RULE_TCP_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_TCP_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_TCP_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->tcpsocs, RULE_TCP_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_TCP_ASSOC))) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_tcp_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has udp send perms check for missing perms */
+ if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_SEND_PERM_SET))) &&
+ ((state->perms & RULE_UDPs_SOCK_FILE) != RULE_UDPs_SOCK_FILE ||
+ (state->perms & RULE_UDPs_SELF_SOC) != RULE_UDPs_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPs_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPs_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPs_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPs_ASSOC))) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_udp_send_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has udp reveive perms check for missing perms */
+ if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_RECV_PERM_SET))) &&
+ ((state->perms & RULE_UDPr_SOCK_FILE) != RULE_UDPr_SOCK_FILE ||
+ (state->perms & RULE_UDPr_SELF_SOC) != RULE_UDPr_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPr_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPr_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPr_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPr_ASSOC))) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_udp_recv_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has only common access perms report that */
+ if (!(state->perms & (~(COMMON_ACCESS_SET)))) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_common_only_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+
+ if (item) {
+ if (apol_vector_append(res->items, (void *)item)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item = NULL;
+ }
+ net_state_destroy(&state);
+ }
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_net_access_run_fail:
+ apol_avrule_query_destroy(&avrule_query);
+ apol_vector_destroy(&avrule_vector);
+ qpol_iterator_destroy(&iter);
+ free(perm_name);
+ net_state_destroy(&state);
+ sechk_item_free(item);
+ sechk_proof_free(proof);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i network domains with insufficient permissions.\n", num_items);
+ }
+
+ /* Print current permissions then the permissions that are missing */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ i = 0;
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_net_access.h b/sechecker/modules/inc_net_access.h
new file mode 100644
index 0000000..746db40
--- /dev/null
+++ b/sechecker/modules/inc_net_access.h
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * Defines the interface for the incomplete network access module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_NET_ACCESS_H
+#define INC_NET_ACCESS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int inc_net_access_register(sechk_lib_t * lib);
+ int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_allow.c b/sechecker/modules/roles_wo_allow.c
new file mode 100644
index 0000000..3d55bc8
--- /dev/null
+++ b/sechecker/modules/roles_wo_allow.c
@@ -0,0 +1,387 @@
+/**
+ * @file
+ * Implementation of the roles without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_allow.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_allow";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_allow_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "roles with no roleallow rules";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles defined in the policy that are not used in any role\n"
+ "allow rules. It is not possible to transition to or from any role that does not\n" "have any role allow rules.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ apol_vector_t *role_allow_vector;
+ apol_role_allow_query_t *role_allow_query = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ if ((role_allow_query = apol_role_allow_query_create()) == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ apol_role_allow_query_set_source(policy, role_allow_query, role_name);
+ apol_role_allow_query_set_source_any(policy, role_allow_query, 1);
+ apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector);
+ if (apol_vector_get_size(role_allow_vector) > 0) {
+ apol_vector_destroy(&role_allow_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_allow_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ proof->text = strdup("Role has no allow.\n");
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ item->item = (void *)role;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&role_allow_vector);
+ apol_role_allow_query_destroy(&role_allow_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_allow_run_fail:
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&role_allow_vector);
+ apol_role_allow_query_destroy(&role_allow_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_role_t *role;
+ const char *role_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles do not appear in any allow rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_allow.h b/sechecker/modules/roles_wo_allow.h
new file mode 100644
index 0000000..c9dd44e
--- /dev/null
+++ b/sechecker/modules/roles_wo_allow.h
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * Defines the interface for the roles without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_ALLOW
+#define ROLES_WO_ALLOW
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/rbacrule-query.h>
+
+ int roles_wo_allow_register(sechk_lib_t * lib);
+ int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_types.c b/sechecker/modules/roles_wo_types.c
new file mode 100644
index 0000000..ed38580
--- /dev/null
+++ b/sechecker/modules/roles_wo_types.c
@@ -0,0 +1,330 @@
+/**
+ * @file
+ * Implementation of the roles without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "roles with no types";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles in the policy that have no types. A role with no types \n"
+ "cannot form a valid context.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Ivalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ qpol_iterator_t *type_iter = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Ivalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+ int at_end;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ qpol_role_get_type_iter(apol_policy_get_qpol(policy), role, &type_iter);
+ at_end = qpol_iterator_end(type_iter);
+ qpol_iterator_destroy(&type_iter);
+ if (!at_end)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ asprintf(&proof->text, "role %s has no types", role_name);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ item->item = (void *)role;
+ item->test_result = 1;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_role_t *role;
+ const char *role_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles have no associated types:\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_types.h b/sechecker/modules/roles_wo_types.h
new file mode 100644
index 0000000..1a241d0
--- /dev/null
+++ b/sechecker/modules/roles_wo_types.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the roles without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_TYPES
+#define ROLES_WO_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+
+ int roles_wo_types_register(sechk_lib_t * lib);
+ int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_users.c b/sechecker/modules/roles_wo_users.c
new file mode 100644
index 0000000..c590880
--- /dev/null
+++ b/sechecker/modules/roles_wo_users.c
@@ -0,0 +1,392 @@
+/**
+ * @file
+ * Defines the interface for the roles without users module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_users.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_users";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_users_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "roles not assigned to users";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles that are not assigned to users. If a role is not \n"
+ "assigned to a user it cannot form a valid context.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ apol_vector_t *user_vector;
+ apol_user_query_t *user_query = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+
+ if (!(user_query = apol_user_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve roles");
+ return -1;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &user_vector);
+ if (apol_vector_get_size(user_vector) > 0) {
+ apol_vector_destroy(&user_vector);
+ continue;
+ }
+ apol_vector_destroy(&user_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item->item = (void *)role;
+ item->test_result = 1;
+ proof->type = SECHK_ITEM_ROLE;
+ proof->text = strdup("This role is not assigned to any user.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_user_query_destroy(&user_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_users_run_fail:
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_user_query_destroy(&user_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ const qpol_role_t *role;
+ const char *role_name;
+ size_t i = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles are not associated with any users.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_users.h b/sechecker/modules/roles_wo_users.h
new file mode 100644
index 0000000..261bebb
--- /dev/null
+++ b/sechecker/modules/roles_wo_users.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the roles without users module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_USERS
+#define ROLES_WO_USERS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+#include <apol/role-query.h>
+
+/* Module functions:
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int roles_wo_users_register(sechk_lib_t * lib);
+ int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/spurious_audit.c b/sechecker/modules/spurious_audit.c
new file mode 100644
index 0000000..21698df
--- /dev/null
+++ b/sechecker/modules/spurious_audit.c
@@ -0,0 +1,778 @@
+/**
+ * @file
+ * Implementation of the spurious audit rule module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Ryan Jordan rjordan@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sechecker.h"
+#include "spurious_audit.h"
+#include <apol/policy-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "spurious_audit";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int spurious_audit_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "no library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s%s%s", "module unknown, \"", mod_name, "\"");
+ errno = ENOENT;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "audit rules with no effect";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds audit rules in the policy which do not affect the auditing of\n"
+ "the policy. This could happen in the following situations:\n"
+ "\n"
+ " 1) there is an allow rule with the same key and permissions for a dontaudit\n"
+ " rule\n"
+ " 2) there is an auditallow rule without an allow rule with the same key or\n"
+ " with permissions that do not appear in an allow rule with the same key.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error, rule_found;
+ apol_avrule_query_t *query = 0;
+ apol_vector_t *allow_rules = NULL, *auditallow_rules = NULL;
+ apol_vector_t *dontaudit_rules = NULL, *perm_vector1 = NULL;
+ apol_vector_t *perm_vector2 = NULL, *perm_intersection = NULL;
+ apol_vector_t *tmp_v = NULL;
+ size_t i, j, k, l, tmp_counter;
+ const qpol_avrule_t *rule1, *rule2;
+ const qpol_type_t *source, *target;
+ const qpol_class_t *object;
+ qpol_iterator_t *perm_iter1, *perm_iter2;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ char *string1, *string2, *tmp;
+ const char *src_name, *tgt_name, *obj_name, *perms;
+
+ error = rule_found = 0;
+ allow_rules = auditallow_rules = dontaudit_rules = perm_vector1 = perm_vector2 = perm_intersection = NULL;
+ rule1 = rule2 = 0;
+ source = target = NULL;
+ perm_iter1 = perm_iter2 = NULL;
+ string1 = string2 = tmp = NULL;
+ src_name = tgt_name = obj_name = perms = NULL;
+
+ if (!mod || !policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ res->item_type = SECHK_ITEM_AVRULE;
+
+ query = apol_avrule_query_create();
+ if (!query) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_AUDITALLOW);
+ if (apol_avrule_get_by_query(policy, query, &auditallow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_DONTAUDIT);
+ if (apol_avrule_get_by_query(policy, query, &dontaudit_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* First error case: Allow && Don't Audit */
+ for (i = 0; i < apol_vector_get_size(dontaudit_rules); i++) {
+ /* get first (DONT_AUDIT) rule */
+ rule1 = (qpol_avrule_t *) apol_vector_get_element(dontaudit_rules, i);
+ if (!rule1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* get source, target, object for Don't Audit rule */
+ if (qpol_avrule_get_source_type(q, rule1, &source)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_target_type(q, rule1, &target)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_object_class(q, rule1, &object)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* extract name strings from source, target, object */
+ if (qpol_type_get_name(q, source, &src_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_type_get_name(q, target, &tgt_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_class_get_name(q, object, &obj_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* configure Allow rule query to match above Don't Audit rule */
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, query, src_name, 1);
+ apol_avrule_query_set_target(policy, query, tgt_name, 1);
+ apol_avrule_query_append_class(policy, query, NULL);
+ apol_avrule_query_append_class(policy, query, obj_name);
+
+ /* get vector of matching ALLOW rules */
+ if (apol_avrule_get_by_query(policy, query, &allow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (apol_vector_get_size(allow_rules) != 0) {
+ /* Bad News: Allow && Don't Audit */
+ for (j = 0; j < apol_vector_get_size(allow_rules); j++) {
+ /* get second (Allow) rule */
+ rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j);
+ if (!rule2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* get permission iterators for both rules, and make vectors from them */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector2 = apol_vector_create_from_iter(perm_iter2, free);
+ if (!perm_vector2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* create intersection of permissions */
+ perm_intersection = apol_vector_create_from_intersection(perm_vector1,
+ perm_vector2, apol_str_strcmp, NULL);
+ if (!perm_intersection) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (apol_vector_get_size(perm_intersection) != 0) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = (void *)rule2; /* proof is the allow rule */
+ proof->type = SECHK_ITEM_AVRULE;
+ /* text will show the permissions that conflict */
+ tmp_counter = 0;
+ for (k = 0; k < apol_vector_get_size(perm_intersection); k++) {
+ apol_str_append(&(proof->text), &tmp_counter,
+ (char *)apol_vector_get_element(perm_intersection, k));
+ if (k != (apol_vector_get_size(perm_intersection) - 1))
+ apol_str_append(&(proof->text), &tmp_counter, ", ");
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ item->item = (void *)rule1; /* item is the dontaudit rule */
+ }
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+
+ } else {
+ /* these two rules don't overlap, no problem */
+ }
+ /* clean up */
+ rule2 = NULL;
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ }
+ apol_vector_destroy(&allow_rules);
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ if (item)
+ apol_vector_append(res->items, (void *)item);
+
+ item = NULL;
+ }
+ apol_vector_destroy(&allow_rules);
+ }
+ apol_vector_destroy(&dontaudit_rules);
+
+ /* Second error case: AuditAllow w/out Allow */
+ for (i = 0; i < apol_vector_get_size(auditallow_rules); i++) {
+ /* get first (AuditAllow) rule */
+ rule1 = (qpol_avrule_t *) apol_vector_get_element(auditallow_rules, i);
+ if (!rule1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ /* get first rule's source, target, object class */
+ if (qpol_avrule_get_source_type(q, rule1, &source)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_target_type(q, rule1, &target)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_object_class(q, rule1, &object)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ /* extract name strings from source, target, object */
+ if (qpol_type_get_name(q, source, &src_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_type_get_name(q, target, &tgt_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_class_get_name(q, object, &obj_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* configure ALLOW rule query to match above rule */
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, query, src_name, 1);
+ apol_avrule_query_set_target(policy, query, tgt_name, 1);
+ apol_avrule_query_append_class(policy, query, obj_name);
+
+ if (apol_avrule_get_by_query(policy, query, &allow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (!apol_vector_get_size(allow_rules)) {
+ /* No ALLOW rule for given AUDIT_ALLOW rule */
+
+ /* Make proof: missing allow rule */
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = NULL;
+ proof->type = SECHK_ITEM_AVRULE;
+
+ /* grab permisisons of auditallow rule, and make text */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ tmp_counter = 0;
+ for (j = 0; j < apol_vector_get_size(perm_vector1); j++) {
+ if (apol_str_append(&(proof->text), &tmp_counter, (char *)apol_vector_get_element(perm_vector1, j))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (j != (apol_vector_get_size(perm_vector1) - 1)) {
+ if (apol_str_append(&(proof->text), &tmp_counter, " ")) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&perm_vector1);
+ qpol_iterator_destroy(&perm_iter1);
+
+ /* Make item: inconsistent auditallow rule */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ item->item = (void *)rule1;
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+
+ /* Add item to test result */
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ if (item)
+ apol_vector_append(res->items, (void *)item);
+ item = NULL;
+ apol_vector_destroy(&allow_rules);
+ continue;
+ }
+
+ /* Here we have AuditAllow rule and Allow rule(s) with same key */
+ /* Checking to make sure they have the same permissions */
+
+ /* Make vector of AuditAllow permissions */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* Get permissions vector for Allow rule(s) */
+ for (j = 0; j < apol_vector_get_size(allow_rules); j++) {
+ /* get Allow rule */
+ rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j);
+ if (!rule2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (!perm_vector2) {
+ perm_vector2 = apol_vector_create(free);
+ if (!perm_vector2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+
+ /* concatenate permissions from this rule, check for errors, all in one go */
+ if (apol_vector_cat(perm_vector2, (tmp_v = apol_vector_create_from_iter(perm_iter2, NULL)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ apol_vector_destroy(&tmp_v);
+ goto spurious_audit_run_fail;
+ }
+ apol_vector_destroy(&tmp_v);
+ }
+
+ /* Find intersection of permission, put into a vector */
+ perm_intersection = apol_vector_create_from_intersection(perm_vector1, perm_vector2, apol_str_strcmp, NULL);
+
+ if (apol_vector_get_size(perm_intersection) != apol_vector_get_size(perm_vector1)) {
+ /* Auditallow rule audits things that are not allowed */
+
+ /* item for result is the AuditAllow rule */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));;
+ goto spurious_audit_run_fail;
+ }
+ }
+ item->item = (void *)rule1;
+ /* proof is the lack of Allow rule */
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = NULL;
+ proof->type = SECHK_ITEM_AVRULE;
+
+ /* the next series of if statements prints the following:
+ * missing: allow <src_name> <tgt_name> : <obj_name> { perms }; */
+ tmp_counter = 0;
+ for (j = 0; j < apol_vector_get_size(perm_vector1); j++) {
+ string1 = (char *)apol_vector_get_element(perm_vector1, j);
+ if (apol_vector_get_index(perm_intersection, (void *)string1, apol_str_strcmp, NULL, &l) < 0) {
+ if (apol_str_append(&(proof->text), &tmp_counter, string1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (apol_str_append(&(proof->text), &tmp_counter, " ")) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ string1 = NULL;
+ }
+
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+ proof = NULL;
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(res->items, (void *)item);
+ item = NULL;
+ }
+
+ /* clean up */
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ apol_vector_destroy(&allow_rules);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ }
+
+ apol_vector_destroy(&auditallow_rules);
+ apol_avrule_query_destroy(&query);
+
+ mod->result = res;
+
+ /* If module finds something that would be considered a fail
+ * on the policy return 1 here */
+ if (apol_vector_get_size(res->items) > 0)
+ return 1;
+
+ return 0;
+
+ spurious_audit_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ apol_vector_destroy(&allow_rules);
+ apol_vector_destroy(&auditallow_rules);
+ apol_vector_destroy(&dontaudit_rules);
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ apol_avrule_query_destroy(&query);
+ free(tmp);
+ tmp = NULL;
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0;
+ uint32_t ruletype;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ char *tmp;
+
+ if (!mod || !policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "%s%s%s", "module ", mod->name, "has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ i = apol_vector_get_size(mod->result->items);
+ printf("Found %zd rule%s.\n", i, (i == 1) ? "" : "s");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item)));
+ free(tmp);
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item)));
+
+ qpol_avrule_get_rule_type(q, (qpol_avrule_t *) item->item, &ruletype);
+ if (ruletype == QPOL_RULE_DONTAUDIT) {
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\tinconsistent: ");
+ printf("%s\n", apol_avrule_render(policy, (qpol_avrule_t *) proof->elem));
+ printf("\tinconsistent permissions:\n");
+ printf("\t%s\n", proof->text);
+ }
+ } else if (ruletype == QPOL_RULE_AUDITALLOW) {
+ printf("\tmissing: ");
+ printf("%s\n", strstr(apol_avrule_render(policy, (qpol_avrule_t *) item->item), "allow"));
+ printf("\tmissing permissions:\n");
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/spurious_audit.h b/sechecker/modules/spurious_audit.h
new file mode 100644
index 0000000..19b93f6
--- /dev/null
+++ b/sechecker/modules/spurious_audit.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the spurious audit rule module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Ryan Jordan rjordan@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SPURIOUS_AUDIT
+#define SPURIOUS_AUDIT
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+#define SECHK_SPUR_AU_AA_MISS 0x01
+#define SECHK_SPUR_AU_AA_PART 0x02
+#define SECHK_SPUR_AU_DA_FULL 0x04
+#define SECHK_SPUR_AU_DA_PART 0x08
+
+/* Module functions: */
+ int spurious_audit_register(sechk_lib_t * lib);
+ int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/template/profiles.readme b/sechecker/modules/template/profiles.readme
new file mode 100644
index 0000000..f781ee0
--- /dev/null
+++ b/sechecker/modules/template/profiles.readme
@@ -0,0 +1,142 @@
+How to write a profile for SEChecker
+=====================================
+
+Table of Contents
+========================
+1. Use of Profiles
+2. Format of the Profile
+ 2.0 <sechecker>
+ 2.1 <profile>
+ 2.2 <module>
+ 2.3 <output>
+ 2.4 <option>
+3. Example Profile
+
+1. Use of Profiles
+==========================
+SEChecker has a wide variety of modules which perform various tests
+on the policy and/or system. To make the management and running of
+these modules easier, several profiles are defined.
+
+A profile is used to run a set of modules with options set in a way
+that the resulting report reflects a specific security goal.
+
+To write your own profile, create a new XML file named <profile name>.prof.
+The format of the file is detailed below.
+
+2. Format of the Profile
+=========================
+A profile is an XML file loaded by SEChecker to run a specific set of tests.
+The profile recognizes the following tags
+
+2.0 <sechecker>
+===========================
+The sechecker tag should be the first open tag in the file and the final
+tag to be closed. The tag has a single attribute version, which should
+be set to the current version of SEChecker you are using. To find your
+version number, run: "sechecker --version".
+
+<sechecker version="1.0">
+
+Be sure to remember to close this tag at the end of the file.
+
+2.1 <profile>
+===========================
+The profile tag tells the parser that SEChecker should interpret this
+file as a profile. This tag has no attributes.
+
+<profile>
+
+Close this tag just before the sechecker tag is closed at the end of the file
+
+2.2 <module>
+===========================
+The module tag tells SEChecker that a particular module should be run for
+this profile. The only attribute is name.
+
+<module name="mod_name">
+
+This tag is closed after all other tags related to that module
+
+2.3 <output>
+=========================
+The output tag tells SEChecker to use this output format for the module
+in which it appears. This tag is optional and has one attribute, value.
+
+<output value="short"/>
+
+This tag should close itself. The valid values are:
+ none - do not print anything in the report; only run this module
+ as dependency of another module.
+ quiet - print only the stats and header in the report
+ short - print the header, stats, and a list of items found by the
+ module without any accompanying proof
+ long - print the header, stats, and a list of items found by the
+ module with proof of the result following each item
+ verbose - print all possible output including the header, stats,
+ a list of items and a list of items with proof
+
+NOTE: any of the above values other than "none" are overridden by the
+ command line output flags. Setting an output value in a profile
+ overrides the default setting in the configuration file for this
+ profile only.
+
+2.4 <option>
+=======================
+The option tag allows a profile to specify additional options for a module.
+The option tag has two mandatory attributes, "name" and "value".
+The values of these attributes is specific to the module for which the
+option is specified. Options specified in a profile are used in addition
+to those in the configuration file.
+
+<option name="option_name" value="some_value"/>
+
+This tag closes itself. As its name implies this tag is optional.
+
+3. Example Profile
+======================
+The following is a brief example of a profile
+
+<sechecker version="1.0">
+<profile>
+
+ <module name="mod1">
+ </module>
+
+ <module name="mod2">
+ <output value="none"/>
+ <option name="attribute" value="my_attrib"/>
+ </module>
+
+ <module name="mod3">
+ <option name="foo" value="bar"/>
+ </module>
+
+ <module name="mod4">
+ <output value="short"/>
+ </module>
+
+ <module name="mod5">
+ <output value="quiet"/>
+ <option name="type" value="shadow_t"/>
+ </module>
+
+</profile>
+</sechecker>
+
+The result of this profile would be:
+- run mod1 with default configuration;
+ print with default settings
+- run mod2 with the additional attribute my_attrib,
+ but don't print its results
+- run mod3 with option foo set to bar (in addition to any other settings);
+ print with default settings
+- run mod4;
+ print in short output
+- run mod5 with additional type shadow_t;
+ print using quiet output
+
+If there are also modules mod6 and mod7, neither would be run unless
+one of the other modules (mod1-5) had a dependency on them.
+
+
diff --git a/sechecker/modules/template/template.howto b/sechecker/modules/template/template.howto
new file mode 100644
index 0000000..09151e0
--- /dev/null
+++ b/sechecker/modules/template/template.howto
@@ -0,0 +1,13 @@
+Instructions for using the template to add new modules
+========================================================
+1. copy the xx.c and xx.h files to the modules directory
+2. rename the files and replace the text xx with the
+ module name in both files
+3. add the register function for your module xx_register
+ to the register_list.h and register_list.c entries
+4. add options and any requirements or dependencies to
+ the decription in the register function
+5. fill out TODO sections of the template with logic for
+ your module
+6. recompile
+
diff --git a/sechecker/modules/template/xx.c b/sechecker/modules/template/xx.c
new file mode 100644
index 0000000..20f7f5f
--- /dev/null
+++ b/sechecker/modules/template/xx.c
@@ -0,0 +1,393 @@
+/**
+ * @file
+ * Implementation of the xx module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* NOTE: TODO This is a module template, which includes all the necessary
+ * infrastructure to implement a basic SEChecker module. To use this template
+ * first replace all instances of the string xx with the name of the module,
+ * then edit or complete all sections marked TODO as instructed. */
+
+#include <config.h>
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include "xx.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem of the file
+ * name; it should also match the prefix of all functions defined in this
+ * module and the private data storage structure */
+static const char *const mod_name = "xx";
+
+/* The register function registers all of a module's functions
+ * with the library. TODO: Edit the description fields to include all
+ * options, requirements, and dependencies. Also provide a brief summary
+ * of the steps performed in this module's checks. If you are adding
+ * additional functions you need other modules to call, see the note at
+ * the bottom of this function to do so. */
+int xx_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the register list file and their name and options
+ * are stored in the module vector of the library. The name is looked up to
+ * determine where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(lib->policy, "Module unknown \"%s\"", mod_name);
+ errno = ENOENT;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* TODO: assign the descriptions */
+ mod->brief_description = "";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "TODO: detailed description for this module.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = "TODO: set proper severity";
+
+ /* TODO: assign default options (remove if none)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->options, (void *)nv);
+
+ /* TODO: assign requirements (remove if none)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* TODO: assign dependencies (remove if not needed)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->dependencies, (void *)nv);
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ /* TODO: if the module does not have a private data structure
+ * set this function pointer to NULL */
+ mod->data_free = xx_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ /* TODO: (optional) add any other functions needed here,
+ * add a block as above for each additional function */
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object and
+ * initializes its values. Add any option processing logic as indicated below.
+ * TODO: add options processing logic */
+int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ xx_data_t *datum = NULL;
+ int error = 0;
+ size_t i = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* If the module doesnot have a privte data sturcture replace the following
+ * block with "mod->data = NULL" */
+ datum = xx_data_new();
+ if (!datum) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ errno = error;
+ return -1;
+ }
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ /* TODO: check options
+ * check strings opt->name and opt->value of each option
+ * to set the members of the private data storage object
+ * (pointed to by datum).
+ * i.e. if (!strcmp(...)) {} else if (!strcmp((...)) etc.
+ * There should be relatively few options for any one module.
+ * If too many options are needed consider splitting the check
+ * into multiple modules and using dependencies. It is desirable
+ * for all checks to be a simple and granular as is possible */
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found
+ * TODO: add check logic */
+int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ xx_data_t *datum;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error = 0;
+
+ /* TODO: define any aditional variables needed */
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (xx_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto xx_run_fail;
+ }
+ /* TODO: set res->item_type to indicate which array the item_id indexes
+ * use values from the sechk_item_type_e enum (see sechecker.h) */
+
+ /* TODO: check logic here
+ * Perform check here. Create and initialize items and proof as found,
+ * appending to the appropriate vectors.
+ * For examples of the type of code to use here see other modules. */
+
+ mod->result = res;
+
+ /* If module finds something that would be considered a failure
+ * of the policy return 1 here */
+ if (apol_vector_get_size(res->items) > 0)
+ return 1;
+
+ return 0;
+
+ xx_run_fail:
+ /* TODO: free any other memory allocated during check logic */
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module
+ * TODO: be sure to free any allocated space in the private data */
+void xx_data_free(void *data)
+{
+ xx_data_t *datum = (xx_data_t *) data;
+
+ if (datum) {
+ /* TODO: free any allocated members of the module's
+ * private data structure */
+ }
+
+ free(data);
+}
+
+/* The print function generates the text and prints the results to stdout. The
+ * outline below prints the standard format of a report section. Some modules
+ * may not have results in a format that can be represented by this outline and
+ * will need a different specification. It is required that each of the flags
+ * for output components be tested in this function (stats, list, proof,
+ * detailed, and brief) TODO: fill in the indicated information in the report
+ * fields as indicated below. Some alteration may be necessary for checks that
+ * perform different analyses */
+int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ xx_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (xx_data_t *) mod->data;
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "Module %s has not been run", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* TODO: display the statistics of the results
+ * typical text is "Found %i <itemtype>.\n"
+ * additional information may be printed here depending upon
+ * the amount of data gathered in the check */
+ if (outformat & SECHK_OUT_STATS) {
+ /* TODO: "Found %i <itemtype>.\n": enter itemtype */
+ printf("Found %zd .\n", apol_vector_get_size(mod->result->items));
+ /* TODO: any additional generated statistics */
+ }
+ /* The list report component is a display of all items found without any
+ * supporting proof. The default method is to display a comma separated list
+ * four items to a line this may need to be changed for longer items.
+ * TODO: you will need to enter the string representation of
+ * each item as the second parameter in the printf statement
+ * in place of the empty string.
+ * NOTE: if the item is a type of rule print only one per line. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ i++;
+ /* TODO: (optional) change the number below to
+ * print more or less than 4 items per line */
+ i %= 4;
+ /* TODO: second parameter: item name */
+ printf("%s%s", "", (i ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items with an
+ * indented list of proof statements supporting the result of the check for
+ * that item (e.g. rules with a given type). Each proof element is then
+ * displayed in an indented list one per line below it.
+ * TODO: the name of the item should be entered below.
+ * NOTE: certain checks may need to further modify this report component if
+ * the results cannot be presented in this format */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s", ""); /* TODO: item name */
+ printf(" - severity: %s\n", sechk_item_sev(item));
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+/* The xx_data_new function allocates and returns an initialized private data
+ * storage structure for this module.
+ * TODO: initialize any non-zero/non-null data (if needed) below */
+xx_data_t *xx_data_new(void)
+{
+ xx_data_t *datum = NULL;
+
+ datum = (xx_data_t *) calloc(1, sizeof(xx_data_t));
+
+ /* TODO: initialize data */
+
+ return datum;
+}
diff --git a/sechecker/modules/template/xx.h b/sechecker/modules/template/xx.h
new file mode 100644
index 0000000..d8c18b8
--- /dev/null
+++ b/sechecker/modules/template/xx.h
@@ -0,0 +1,72 @@
+/**
+ * @file
+ * Defines the interface for the xx module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* NOTE: TODO This is a module template, which includes all the necessary
+ * infrastructure to implement a basic SEChecker module. To use this template
+ * first replace all instances of the string xx with the name of the module,
+ * then edit or complete all sections marked TODO as instructed. Do not forget
+ * to add an entry in the register_list files (see these files for further
+ * instruction) */
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+/* The xx_data structure is used to hold the check specific
+ * private data of a module.
+ * TODO: Add any members you need to perform the check or if the module is not
+ * going to need private data remove this declaration and the data_new() and
+ * data_free() functions */
+typedef struct xx_data
+{
+ /* TODO: define members of this data structure
+ * for module's private data */
+} xx_data_t;
+
+/* The following functions are used to allocate and initialize the private data
+ * storage structure for this module and to free all memory used by it. */
+xx_data_t *xx_data_new(void);
+void xx_data_free(void *data);
+
+/* The register function places the needed information about the module in the
+ * library, including description fields and the functions available. TODO: be
+ * sure to add an entry for this function in the register_list files. */
+int xx_register(sechk_lib_t * lib);
+
+/* Module functions:
+ * The following three functions (init, run, and print) must exist for all
+ * modules. NOTE: while using a modular format SEChecker is built statically;
+ * this means that all modules and their functions are in the same namespace.
+ * Be sure to choose a unique name for each module and to set the module name
+ * prefix xx everywhere */
+int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+/* TODO: (optional) Declare any other functions needed by other modules here.
+ * The prototype of the function must be int xx_fn(sechk_module_t *mod,
+ * apol_policy_t *policy, void *arg). For use by the get_module_function()
+ * function, be sure to add a block in the xx_register function to register
+ * your function.
+ * NOTE: While SEChecker is build statically, it is intended that no module
+ * directly call a function from another but instead use get_module_function()
+ * to get the desired function from the library. */
diff --git a/sechecker/modules/types_wo_allow.c b/sechecker/modules/types_wo_allow.c
new file mode 100644
index 0000000..2d0112a
--- /dev/null
+++ b/sechecker/modules/types_wo_allow.c
@@ -0,0 +1,442 @@
+/**
+ * @file
+ * Implementation of the types without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "types_wo_allow.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "types_wo_allow";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int types_wo_allow_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "types with no allow rules";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds types defined in the policy that are not used in any allow\n"
+ "rules. A type that is never granted an allow rule in the policy is a dead type.\n"
+ "This means that all attempted access to the type will be denied including\n"
+ "attempts to relabel to a (usable) type. The type may need to be removed from\n"
+ "the policy or some intended access should be granted to the type.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ bool used = false;
+ apol_vector_t *type_vector;
+ apol_vector_t *avrule_vector;
+ apol_avrule_query_t *avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+
+ if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) {
+ error = errno;
+ goto types_wo_allow_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ const qpol_type_t *type;
+ const char *type_name;
+ size_t j;
+
+ used = false;
+ type = apol_vector_get_element(type_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ /* Check source for allow type */
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 1);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ uint32_t rule_type;
+ qpol_avrule_t *rule;
+
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_rule_type(q, rule, &rule_type);
+ if (rule_type == QPOL_RULE_ALLOW)
+ used = true;
+ }
+ apol_vector_destroy(&avrule_vector);
+ if (used)
+ continue;
+
+ /* Check target for allow type */
+ apol_avrule_query_set_source(policy, avrule_query, NULL, 0);
+ apol_avrule_query_set_target(policy, avrule_query, type_name, 1);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ uint32_t rule_type;
+ qpol_avrule_t *rule;
+
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_rule_type(q, rule, &rule_type);
+ if (rule_type == QPOL_RULE_ALLOW)
+ used = true;
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ if (used)
+ continue;
+
+ /* not used anywhere */
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)type;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup("This type does not appear in any allow rules.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ }
+ apol_vector_destroy(&type_vector);
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ types_wo_allow_run_fail:
+ apol_vector_destroy(&type_vector);
+ apol_vector_destroy(&avrule_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types do not appear in any allow rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+ return 0;
+}
diff --git a/sechecker/modules/types_wo_allow.h b/sechecker/modules/types_wo_allow.h
new file mode 100644
index 0000000..325c786
--- /dev/null
+++ b/sechecker/modules/types_wo_allow.h
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * Defines the interface for the types without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TYPES_WO_ALLOW
+#define TYPES_WO_ALLOW
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+#include <apol/type-query.h>
+
+ int types_wo_allow_register(sechk_lib_t * lib);
+ int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/unreachable_doms.c b/sechecker/modules/unreachable_doms.c
new file mode 100644
index 0000000..4653c2d
--- /dev/null
+++ b/sechecker/modules/unreachable_doms.c
@@ -0,0 +1,1053 @@
+/**
+ * @file
+ * Implementation of the unreachable domains module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "unreachable_doms.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy);
+static bool in_isid_ctx(const char *type_name, apol_policy_t * policy);
+static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum);
+/* for some reason we have to define this here to remove compile warnings */
+extern ssize_t getline(char **lineptr, size_t * n, FILE * stream);
+
+/* This string is the name f the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "unreachable_doms";
+
+int unreachable_doms_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "unreachable domains";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all domains in a policy which are unreachable. A domain is\n"
+ "unreachable if any of the following apply:\n"
+ " 1) There is insufficient type enforcement policy to allow a transition,\n"
+ " 2) There is insufficient RBAC policy to allow a transition,\n"
+ " 3) There are no users with proper roles to allow a transition.\n"
+ "However, if any of the above rules indicate an unreachable domain, yet the\n"
+ "domain appears in the system default contexts file, it is considered reachable.\n";
+ mod->opt_description = " Module requirements:\n" " attribute names\n"
+#ifdef LIBSELINUX
+ " default_contexts file\n"
+#endif
+ " Module dependencies:\n" " find_domains module\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#ifdef LIBSELINUX
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_DEFAULT_CONTEXTS, NULL)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#endif
+
+ /* assign dependencies */
+ if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = unreachable_doms_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum = NULL;
+ const char *ctx_file_path = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = unreachable_doms_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ mod->data = datum;
+
+ /* Parse default contexts file */
+ if (!(datum->ctx_vector = apol_vector_create(free))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#ifdef LIBSELINUX
+ ctx_file_path = selinux_default_context_path();
+ if (!ctx_file_path) {
+ ERR(policy, "%s", "Unable to find default contexts file");
+ errno = ENOENT;
+ return -1;
+ } else {
+ bool retv = parse_default_contexts(ctx_file_path, datum->ctx_vector, policy);
+ if (!retv) {
+ ERR(policy, "%s", "Unable to parse default contexts file");
+ errno = EIO;
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+typedef enum dom_need
+{
+ KEEP_SEARCHING = 0, /* keep checking way to reach not found yet */
+ USER, /* missing a user for role(s) associated with the type */
+ COMMON_USER, /* missing user for the role in a transition to that type */
+ ROLE_TRANS, /* transition is valid but need a role transition as well */
+ ROLE_ALLOW, /* transition is valid and has a role_transition but not role allow */
+ RBAC, /* there is a transition but insufficient RBAC rules to permit or to determie a user */
+ VALID_TRANS, /* only transitions to the type are invalid ones needs one or more rules to complete */
+ ROLE, /* type has no associated role */
+ TRANSITION, /* no transition exists */
+ DONE /* done searching a valid way to reach the type has been found */
+} dom_need_e;
+
+/**
+ * Finds user witn at least one role from each vector.
+ * @param policy The policy.
+ * @param src_roles The first set of roles.
+ * @param tgt_roles The second set of roles.
+ * @return 1 if a common user can be found 0 other wise.
+ */
+static int exists_common_user(apol_policy_t * policy, apol_vector_t * src_roles, apol_vector_t * tgt_roles,
+ const qpol_role_t ** which_sr, const qpol_role_t ** which_tr, const qpol_user_t ** which_u)
+{
+ int retv = 0;
+ apol_user_query_t *uq;
+ const char *name = NULL;
+ const qpol_role_t *role = NULL;
+ const qpol_user_t *user = NULL;
+ qpol_iterator_t *iter = NULL;
+ apol_vector_t *user_v = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, j, k;
+
+ if (!policy || !src_roles || !tgt_roles)
+ return 0;
+
+ if (which_sr)
+ *which_sr = NULL;
+ if (which_tr)
+ *which_tr = NULL;
+ if (which_u)
+ *which_u = NULL;
+
+ if (!(uq = apol_user_query_create()))
+ return 0;
+
+ for (i = 0; i < apol_vector_get_size(src_roles); i++) {
+ role = apol_vector_get_element(src_roles, i);
+ if (which_sr)
+ *which_sr = role;
+ qpol_role_get_name(q, role, &name);
+ apol_user_query_set_role(policy, uq, name);
+ apol_user_get_by_query(policy, uq, &user_v);
+ for (j = 0; j < apol_vector_get_size(user_v); j++) {
+ user = apol_vector_get_element(user_v, j);
+ qpol_user_get_role_iter(q, user, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&role);
+ if (!apol_vector_get_index(tgt_roles, role, NULL, NULL, &k)) {
+ retv = 1;
+ if (which_tr)
+ *which_tr = role;
+ if (which_u)
+ *which_u = user;
+ goto exists_done;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&user_v);
+ }
+
+ exists_done:
+ qpol_iterator_destroy(&iter);
+ apol_vector_destroy(&user_v);
+ apol_user_query_destroy(&uq);
+ return retv;
+}
+
+/* The run function performs the check. This function runs only once even if
+ * called multiple times. This function allocates the result structure and
+ * fills in all relevant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum;
+ sechk_name_value_t *dep = NULL;
+ sechk_result_t *res = NULL, *find_domains_res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j, k, l;
+ sechk_mod_fn_t run_fn = NULL;
+ int error = 0, trans_missing = 0;
+ apol_vector_t *dom_vector = NULL, *dom_results = NULL, *dom_roles = NULL;
+ apol_vector_t *valid_rev_trans = NULL, *invalid_rev_trans = NULL;
+ apol_vector_t *start_roles = NULL, *intersect_roles = NULL;
+ apol_vector_t *tmp_users = NULL, *role_users = NULL;
+ apol_vector_t *role_trans_vector = NULL, *role_allow_vector = NULL;
+ apol_domain_trans_analysis_t *dta = NULL;
+ apol_domain_trans_result_t *dtr = NULL;
+ const char *tmp_name = NULL, *cur_dom_name = NULL;
+ const char *tmp2 = NULL, *tmp3 = NULL;
+ const qpol_type_t *cur_dom = NULL, *ep_type = NULL, *start_type = NULL;
+ const qpol_type_t *last_type = NULL;
+ const qpol_role_t *last_role = NULL, *src_role = NULL, *dflt_role = NULL;
+ const qpol_role_t *last_dflt = NULL;
+ const qpol_user_t *last_user = NULL;
+ dom_need_e need = KEEP_SEARCHING;
+ apol_role_query_t *role_q = NULL;
+ apol_user_query_t *user_q = NULL;
+ apol_role_trans_query_t *rtq = NULL;
+ apol_role_allow_query_t *raq = NULL;
+ const qpol_role_trans_t *role_trans = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (unreachable_doms_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto unreachable_doms_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto unreachable_doms_run_fail;
+ }
+
+ /* run dependencies and get results */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib);
+ dom_results = find_domains_res->items;
+ if (!(dom_vector = apol_vector_create(NULL))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ for (i = 0; i < apol_vector_get_size(dom_results); i++) {
+ item = apol_vector_get_element(dom_results, i);
+ if (apol_vector_append(dom_vector, (void *)(item->item))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ }
+ item = NULL;
+ dom_results = NULL; /* no need to destroy, belongs to another module. */
+
+ /* initialize query objects */
+ dta = apol_domain_trans_analysis_create();
+ if (!dta) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ apol_domain_trans_analysis_set_direction(policy, dta, APOL_DOMAIN_TRANS_DIRECTION_REVERSE);
+
+ role_q = apol_role_query_create();
+ if (!role_q) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ user_q = apol_user_query_create();
+ if (!user_q) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ rtq = apol_role_trans_query_create();
+ if (!rtq) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ raq = apol_role_allow_query_create();
+ if (!raq) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ /* dom_vector now contains all types considered domains */
+ for (i = 0; i < apol_vector_get_size(dom_vector); i++) {
+ cur_dom = apol_vector_get_element(dom_vector, i);
+ qpol_type_get_name(q, cur_dom, &cur_dom_name);
+ need = KEEP_SEARCHING;
+
+ if (
+#ifdef LIBSELINUX
+ in_def_ctx(cur_dom_name, datum) ||
+#endif
+ in_isid_ctx(cur_dom_name, policy))
+ continue;
+
+ /* collect information about roles and transitions to this domain */
+ apol_role_query_set_type(policy, role_q, cur_dom_name);
+ apol_role_get_by_query(policy, role_q, &dom_roles);
+ apol_policy_reset_domain_trans_table(policy);
+ apol_domain_trans_analysis_set_start_type(policy, dta, cur_dom_name);
+ apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_VALID);
+ apol_domain_trans_analysis_do(policy, dta, &valid_rev_trans);
+ apol_policy_reset_domain_trans_table(policy);
+ apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_INVALID);
+ apol_domain_trans_analysis_do(policy, dta, &invalid_rev_trans);
+
+ /* for valid transitions - validate RBAC, and then users */
+ for (j = 0; j < apol_vector_get_size(valid_rev_trans); j++) {
+ dtr = apol_vector_get_element(valid_rev_trans, j);
+ start_type = apol_domain_trans_result_get_start_type(dtr);
+ ep_type = apol_domain_trans_result_get_entrypoint_type(dtr);
+ qpol_type_get_name(q, start_type, &tmp_name);
+ apol_role_query_set_type(policy, role_q, tmp_name);
+ apol_role_get_by_query(policy, role_q, &start_roles);
+ intersect_roles = apol_vector_create_from_intersection(dom_roles, start_roles, NULL, NULL);
+ if (apol_vector_get_size(intersect_roles) > 0) {
+ /* find user with role in intersect */
+ role_users = apol_vector_create(NULL);
+ for (k = 0; k < apol_vector_get_size(intersect_roles); k++) {
+ last_role = apol_vector_get_element(intersect_roles, k);
+ qpol_role_get_name(q, last_role, &tmp_name);
+ apol_user_query_set_role(policy, user_q, tmp_name);
+ apol_user_get_by_query(policy, user_q, &tmp_users);
+ if (apol_vector_cat(role_users, tmp_users)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ apol_vector_destroy(&tmp_users);
+ }
+ if (apol_vector_get_size(role_users) > 0)
+ need = DONE;
+ else
+ need = USER;
+ apol_vector_destroy(&role_users);
+ }
+ if (need == DONE)
+ break;
+ /* look for role_transitions */
+ qpol_type_get_name(q, ep_type, &tmp_name);
+ apol_role_trans_query_set_target(policy, rtq, tmp_name, 1);
+ apol_role_trans_get_by_query(policy, rtq, &role_trans_vector);
+ for (k = 0; need != DONE && k < apol_vector_get_size(role_trans_vector); k++) {
+ role_trans = apol_vector_get_element(role_trans_vector, k);
+ qpol_role_trans_get_source_role(q, role_trans, &src_role);
+ qpol_role_trans_get_default_role(q, role_trans, &dflt_role);
+ if (apol_vector_get_index(start_roles, src_role, NULL, NULL, &l)
+ || apol_vector_get_index(dom_roles, dflt_role, NULL, NULL, &l))
+ continue; /* start domain must have the source role and cur_dom must have default role or transition does not apply */
+ if (exists_common_user(policy, start_roles, dom_roles, NULL, NULL, NULL)) {
+ qpol_role_get_name(q, src_role, &tmp_name);
+ apol_role_allow_query_set_source(policy, raq, tmp_name);
+ qpol_role_get_name(q, dflt_role, &tmp_name);
+ apol_role_allow_query_set_target(policy, raq, tmp_name);
+ apol_role_allow_get_by_query(policy, raq, &role_allow_vector);
+ if (apol_vector_get_size(role_allow_vector) > 0) {
+ need = DONE;
+ } else {
+ need = ROLE_ALLOW;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ }
+ apol_vector_destroy(&role_allow_vector);
+ } else {
+ need = COMMON_USER;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ }
+ }
+ /* no roles usable in intersection and no transitions so pick first set with common user */
+ if (apol_vector_get_size(role_trans_vector) == 0) {
+ if (exists_common_user(policy, start_roles, dom_roles, &src_role, &dflt_role, &last_user)) {
+ need = ROLE_TRANS;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ last_type = ep_type;
+ } else {
+ need = RBAC;
+ }
+ }
+ apol_vector_destroy(&role_trans_vector);
+ if (need == DONE)
+ break;
+ }
+ /* if no valid transition found - check what is needed to complete invalid ones */
+ if (need == KEEP_SEARCHING) {
+ for (j = 0; j < apol_vector_get_size(invalid_rev_trans); j++) {
+ dtr = apol_vector_get_element(invalid_rev_trans, j);
+ start_type = apol_domain_trans_result_get_start_type(dtr);
+ ep_type = apol_domain_trans_result_get_entrypoint_type(dtr);
+ trans_missing = apol_domain_trans_table_verify_trans(policy, start_type, ep_type, cur_dom);
+ need = VALID_TRANS;
+ /* since incomplete transitions can be missing types break if we
+ * found one with all three types specified, else keep the last one */
+ if (start_type && ep_type)
+ break;
+ }
+ }
+ /* if no transition exists (valid or otherwise) check that at least one role and user pair is valid */
+ if (need == KEEP_SEARCHING) {
+ role_users = apol_vector_create(NULL);
+ for (j = 0; j < apol_vector_get_size(dom_roles); j++) {
+ last_role = apol_vector_get_element(dom_roles, j);
+ qpol_role_get_name(q, last_role, &tmp_name);
+ apol_user_query_set_role(policy, user_q, tmp_name);
+ apol_user_get_by_query(policy, user_q, &tmp_users);
+ apol_vector_cat(role_users, tmp_users);
+ apol_vector_destroy(&tmp_users);
+ }
+ if (apol_vector_get_size(dom_roles) == 0) {
+ need = ROLE;
+ } else if (apol_vector_get_size(role_users) == 0) {
+ need = USER;
+ } else {
+ need = TRANSITION;
+ }
+ apol_vector_destroy(&role_users);
+ }
+ /* if something needs to be reported do so now */
+ if (need != DONE) {
+ assert(need != KEEP_SEARCHING);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ item->item = (void *)cur_dom;
+ item->test_result = (unsigned char)need;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ switch (need) {
+ case USER:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ if (asprintf(&proof->text, "No user associated with role %s for %s", tmp_name, cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case COMMON_USER:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ if (asprintf
+ (&proof->text, "Role transition required but no user associated with role %s and %s",
+ tmp_name, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE_TRANS:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ qpol_type_get_name(q, last_type, &tmp3);
+ if (asprintf(&proof->text, "Missing: role_transition %s %s %s;", tmp_name, tmp3, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE_ALLOW:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ if (asprintf
+ (&proof->text,
+ "Role transition required but missing role allow rule.\n\tMissing: allow %s %s;",
+ tmp_name, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case RBAC:
+ {
+ if (asprintf
+ (&proof->text,
+ "Valid domain transition to %s exists but indufficient RBAC rules to permit it.",
+ cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case VALID_TRANS:
+ {
+ if (start_type)
+ qpol_type_get_name(q, start_type, &tmp2);
+ else
+ tmp2 = "<start_type>";
+ if (ep_type)
+ qpol_type_get_name(q, ep_type, &tmp3);
+ else
+ tmp3 = "<entrypont>";
+ if (asprintf
+ (&proof->text,
+ "Partial transition to %s found:\n\t%s: allow %s %s : process transition;\n\t%s: allow %s %s : file execute;\n\t%s: allow %s %s : file entrypoint;\n\t%s one of:\n\tallow %s self : process setexec;\n\ttype_transition %s %s : process %s;",
+ cur_dom_name,
+ ((trans_missing & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) ? "Missing" : "Has"), tmp2,
+ cur_dom_name, ((trans_missing & APOL_DOMAIN_TRANS_RULE_EXEC) ? "Missing" : "Has"),
+ tmp2, tmp3, ((trans_missing & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) ? "Missing" : "Has"),
+ cur_dom_name, tmp3,
+ ((trans_missing & (APOL_DOMAIN_TRANS_RULE_TYPE_TRANS | APOL_DOMAIN_TRANS_RULE_SETEXEC))
+ ? "May need" : "Has"), cur_dom_name, tmp2, tmp3, cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE:
+ {
+ if (asprintf(&proof->text, "No role associated with domain %s", cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case TRANSITION:
+ {
+ if (asprintf(&proof->text, "There are no transitions to domain %s", cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case DONE:
+ case KEEP_SEARCHING:
+ default:
+ {
+ assert(0);
+ error = EDOM;
+ goto unreachable_doms_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof = NULL;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&dom_roles);
+ apol_vector_destroy(&valid_rev_trans);
+ apol_vector_destroy(&invalid_rev_trans);
+ }
+
+ apol_vector_destroy(&dom_vector);
+ apol_domain_trans_analysis_destroy(&dta);
+ apol_role_query_destroy(&role_q);
+ apol_user_query_destroy(&user_q);
+ apol_role_trans_query_destroy(&rtq);
+ apol_role_allow_query_destroy(&raq);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ unreachable_doms_run_fail:
+ apol_vector_destroy(&dom_vector);
+ apol_domain_trans_analysis_destroy(&dta);
+ apol_role_query_destroy(&role_q);
+ apol_user_query_destroy(&user_q);
+ apol_role_trans_query_destroy(&rtq);
+ apol_role_allow_query_destroy(&raq);
+ apol_vector_destroy(&dom_roles);
+ apol_vector_destroy(&valid_rev_trans);
+ apol_vector_destroy(&invalid_rev_trans);
+ apol_vector_destroy(&tmp_users);
+ apol_vector_destroy(&role_users);
+ apol_vector_destroy(&role_trans_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module */
+void unreachable_doms_data_free(void *data)
+{
+ unreachable_doms_data_t *d = data;
+ if (!data)
+ return;
+
+ free(d->ctx_file_path);
+ apol_vector_destroy(&d->ctx_vector);
+ free(data);
+}
+
+/* The print function generates the text and prints the results to stdout. */
+int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k, l, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (unreachable_doms_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd unreachable domains.\n", num_items);
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ if (apol_vector_get_size(datum->ctx_vector) > 0) {
+ printf("Found %zd domains in %s:\n", apol_vector_get_size(datum->ctx_vector),
+ selinux_default_context_path());
+ for (j = 0; j < apol_vector_get_size(datum->ctx_vector); j++) {
+ type_name = apol_vector_get_element(datum->ctx_vector, j);
+ printf("\t%s\n", type_name);
+ }
+ }
+
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+/* The unreachable_doms_data_new function allocates and returns an initialized
+ * private data storage structure for this module. */
+unreachable_doms_data_t *unreachable_doms_data_new(void)
+{
+ unreachable_doms_data_t *datum = NULL;
+
+ datum = (unreachable_doms_data_t *) calloc(1, sizeof(unreachable_doms_data_t));
+
+ return datum;
+}
+
+/* Parses default_contexts and adds source domains to datum->ctx_list.
+ * The vector will contain newly allocated strings. */
+static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy)
+{
+ int str_sz, i, charno, error = 0, retv;
+ FILE *ctx_file;
+ char *line = NULL, *src_role = NULL, *src_dom = NULL, *dst_role = NULL, *dst_dom = NULL;
+ size_t line_len = 0;
+ bool uses_mls = false;
+
+ printf("Using default contexts: %s\n", ctx_file_path);
+ ctx_file = fopen(ctx_file_path, "r");
+ if (!ctx_file) {
+ error = errno;
+ ERR(policy, "Opening default contexts file %s", ctx_file_path);
+ goto parse_default_contexts_fail;
+ }
+
+ while (!feof(ctx_file)) {
+ retv = getline(&line, &line_len, ctx_file);
+ if (retv == -1) {
+ if (feof(ctx_file)) {
+ break;
+ } else {
+ error = errno;
+ ERR(policy, "%s", "Reading default contexts file");
+ goto parse_default_contexts_fail;
+ }
+ }
+
+ uses_mls = false;
+ str_sz = APOL_STR_SZ + 128;
+ i = 0;
+
+ /* source role */
+ src_role = malloc(str_sz);
+ if (!src_role) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+
+ memset(src_role, 0x0, str_sz);
+ charno = 0;
+ while (line[i] != ':') {
+ if (!isspace(line[i])) {
+ src_role[i] = line[i];
+ charno++;
+ }
+ i++;
+ }
+ i++; /* skip ':' */
+
+ /* source type */
+ src_dom = malloc(str_sz);
+ if (!src_dom) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(src_dom, 0x0, str_sz);
+ charno = 0;
+ while (1) {
+ if (isspace(line[i]))
+ break;
+ /* Check for MLS */
+ if (line[i] == ':') {
+ uses_mls = true;
+ i++; /* skip ':' */
+ while (!isspace(line[i]))
+ i++;
+ }
+ if (uses_mls)
+ break;
+
+ src_dom[charno] = line[i];
+ charno++;
+ i++;
+ }
+
+ /* dest role */
+ dst_role = malloc(str_sz);
+ if (!dst_role) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(dst_role, 0x0, str_sz);
+ charno = 0;
+ while (line[i] != ':') {
+ if (!isspace(line[i])) {
+ dst_role[charno] = line[i];
+ charno++;
+ }
+
+ i++;
+ }
+ i++; /* skip ':' */
+
+ /* dest type */
+ dst_dom = malloc(str_sz);
+ if (!dst_dom) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(dst_dom, 0x0, str_sz);
+ charno = 0;
+ while (line[i]) {
+ if (uses_mls)
+ if (line[i] == ':')
+ break;
+
+ if (!isspace(line[i]))
+ dst_dom[charno] = line[i];
+
+ charno++;
+ i++;
+ }
+
+ if (apol_vector_append(ctx_vector, (void *)strdup(src_dom)) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ free(line);
+ line = NULL;
+ free(src_role);
+ free(src_dom);
+ free(dst_role);
+ free(dst_dom);
+ }
+ free(line);
+ fclose(ctx_file);
+ return true;
+ parse_default_contexts_fail:
+ if (ctx_file != NULL) {
+ fclose(ctx_file);
+ }
+ free(line);
+ free(src_role);
+ free(src_dom);
+ free(dst_role);
+ free(dst_dom);
+ errno = error;
+ return false;
+}
+
+/* Returns true if type_idx is in datum->ctx_list */
+static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum)
+{
+ size_t i;
+ if (apol_vector_get_index(datum->ctx_vector, type_name, apol_str_strcmp, NULL, &i) < 0) {
+ return false;
+ }
+ return true;
+}
+
+/* Returns true if type is a type assigned to an isid */
+static bool in_isid_ctx(const char *type_name, apol_policy_t * policy)
+{
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ qpol_policy_get_isid_iter(q, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ const qpol_isid_t *isid;
+ const qpol_context_t *ocon;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+
+ qpol_iterator_get_item(iter, (void **)&isid);
+ qpol_isid_get_context(q, isid, &ocon);
+ qpol_context_get_type(q, ocon, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ if (!strcmp(type_name, context_type_name)) {
+ qpol_iterator_destroy(&iter);
+ return true;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ return false;
+}
diff --git a/sechecker/modules/unreachable_doms.h b/sechecker/modules/unreachable_doms.h
new file mode 100644
index 0000000..660de76
--- /dev/null
+++ b/sechecker/modules/unreachable_doms.h
@@ -0,0 +1,73 @@
+/**
+ * @file
+ * Defines the interface for the unreachable domains module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef UNREACHABLE_DOMS
+#define UNREACHABLE_DOMS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+#include <apol/role-query.h>
+#include <apol/isid-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/domain-trans-analysis.h>
+#include <selinux/selinux.h>
+
+#define SECHK_INC_DOM_TRANS_HAS_TT 0x08
+#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04
+#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02
+#define SECHK_INC_DOM_TRANS_HAS_EP 0x01
+#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC)
+
+#define APOL_STR_SZ 128
+
+/* The unreachable_doms_data structure is used to hold the check specific
+ * private data of a module. */
+ typedef struct unreachable_doms_data
+ {
+ char *ctx_file_path;
+ /* vector of strings, read from default contexts file */
+ apol_vector_t *ctx_vector;
+ } unreachable_doms_data_t;
+
+ unreachable_doms_data_t *unreachable_doms_data_new(void);
+ void unreachable_doms_data_free(void *data);
+
+ int unreachable_doms_register(sechk_lib_t * lib);
+ int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UNREACHABLE_DOMS */
diff --git a/sechecker/modules/users_wo_roles.c b/sechecker/modules/users_wo_roles.c
new file mode 100644
index 0000000..a98d94d
--- /dev/null
+++ b/sechecker/modules/users_wo_roles.c
@@ -0,0 +1,321 @@
+/**
+ * @file
+ * Implementation of the users without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "users_wo_roles.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "users_wo_roles";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int users_wo_roles_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "users with no roles";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all the SELinux users in the policy that have no associated\n"
+ "roles. Users without roles may appear in the label of a file system object;\n"
+ "however, these users cannot login to the system or run any process. Since these\n"
+ "users cannot be used on the system, a policy change is recomended to remove the\n"
+ "users or provide some intended access.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data. */
+int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *user_vector;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ res->item_type = SECHK_ITEM_USER;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+
+ apol_user_get_by_query(policy, NULL, &user_vector);
+ for (i = 0; i < apol_vector_get_size(user_vector); i++) {
+ qpol_user_t *user;
+ qpol_iterator_t *role_iter;
+
+ user = apol_vector_get_element(user_vector, i);
+ qpol_user_get_role_iter(apol_policy_get_qpol(policy), user, &role_iter);
+ if (!qpol_iterator_end(role_iter)) {
+ qpol_iterator_destroy(&role_iter);
+ continue;
+ }
+ qpol_iterator_destroy(&role_iter);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ proof->type = SECHK_ITEM_USER;
+ proof->text = "User has no roles.\n";
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ item->item = (void *)user;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ }
+ apol_vector_destroy(&user_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ users_wo_roles_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_user_t *user;
+ const char *user_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd users.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following users have no associated roles.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ user = (qpol_user_t *) item->item;
+ qpol_user_get_name(apol_policy_get_qpol(policy), user, &user_name);
+ printf("%s%s", user_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/sechecker/modules/users_wo_roles.h b/sechecker/modules/users_wo_roles.h
new file mode 100644
index 0000000..dd1ee42
--- /dev/null
+++ b/sechecker/modules/users_wo_roles.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the users without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef USERS_WO_ROLES
+#define USERS_WO_ROLES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+
+ int users_wo_roles_register(sechk_lib_t * lib);
+ int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/profiles/all-checks-no-mls.sechecker b/sechecker/profiles/all-checks-no-mls.sechecker
new file mode 100644
index 0000000..657b5ba
--- /dev/null
+++ b/sechecker/profiles/all-checks-no-mls.sechecker
@@ -0,0 +1,98 @@
+<sechecker version="1.1">
+<profile>
+ <module name="find_domains">
+ <output value="quiet"/>
+ <option name="domain_attribute">
+ <item value="domain"/>
+ </option>
+ </module>
+
+ <module name="find_file_types">
+ <output value="quiet"/>
+ <option name="file_type_attribute">
+ <item value="file_type"/>
+ </option>
+ </module>
+
+ <module name="domain_and_file">
+ <output value="short"/>
+ </module>
+
+ <module name="attribs_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="users_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="types_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="attribs_wo_rules">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_users">
+ <output value="short"/>
+ </module>
+
+ <module name="spurious_audit">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_mount">
+ <output value="short"/>
+ </module>
+
+ <module name="domains_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_dom_trans">
+ <output value="short"/>
+ </module>
+
+ <module name="find_net_domains">
+ <output value="quiet"/>
+ <option name="net_obj">
+ <item value="netif"/>
+ <item value="tcp_socket"/>
+ <item value="udp_socket"/>
+ <item value="node"/>
+ <item value="association"/>
+ </option>
+ </module>
+
+ <module name="find_port_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_node_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_netif_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="inc_net_access">
+ <output value="short"/>
+ </module>
+
+ <module name="unreachable_doms">
+ <output value="short"/>
+ </module>
+
+</profile>
+</sechecker>
+
diff --git a/sechecker/profiles/all-checks.sechecker b/sechecker/profiles/all-checks.sechecker
new file mode 100644
index 0000000..498da0b
--- /dev/null
+++ b/sechecker/profiles/all-checks.sechecker
@@ -0,0 +1,102 @@
+<sechecker version="1.1">
+<profile>
+ <module name="find_domains">
+ <output value="quiet"/>
+ <option name="domain_attribute">
+ <item value="domain"/>
+ </option>
+ </module>
+
+ <module name="find_file_types">
+ <output value="quiet"/>
+ <option name="file_type_attribute">
+ <item value="file_type"/>
+ </option>
+ </module>
+
+ <module name="domain_and_file">
+ <output value="short"/>
+ </module>
+
+ <module name="attribs_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="users_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="types_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="attribs_wo_rules">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_users">
+ <output value="short"/>
+ </module>
+
+ <module name="spurious_audit">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_mount">
+ <output value="short"/>
+ </module>
+
+ <module name="domains_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_dom_trans">
+ <output value="short"/>
+ </module>
+
+ <module name="find_net_domains">
+ <output value="quiet"/>
+ <option name="net_obj">
+ <item value="netif"/>
+ <item value="tcp_socket"/>
+ <item value="udp_socket"/>
+ <item value="node"/>
+ <item value="association"/>
+ </option>
+ </module>
+
+ <module name="find_port_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_node_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_netif_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="inc_net_access">
+ <output value="short"/>
+ </module>
+
+ <module name="imp_range_trans">
+ <output value="short"/>
+ </module>
+
+ <module name="unreachable_doms">
+ <output value="short"/>
+ </module>
+
+</profile>
+</sechecker>
+
diff --git a/sechecker/profiles/analysis-checks.sechecker b/sechecker/profiles/analysis-checks.sechecker
new file mode 100644
index 0000000..8efaec9
--- /dev/null
+++ b/sechecker/profiles/analysis-checks.sechecker
@@ -0,0 +1,78 @@
+<sechecker version="1.1">
+<profile>
+ <module name="find_domains">
+ <output value="quiet"/>
+ <option name="domain_attribute">
+ <item value="domain"/>
+ </option>
+ </module>
+
+ <module name="find_file_types">
+ <output value="quiet"/>
+ <option name="file_type_attribute">
+ <item value="file_type"/>
+ </option>
+ </module>
+
+ <module name="domain_and_file">
+ <output value="short"/>
+ </module>
+
+ <module name="spurious_audit">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_mount">
+ <output value="short"/>
+ </module>
+
+ <module name="rules_exp_nothing">
+ <output value="short"/>
+ </module>
+
+ <module name="domains_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="inc_dom_trans">
+ <output value="short"/>
+ </module>
+
+ <module name="find_net_domains">
+ <output value="quiet"/>
+ <option name="net_obj">
+ <item value="netif"/>
+ <item value="tcp_socket"/>
+ <item value="udp_socket"/>
+ <item value="node"/>
+ <item value="association"/>
+ </option>
+ </module>
+
+ <module name="find_port_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_node_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_netif_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="inc_net_access">
+ <output value="short"/>
+ </module>
+
+ <module name="imp_range_trans">
+ <output value="short"/>
+ </module>
+
+ <module name="unreachable_doms">
+ <output value="short"/>
+ </module>
+
+</profile>
+</sechecker>
+
diff --git a/sechecker/profiles/devel-checks.sechecker b/sechecker/profiles/devel-checks.sechecker
new file mode 100644
index 0000000..5807044
--- /dev/null
+++ b/sechecker/profiles/devel-checks.sechecker
@@ -0,0 +1,74 @@
+<sechecker version="1.1">
+<profile>
+ <module name="find_domains">
+ <output value="quiet"/>
+ <option name="domain_attribute">
+ <item value="domain"/>
+ </option>
+ </module>
+
+ <module name="find_file_types">
+ <output value="quiet"/>
+ <option name="file_type_attribute">
+ <item value="file_type"/>
+ </option>
+ </module>
+
+ <module name="attribs_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_types">
+ <output value="short"/>
+ </module>
+
+ <module name="users_wo_roles">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="types_wo_allow">
+ <output value="short"/>
+ </module>
+
+ <module name="attribs_wo_rules">
+ <output value="short"/>
+ </module>
+
+ <module name="roles_wo_users">
+ <output value="short"/>
+ </module>
+
+ <module name="spurious_audit">
+ <output value="short"/>
+ </module>
+
+ <module name="find_net_domains">
+ <output value="quiet"/>
+ <option name="net_obj">
+ <item value="netif"/>
+ <item value="tcp_socket"/>
+ <item value="udp_socket"/>
+ <item value="node"/>
+ <item value="association"/>
+ </option>
+ </module>
+
+ <module name="find_port_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_node_types">
+ <output value="quiet"/>
+ </module>
+
+ <module name="find_netif_types">
+ <output value="quiet"/>
+ </module>
+
+</profile>
+</sechecker>
+
diff --git a/sechecker/profiles/sechecker.dtd b/sechecker/profiles/sechecker.dtd
new file mode 100644
index 0000000..d0aa054
--- /dev/null
+++ b/sechecker/profiles/sechecker.dtd
@@ -0,0 +1,19 @@
+<!ELEMENT item EMPTY>
+<!ATTLIST item value NMTOKEN #REQUIRED>
+
+<!ELEMENT module (output, option?)>
+<!ATTLIST module name ID #REQUIRED>
+
+<!ELEMENT option (item+)>
+<!ATTLIST option name NMTOKEN #REQUIRED>
+
+<!ELEMENT output EMPTY>
+<!ATTLIST output value (quiet|short|verbose|none) #REQUIRED>
+
+<!ELEMENT profile (module+)>
+
+<!ELEMENT sechecker (profile)>
+<!ATTLIST sechecker version NMTOKEN #REQUIRED>
+
+
+
diff --git a/sechecker/register_list.c b/sechecker/register_list.c
new file mode 100644
index 0000000..febc79e
--- /dev/null
+++ b/sechecker/register_list.c
@@ -0,0 +1,102 @@
+/**
+ * @file
+ * Keeps track of the all known sechecker modules.
+ *
+ * @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 "register_list.h"
+
+static size_t sechk_register_num_modules = 0;
+static size_t sechk_register_num_profiles = 0;
+
+/* NULL terminated array of module names and register functions */
+static sechk_module_name_reg_t sechk_module_register_list[] = {
+ {"attribs_wo_rules", &attribs_wo_rules_register},
+ {"attribs_wo_types", &attribs_wo_types_register},
+ {"domain_and_file", &domain_and_file_register},
+ {"domains_wo_roles", &domains_wo_roles_register},
+ {"find_assoc_types", &find_assoc_types_register},
+ {"find_domains", &find_domains_register},
+ {"find_file_types", &find_file_types_register},
+ {"find_net_domains", &find_net_domains_register},
+ {"find_node_types", &find_node_types_register},
+ {"find_netif_types", &find_netif_types_register},
+ {"find_port_types", &find_port_types_register},
+ {"imp_range_trans", &imp_range_trans_register},
+ {"inc_dom_trans", &inc_dom_trans_register},
+ {"inc_mount", &inc_mount_register},
+ {"inc_net_access", &inc_net_access_register},
+ {"roles_wo_allow", &roles_wo_allow_register},
+ {"roles_wo_types", &roles_wo_types_register},
+ {"roles_wo_users", &roles_wo_users_register},
+ /* Deprecated *
+ * {"roles_exp_nothing", &roles_exp_nothing_register},
+ */
+ {"spurious_audit", &spurious_audit_register},
+ {"types_wo_allow", &types_wo_allow_register},
+ {"unreachable_doms", &unreachable_doms_register},
+ {"users_wo_roles", &users_wo_roles_register},
+ /* TODO: add additional register addresses here in alphabetical order */
+
+ {NULL, NULL}
+};
+
+/* NULL terminated array of profiles (name, file, description) */
+static sechk_profile_name_reg_t sechk_profile_register_list[] = {
+ {"analysis", "analysis-checks.sechecker", "common analysis checks"},
+ {"development", "devel-checks.sechecker", "common development checks"},
+ {"all", "all-checks.sechecker", "all available checks"},
+ {"all-no-mls", "all-checks-no-mls.sechecker", "all available checks not requiring MLS"},
+ /* TODO: add more profiles */
+
+ {NULL, NULL, NULL}
+};
+
+size_t sechk_register_list_get_num_profiles()
+{
+ size_t i;
+ if (sechk_register_num_profiles != 0)
+ return sechk_register_num_profiles;
+ for (i = 0; sechk_profile_register_list[i].name != NULL; i++) ;
+
+ sechk_register_num_profiles = i;
+ return sechk_register_num_profiles;
+}
+
+const sechk_profile_name_reg_t *sechk_register_list_get_profiles()
+{
+ return sechk_profile_register_list;
+}
+
+size_t sechk_register_list_get_num_modules()
+{
+ size_t i;
+ if (sechk_register_num_modules != 0)
+ return sechk_register_num_modules;
+ for (i = 0; sechk_module_register_list[i].name != NULL; i++) ;
+
+ sechk_register_num_modules = i;
+ return sechk_register_num_modules;
+}
+
+const sechk_module_name_reg_t *sechk_register_list_get_modules()
+{
+ return sechk_module_register_list;
+}
diff --git a/sechecker/register_list.h b/sechecker/register_list.h
new file mode 100644
index 0000000..0a0a6fc
--- /dev/null
+++ b/sechecker/register_list.h
@@ -0,0 +1,64 @@
+/* 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
+ */
+
+/*
+ * Author: jmowery@tresys.com
+ *
+ */
+
+#ifndef SECHK_REGISTER_LIST_H
+#define SECHK_REGISTER_LIST_H
+
+#include "sechecker.h"
+
+/* TODO: to add a module declare it's register function as
+ * extern int <module_name>_register(sechk_lib_t *lib);
+ * here and add it's address to the array in register_list.c
+ * don't forget to add any necessary options to the config file */
+
+/* extern register functions declarations */
+extern int find_domains_register(sechk_lib_t * lib);
+extern int find_file_types_register(sechk_lib_t * lib);
+extern int domain_and_file_register(sechk_lib_t * lib);
+extern int attribs_wo_types_register(sechk_lib_t * lib);
+extern int roles_wo_types_register(sechk_lib_t * lib);
+extern int users_wo_roles_register(sechk_lib_t * lib);
+extern int roles_wo_allow_register(sechk_lib_t * lib);
+extern int types_wo_allow_register(sechk_lib_t * lib);
+extern int spurious_audit_register(sechk_lib_t * lib);
+extern int attribs_wo_rules_register(sechk_lib_t * lib);
+extern int inc_mount_register(sechk_lib_t * lib);
+extern int roles_wo_users_register(sechk_lib_t * lib);
+/* Deprecated *
+ extern int rules_exp_nothing_register(sechk_lib_t *lib);
+*/
+extern int domains_wo_roles_register(sechk_lib_t * lib);
+extern int inc_dom_trans_register(sechk_lib_t * lib);
+extern int find_port_types_register(sechk_lib_t * lib);
+extern int find_node_types_register(sechk_lib_t * lib);
+extern int find_netif_types_register(sechk_lib_t * lib);
+extern int find_assoc_types_register(sechk_lib_t * lib);
+extern int find_net_domains_register(sechk_lib_t * lib);
+extern int inc_net_access_register(sechk_lib_t * lib);
+extern int unreachable_doms_register(sechk_lib_t * lib);
+extern int imp_range_trans_register(sechk_lib_t * lib);
+/* TODO: additional externs go here ... */
+
+size_t sechk_register_list_get_num_modules(void);
+const sechk_module_name_reg_t *sechk_register_list_get_modules(void);
+size_t sechk_register_list_get_num_profiles(void);
+const sechk_profile_name_reg_t *sechk_register_list_get_profiles(void);
+#endif /* SECHK_REGISTER_LIST_H */
diff --git a/sechecker/sechecker.c b/sechecker/sechecker.c
new file mode 100644
index 0000000..57bb7f1
--- /dev/null
+++ b/sechecker/sechecker.c
@@ -0,0 +1,1230 @@
+/**
+ * @file
+ * Implementation of the public interface for all sechecker modules
+ * and the library.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2008 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sechecker.h"
+#include "register_list.h"
+#include "sechk_parse.h"
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <apol/policy.h>
+#include <apol/util.h>
+#include <apol/vector.h>
+
+#include <sefs/util.h>
+#include <sefs/fcfile.hh>
+#include <sefs/query.hh>
+
+#ifdef LIBSELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include <qpol/policy.h>
+#include <qpol/util.h>
+
+static int sechk_lib_compare_sev(const char *a, const char *b)
+{
+ int aval, bval;
+
+ if (a == NULL || b == NULL) {
+ assert(false);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strcmp(a, SECHK_SEV_NONE) == 0)
+ aval = 0;
+ else if (strcmp(a, SECHK_SEV_LOW) == 0)
+ aval = 1;
+ else if (strcmp(a, SECHK_SEV_MED) == 0)
+ aval = 2;
+ else if (strcmp(a, SECHK_SEV_HIGH) == 0)
+ aval = 3;
+ else {
+ assert(false);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strcmp(b, SECHK_SEV_NONE) == 0)
+ bval = 0;
+ else if (strcmp(b, SECHK_SEV_LOW) == 0)
+ bval = 1;
+ else if (strcmp(b, SECHK_SEV_MED) == 0)
+ bval = 2;
+ else if (strcmp(b, SECHK_SEV_HIGH) == 0)
+ bval = 3;
+ else {
+ assert(false);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (aval == bval)
+ return 0;
+
+ return aval < bval ? -1 : 1;
+}
+
+int sechk_lib_set_minsev(const char *minsev, sechk_lib_t * lib)
+{
+ if (lib == NULL || lib->policy == NULL || minsev == NULL) {
+ assert(false);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strcmp(minsev, SECHK_SEV_LOW) == 0)
+ lib->minsev = SECHK_SEV_LOW;
+ else if (strcmp(minsev, SECHK_SEV_MED) == 0)
+ lib->minsev = SECHK_SEV_MED;
+ else if (strcmp(minsev, SECHK_SEV_HIGH) == 0)
+ lib->minsev = SECHK_SEV_HIGH;
+ else {
+ ERR(lib->policy, "%s", "Invalid severity.");
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+sechk_module_t *sechk_module_new(void)
+{
+ sechk_module_t *mod = NULL;
+ int error = 0;
+
+ mod = calloc(1, sizeof(sechk_module_t));
+ if (!mod)
+ return NULL;
+
+ /* create empty vectors */
+ if (!(mod->options = apol_vector_create(sechk_name_value_free)) ||
+ !(mod->requirements = apol_vector_create(sechk_name_value_free)) ||
+ !(mod->dependencies = apol_vector_create(sechk_name_value_free))
+ || !(mod->functions = apol_vector_create(sechk_fn_free))) {
+ error = errno;
+ apol_vector_destroy(&mod->options);
+ apol_vector_destroy(&mod->requirements);
+ apol_vector_destroy(&mod->dependencies);
+ apol_vector_destroy(&mod->functions);
+ free(mod);
+ errno = error;
+ return NULL;
+ }
+
+ return mod;
+}
+
+sechk_lib_t *sechk_lib_new(void)
+{
+ sechk_lib_t *lib = NULL;
+ int retv, error;
+ const sechk_module_name_reg_t *reg_list;
+ size_t num_known_modules = 0;
+ size_t i = 0;
+ sechk_module_t *tmp = NULL;
+
+ /* allocate the new sechk_lib_t structure */
+ lib = (sechk_lib_t *) calloc(1, sizeof(sechk_lib_t));
+ if (!lib) {
+ error = errno;
+ perror("Error creating module library");
+ goto exit_err;
+ }
+
+ /* create the module array from the known modules in register list */
+ num_known_modules = sechk_register_list_get_num_modules();
+ reg_list = sechk_register_list_get_modules();
+ lib->modules = apol_vector_create(sechk_module_free);
+ if (!lib->modules) {
+ error = errno;
+ perror("Error adding modules");
+ goto exit_err;
+
+ }
+ for (i = 0; i < num_known_modules; i++) {
+ tmp = sechk_module_new();
+ if (!tmp) {
+ error = errno;
+ perror("Error adding modules");
+ goto exit_err;
+ }
+ tmp->name = strdup(reg_list[i].name);
+ if (!tmp->name) {
+ error = errno;
+ perror("Error adding modules");
+ goto exit_err;
+ }
+ if (apol_vector_append(lib->modules, tmp)) {
+ error = errno;
+ perror("Error adding modules");
+ goto exit_err;
+ }
+ tmp = NULL;
+ }
+
+ /* set the default output format */
+ lib->outputformat = SECHK_OUT_SHORT;
+ lib->minsev = SECHK_SEV_LOW;
+
+ /* register modules */
+ if ((retv = sechk_lib_register_modules(reg_list, lib)) != 0) {
+ error = errno;
+ perror("Error registering modules");
+ goto exit_err;
+ }
+ exit:
+ return lib;
+
+ exit_err:
+ sechk_lib_destroy(&lib);
+ sechk_module_free(tmp);
+ errno = error;
+ goto exit;
+}
+
+void sechk_lib_destroy(sechk_lib_t ** lib)
+{
+ if (lib == NULL || *lib == NULL)
+ return;
+
+ apol_vector_destroy(&((*lib)->modules));
+ apol_policy_destroy(&((*lib)->policy));
+ apol_vector_destroy(&((*lib)->fc_entries));
+ free((*lib)->fc_path);
+ sefs_fclist_destroy(&((*lib)->fc_file));
+ free((*lib)->selinux_config_path);
+ apol_policy_path_destroy(&((*lib)->policy_path));
+ free(*lib);
+ *lib = NULL;
+}
+
+void sechk_module_free(void *module)
+{
+ sechk_module_t *mod = (sechk_module_t *) module;
+
+ if (!module)
+ return;
+
+ /* do not free describtin fields */
+ sechk_result_destroy(&mod->result);
+ apol_vector_destroy(&mod->options);
+ apol_vector_destroy(&mod->requirements);
+ apol_vector_destroy(&mod->dependencies);
+ /* do not free severity */
+ if (mod->data) {
+ assert(mod->data_free);
+ mod->data_free(mod->data);
+ }
+ free(mod->name);
+ mod->name = NULL;
+ apol_vector_destroy(&mod->functions);
+ free(mod);
+}
+
+void sechk_fn_free(void *fn_struct)
+{
+ sechk_fn_t *fn = (sechk_fn_t *) fn_struct;
+ if (!fn_struct)
+ return;
+
+ free(fn->name);
+ /* NEVER free fn->fn */
+ free(fn);
+}
+
+void sechk_name_value_free(void *nv)
+{
+ sechk_name_value_t *in = (sechk_name_value_t *) nv;
+ if (!nv)
+ return;
+
+ free(in->name);
+ free(in->value);
+ free(nv);
+}
+
+void sechk_result_destroy(sechk_result_t ** res)
+{
+ if (!res || !(*res))
+ return;
+
+ free((*res)->test_name);
+ apol_vector_destroy(&((*res)->items));
+ free(*res);
+ *res = NULL;
+}
+
+void sechk_item_free(void *item)
+{
+ sechk_item_t *it = (sechk_item_t *) item;
+
+ if (!item)
+ return;
+
+ apol_vector_destroy(&it->proof);
+ if (it->item_free_fn)
+ it->item_free_fn(it->item);
+
+ free(item);
+}
+
+void sechk_proof_free(void *proof)
+{
+ sechk_proof_t *p = (sechk_proof_t *) proof;
+
+ if (!proof)
+ return;
+
+ free(p->text);
+ free(p->xml_out);
+
+ if (p->elem_free_fn)
+ p->elem_free_fn(p->elem);
+
+ free(proof);
+}
+
+sechk_fn_t *sechk_fn_new(void)
+{
+ /* no initialization needed here */
+ return (sechk_fn_t *) calloc(1, sizeof(sechk_fn_t));
+}
+
+sechk_name_value_t *sechk_name_value_new(const char *name, const char *value)
+{
+ sechk_name_value_t *nv;
+ int error;
+
+ nv = (sechk_name_value_t *) calloc(1, sizeof(sechk_name_value_t));
+ if (!nv)
+ return NULL;
+ if (name) {
+ nv->name = strdup(name);
+ if (!nv->name) {
+ error = errno;
+ goto err;
+ }
+ }
+ if (value) {
+ nv->value = strdup(value);
+ if (!nv->value) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ return nv;
+
+ err:
+ free(nv->name);
+ free(nv);
+ errno = error;
+ return NULL;
+}
+
+sechk_result_t *sechk_result_new(void)
+{
+ /* initilization to zero is sufficient here */
+ return (sechk_result_t *) calloc(1, sizeof(sechk_result_t));
+}
+
+sechk_item_t *sechk_item_new(free_fn_t fn)
+{
+ sechk_item_t *it = NULL;
+
+ it = (sechk_item_t *) calloc(1, sizeof(sechk_item_t));
+ if (!it)
+ return NULL;
+ it->item_free_fn = fn;
+
+ return it;
+}
+
+sechk_proof_t *sechk_proof_new(free_fn_t fn)
+{
+ sechk_proof_t *proof = NULL;
+ proof = (sechk_proof_t *) calloc(1, sizeof(sechk_proof_t));
+ if (!proof)
+ return NULL;
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem_free_fn = fn;
+ return proof;
+}
+
+int sechk_lib_load_policy(apol_policy_path_t * policy_mods, sechk_lib_t * lib)
+{
+
+ char *default_policy_path = NULL;
+ int retv = -1;
+
+ if (!lib)
+ return -1;
+
+ /* if no policy is given, attempt to find default */
+ if (!policy_mods) {
+ retv = qpol_default_policy_find(&default_policy_path);
+ if (retv < 0) {
+ fprintf(stderr, "Default policy search failed: %s\n", strerror(errno));
+ return -1;
+ } else if (retv != 0) {
+ fprintf(stderr, "No default policy found.\n");
+ return -1;
+ }
+ policy_mods = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, default_policy_path, NULL);
+ lib->policy = apol_policy_create_from_policy_path(policy_mods, QPOL_POLICY_OPTION_MATCH_SYSTEM, NULL, NULL);
+ if (lib->policy == NULL) {
+ fprintf(stderr, "Error: failed opening default policy\n");
+ return -1;
+ }
+ lib->policy_path = policy_mods;
+ if (!(lib->outputformat & SECHK_OUT_QUIET)) {
+ fprintf(stderr, "Using policy: %s\n", apol_policy_path_get_primary(lib->policy_path));
+ }
+ } else {
+ lib->policy_path = policy_mods;
+ lib->policy = apol_policy_create_from_policy_path(policy_mods, 0, NULL, NULL);
+ if (lib->policy == NULL) {
+ fprintf(stderr, "Error: failed opening policy %s\n", apol_policy_path_to_string(lib->policy_path));
+ goto err;
+ }
+ }
+ return 0;
+
+ err:
+ apol_policy_destroy(&lib->policy);
+ return -1;
+}
+
+int sechk_lib_load_fc(const char *fcfilelocation, sechk_lib_t * lib)
+{
+ int error = 0;
+ char *default_fc_path = NULL;
+ sefs_fclist_t *fcfile = NULL;
+ sefs_query_t *q = NULL;
+
+ /* if no policy we can't parse the fc file */
+ if (!lib || !lib->policy) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if no file_contexts file is given attempt to find the default */
+ if (!fcfilelocation) {
+ default_fc_path = sefs_default_file_contexts_get_path();
+ if (default_fc_path == NULL) {
+ error = errno;
+ WARN(lib->policy, "Unable to find default file_contexts file: %s", strerror(error));
+ errno = error;
+ return 0; /* not fatal error until a module requires this to exist */
+ }
+ if (strcmp(default_fc_path, "") == 0) {
+ WARN(lib->policy, "%s", "The system has no default file_contexts file.");
+ free(default_fc_path);
+ errno = ENOSYS;
+ return 0; /* not fatal error until a module requires this to exist */
+ }
+ fcfile = sefs_fcfile_create_from_file(default_fc_path, NULL, NULL);
+ q = sefs_query_create();
+ lib->fc_entries = sefs_fclist_run_query(fcfile, q);
+ if (!(lib->fc_entries)) {
+ error = errno;
+ WARN(lib->policy, "Unable to process file_contexts file %s.", default_fc_path);
+ free(default_fc_path);
+ errno = error;
+ return -1;
+ } else {
+ lib->fc_path = default_fc_path;
+ lib->fc_file = fcfile;
+ }
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ fprintf(stderr, "Using file contexts: %s\n", lib->fc_path);
+ }
+ } else {
+ fcfile = sefs_fcfile_create_from_file(fcfilelocation, NULL, NULL);
+ q = sefs_query_create();
+ lib->fc_entries = sefs_fclist_run_query(fcfile, q);
+ if (!(lib->fc_entries)) {
+ error = errno;
+ WARN(lib->policy, "Unable to process file_contexts file %s.", fcfilelocation);
+ errno = error;
+ return -1;
+ } else {
+ lib->fc_path = strdup(fcfilelocation);
+ lib->fc_file = fcfile;
+ }
+ }
+ sefs_query_destroy(&q);
+
+ return 0;
+}
+
+int sechk_lib_register_modules(const sechk_module_name_reg_t * register_fns, sechk_lib_t * lib)
+{
+ int retv, error = 0;
+ size_t i;
+ sechk_register_fn_t fn = NULL;
+ if (!register_fns || !lib) {
+ fprintf(stderr, "Error: could not register modules\n");
+ errno = EINVAL;
+ return -1;
+ }
+ if (apol_vector_get_size(lib->modules) != sechk_register_list_get_num_modules()) {
+ fprintf(stderr,
+ "Error: the number of registered modules (%zd) does not match the number of modules in the configuration file (%zd).\n",
+ sechk_register_list_get_num_modules(), apol_vector_get_size(lib->modules));
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ fn = (sechk_register_fn_t) (register_fns[i].fn);
+ retv = fn(lib);
+ if (retv) {
+ error = errno;
+ fprintf(stderr, "Error: could not register module #%zd\n", i);
+ errno = error;
+ return retv;
+ }
+ }
+
+ return 0;
+}
+
+sechk_mod_fn_t sechk_lib_get_module_function(const char *module_name, const char *function_name, const sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ size_t i;
+
+ if (!module_name || !function_name || !lib) {
+ fprintf(stderr, "Error: failed to get function from module\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* find the correct module */
+ mod = sechk_lib_get_module(module_name, lib);
+ if (!mod) {
+ fprintf(stderr, "Error: %s: no such module\n", module_name);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* find function in module */
+ for (i = 0; i < apol_vector_get_size(mod->functions); i++) {
+ fn_struct = apol_vector_get_element(mod->functions, i);
+ if (!strcmp(fn_struct->name, function_name))
+ break;
+ else
+ fn_struct = NULL;
+ }
+ if (!fn_struct) {
+ fprintf(stderr, "Error: %s: no such function in module %s\n", function_name, module_name);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ return fn_struct->fn;
+}
+
+sechk_module_t *sechk_lib_get_module(const char *module_name, const sechk_lib_t * lib)
+{
+ size_t i;
+ sechk_module_t *mod = NULL;
+
+ if (!module_name || !lib) {
+ fprintf(stderr, "Error: failed to get module\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!(mod->name))
+ continue;
+ if (!strcmp(mod->name, module_name))
+ return mod;
+ }
+ fprintf(stderr, "Error: %s: no such module\n", module_name);
+ errno = ENOENT;
+ return NULL;
+}
+
+sechk_result_t *sechk_lib_get_module_result(const char *module_name, const sechk_lib_t * lib)
+{
+ size_t i;
+ sechk_module_t *mod = NULL;
+ sechk_mod_fn_t run = NULL;
+
+ if (!module_name || !lib) {
+ fprintf(stderr, "Error: failed to get module result\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!(mod->name))
+ continue;
+ if (strcmp(mod->name, module_name))
+ continue;
+ if (!(mod->result)) {
+ if (!(run = sechk_lib_get_module_function(module_name, SECHK_MOD_FN_RUN, lib)) ||
+ run(mod, lib->policy, NULL) < 0) {
+ return NULL; /* run or get function will set errno */
+ }
+ }
+ return mod->result;
+ }
+ fprintf(stderr, "Error: %s: no such module\n", module_name);
+ errno = ENOENT;
+ return NULL;
+}
+
+int sechk_lib_check_module_dependencies(sechk_lib_t * lib)
+{
+ int idx = 0;
+ size_t i, j;
+ bool test = true, done = false, *processed = NULL;
+ sechk_name_value_t *nv = NULL;
+ sechk_module_t *mod = NULL, *dep = NULL;
+
+ if (!lib) {
+ fprintf(stderr, "Error: invalid module library\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ processed = (bool *) calloc(apol_vector_get_size(lib->modules), sizeof(bool));
+ if (!processed) {
+ perror(NULL);
+ return -1;
+ }
+
+ /* check dependencies and select dependencies to be run */
+ while (!done) {
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ if (processed[i])
+ continue;
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!mod->selected) {
+ processed[i] = true;
+ continue;
+ }
+ for (j = 0; j < apol_vector_get_size(mod->dependencies); j++) {
+ nv = apol_vector_get_element(mod->dependencies, j);
+ test = false;
+ test = sechk_lib_check_dependency(nv, lib);
+ if (!test) {
+ ERR(lib->policy, "Dependency %s not found for %s.", nv->name, mod->name);
+ free(processed);
+ errno = ENOENT;
+ return -1;
+ }
+ idx = sechk_lib_get_module_idx(nv->value, lib);
+ dep = apol_vector_get_element(lib->modules, idx);
+ if (!dep->selected) {
+ processed[idx] = false;
+ dep->selected = true;
+ }
+ }
+ processed[i] = true;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ if (!processed[i])
+ break;
+ }
+ if (i == apol_vector_get_size(lib->modules))
+ done = true;
+ }
+ free(processed);
+
+ return 0;
+}
+
+int sechk_lib_check_module_requirements(sechk_lib_t * lib)
+{
+ int retv = 0;
+ size_t i, j;
+ bool test = true;
+ sechk_name_value_t *nv = NULL;
+ sechk_module_t *mod = NULL;
+
+ /* check requirements for all selected modules */
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!mod->selected)
+ continue;
+ for (j = 0; j < apol_vector_get_size(mod->requirements); j++) {
+ nv = apol_vector_get_element(mod->requirements, j);
+ test = false;
+ test = sechk_lib_check_requirement(nv, lib);
+ if (!test) {
+ /* if we're in quiet mode then we quit on a failed requirement */
+ if (lib->outputformat & (SECHK_OUT_QUIET)) {
+ errno = ENOTSUP;
+ return -1;
+ } else {
+ /* otherwise we just disable this module and keep testing */
+ ERR(lib->policy, "Requirements not met for %s.", mod->name);
+ mod->selected = false;
+ retv = -1;
+ break;
+ }
+ }
+ }
+ }
+ return retv;
+}
+
+int sechk_lib_init_modules(sechk_lib_t * lib)
+{
+ int retv, error = 0;
+ size_t i;
+ sechk_module_t *mod = NULL;
+ sechk_mod_fn_t init_fn = NULL;
+
+ if (lib == NULL || lib->modules == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!mod->selected)
+ continue;
+ init_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_INIT, lib);
+ if (!init_fn) {
+ error = errno;
+ fprintf(stderr, "Error: could not initialize module %s\n", mod->name);
+ errno = error;
+ return -1;
+ }
+ retv = init_fn(mod, lib->policy, NULL);
+ if (retv)
+ return retv;
+ }
+
+ return 0;
+}
+
+int sechk_lib_run_modules(sechk_lib_t * lib)
+{
+ int retv, num_selected = 0, rc = 0;
+ size_t i;
+ sechk_module_t *mod = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+
+ if (!lib) {
+ fprintf(stderr, "Error: invalid library\n");
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (mod->selected)
+ num_selected++;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ /* if module is "off" do not run */
+ if (!mod->selected)
+ continue;
+ /* if module is below the minsev do not run unless its exactly one module */
+ if (lib->minsev && sechk_lib_compare_sev(mod->severity, lib->minsev) < 0 && num_selected != 1)
+ continue;
+ assert(mod->name);
+ run_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_RUN, lib);
+ if (!run_fn) {
+ ERR(lib->policy, "Could not run module %s.", mod->name);
+ errno = ENOTSUP;
+ return -1;
+ }
+ retv = run_fn(mod, lib->policy, NULL);
+
+ if (retv < 0) {
+ /* module failure */
+ /* only put output failures if we are not in quiet mode */
+ if (lib->outputformat & ~(SECHK_OUT_QUIET))
+ ERR(lib->policy, "Module %s failed.", mod->name);
+ rc = -1;
+ } else if (retv > 0) {
+ /* a module looking for policy errors has found one
+ * if in quiet mode stop since running additional
+ * modules will not change the return code */
+ if (lib->outputformat & (SECHK_OUT_QUIET))
+ return -1;
+ }
+ }
+ return rc;
+}
+
+int sechk_lib_print_modules_report(sechk_lib_t * lib)
+{
+ int retv, num_selected = 0, rc = 0;
+ size_t i;
+ sechk_module_t *mod = NULL;
+ sechk_mod_fn_t print_fn = NULL;
+
+ if (!lib) {
+ fprintf(stderr, "Error: invalid library\n");
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (mod->selected)
+ num_selected++;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ /* if module is "off" or its output format is quiet continue */
+ if (!mod->selected || mod->outputformat & SECHK_OUT_QUIET)
+ continue;
+ /* if module is below the minsev do not print unless exactly one module is selected */
+ if (lib->minsev && sechk_lib_compare_sev(mod->severity, lib->minsev) < 0 && num_selected != 1)
+ continue;
+ /* if module is the only selected one make sure output is generated */
+ if (mod->outputformat == SECHK_OUT_NONE && num_selected == 1)
+ mod->outputformat = SECHK_OUT_SHORT;
+ assert(mod->name);
+ printf("\nModule name: %s\tSeverity: %s\n%s\n", mod->name, mod->severity, mod->detailed_description);
+ print_fn = sechk_lib_get_module_function(mod->name, SECHK_MOD_FN_PRINT, lib);
+ if (!print_fn) {
+ ERR(lib->policy, "Could not get print function for module %s.", mod->name);
+ errno = ENOTSUP;
+ return -1;
+ }
+ retv = print_fn(mod, lib->policy, NULL);
+ if (retv) {
+ fprintf(stderr, "Error: unable to print results for module %s \n", mod->name);
+ rc = -1;
+ }
+ }
+
+ return rc;
+}
+
+bool sechk_lib_check_requirement(sechk_name_value_t * req, sechk_lib_t * lib)
+{
+ struct stat stat_buf;
+
+ if (!req) {
+ fprintf(stderr, "Error: invalid requirement\n");
+ errno = EINVAL;
+ return false;
+ }
+
+ if (!lib || !lib->policy) {
+ fprintf(stderr, "Error: invalid library\n");
+ errno = EINVAL;
+ return false;
+ }
+
+ if (!strcmp(req->name, SECHK_REQ_POLICY_CAP)) {
+ if (!strcmp(req->value, SECHK_REQ_CAP_ATTRIB_NAMES)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_ATTRIB_NAMES)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_MLS)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_MLS)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_SYN_RULES)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_SYN_RULES)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_RULES_LOADED)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_RULES_LOADED)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_LINE_NOS)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_LINE_NUMBERS)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_CONDITIONALS)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_CONDITIONALS)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else if (!strcmp(req->value, SECHK_REQ_CAP_MODULES)) {
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(lib->policy), QPOL_CAP_MODULES)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ }
+ return false;
+ }
+ } else {
+ ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value);
+ return false;
+ }
+ } else if (!strcmp(req->name, SECHK_REQ_DEFAULT_CONTEXTS)) {
+#ifdef LIBSELINUX
+ if (stat(selinux_default_context_path(), &stat_buf) < 0) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s not met.", req->name);
+ }
+ return false;
+ }
+#else
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Checking requirement %s: %s", req->name, strerror(ENOTSUP));
+ }
+ return false;
+#endif
+ } else if (!strcmp(req->name, SECHK_REQ_FILE_CONTEXTS)) {
+ if (!lib->fc_entries || !apol_vector_get_size(lib->fc_entries)) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET)) {
+ ERR(lib->policy, "Requirement %s not met.", req->name);
+ }
+ }
+ } else if (!strcmp(req->name, SECHK_REQ_SYSTEM)) {
+ if (!strcmp(req->value, SECHK_REQ_SYS_SELINUX)) {
+#ifdef LIBSELINUX
+ if (!is_selinux_mls_enabled() || !is_selinux_enabled()) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET))
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ return false;
+ }
+#else
+ if (lib->outputformat & ~(SECHK_OUT_QUIET))
+ ERR(lib->policy, "Checking requirement %s, %s: %s", req->name, req->value, strerror(ENOTSUP));
+ return false;
+#endif
+ } else if (!strcmp(req->value, SECHK_REQ_SYS_MLS)) {
+#ifdef LIBSELINUX
+ if (!is_selinux_mls_enabled() || !is_selinux_enabled()) {
+ if (lib->outputformat & ~(SECHK_OUT_QUIET))
+ ERR(lib->policy, "Requirement %s, %s not met.", req->name, req->value);
+ return false;
+ }
+#else
+ if (lib->outputformat & ~(SECHK_OUT_QUIET))
+ ERR(lib->policy, "Checking requirement %s, %s: %s", req->name, req->value, strerror(ENOTSUP));
+ return false;
+#endif
+ } else {
+ ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value);
+ return false;
+ }
+ } else {
+ ERR(lib->policy, "Unknown requirement: %s, %s", req->name, req->value);
+ return false;
+ }
+
+ return true;
+}
+
+bool sechk_lib_check_dependency(sechk_name_value_t * dep, sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+
+ if (!dep || !dep->value) {
+ fprintf(stderr, "Error: invalid dependency\n");
+ errno = EINVAL;
+ return false;
+ }
+
+ if (!lib) {
+ fprintf(stderr, "Error: invalid library\n");
+ errno = EINVAL;
+ return false;
+ }
+
+ mod = sechk_lib_get_module(dep->value, lib);
+ if (!mod) {
+ fprintf(stderr, "Error: could not find dependency %s\n", dep->value);
+ errno = ENOENT;
+ return false;
+ }
+
+ return true;
+}
+
+int sechk_lib_set_outputformat(unsigned char out, sechk_lib_t * lib)
+{
+ size_t i;
+ sechk_module_t *mod = NULL;
+
+ if (!lib || !out) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ lib->outputformat = out;
+
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ mod->outputformat = out;
+ }
+
+ return 0;
+}
+
+sechk_proof_t *sechk_proof_copy(sechk_proof_t * orig)
+{
+ sechk_proof_t *copy = NULL;
+
+ if (!orig)
+ return NULL;
+
+ copy = sechk_proof_new(orig->elem_free_fn);
+ if (!copy) {
+ fprintf(stderr, "Error: out of memory\n");
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ copy->elem = orig->elem;
+ copy->type = orig->type;
+ copy->text = strdup(orig->text);
+ if (!copy->text) {
+ fprintf(stderr, "Error: out of memory\n");
+ errno = ENOMEM;
+ return NULL;
+ }
+ copy->xml_out = NULL; /* TODO: do xml string copy here */
+
+ return copy;
+}
+
+int sechk_lib_load_profile(const char *prof_name, sechk_lib_t * lib)
+{
+ const sechk_profile_name_reg_t *profiles;
+ char *profpath = NULL, *prof_filename = NULL, *path = NULL;
+ int retv = -1, error = 0;
+ size_t num_profiles, i;
+ sechk_module_t *mod = NULL;
+
+ if (!prof_name || !lib) {
+ fprintf(stderr, "Error: invalid parameters to load profile\n");
+ return -1;
+ }
+
+ /* try to find the profile in our known profiles */
+ profiles = sechk_register_list_get_profiles();
+ num_profiles = sechk_register_list_get_num_profiles();
+ for (i = 0; i < num_profiles; i++) {
+ if (strcmp(profiles[i].name, prof_name) == 0) {
+ break;
+ }
+ }
+ /* this is a known installed profile, look for it in that directory */
+ if (i < num_profiles) {
+ /* first look in the local subdir using just PROF_SUBDIR/profile */
+ prof_filename = (char *)calloc(strlen(profiles[i].file) + 4 + strlen(PROF_SUBDIR), sizeof(char));
+ if (!prof_filename) {
+ fprintf(stderr, "Error: out of memory\n");
+ errno = ENOMEM;
+ return -1;
+ }
+ sprintf(prof_filename, "%s/%s", PROF_SUBDIR, profiles[i].file);
+ path = apol_file_find(prof_filename);
+ if (!path) {
+ free(prof_filename);
+ prof_filename = NULL;
+ prof_filename = (char *)calloc(strlen(PROFILE_INSTALL_DIR) + strlen(profiles[i].file) + 4, sizeof(char));
+ if (!prof_filename) {
+ fprintf(stderr, "Error: out of memory\n");
+ errno = ENOMEM;
+ return -1;
+ }
+ sprintf(prof_filename, "%s/%s", PROFILE_INSTALL_DIR, profiles[i].file);
+ path = apol_file_find(prof_filename);
+ if (!path) {
+ fprintf(stderr, "Error: Unable to find path\n");
+ error = ENOENT;
+ goto sechk_load_profile_error;
+ }
+ }
+
+ /* concatenate path and filename */
+ profpath = (char *)calloc(3 + strlen(path) + strlen(prof_filename), sizeof(char));
+ if (!profpath) {
+ fprintf(stderr, "Error: out of memory\n");
+ error = ENOMEM;
+ goto sechk_load_profile_error;
+ }
+ sprintf(profpath, "%s/%s", path, prof_filename);
+ free(path);
+ free(prof_filename);
+ path = NULL;
+ prof_filename = NULL;
+ } else {
+ profpath = strdup(prof_name);
+ }
+
+ /* parse the profile */
+ retv = sechk_lib_parse_profile(profpath, lib);
+ if (retv) {
+ error = errno;
+ fprintf(stderr, "Error: could not parse profile\n");
+ goto sechk_load_profile_error;
+ }
+
+ /* turn off output for any unselected modules */
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (!mod->selected)
+ mod->outputformat = SECHK_OUT_NONE;
+ }
+
+ free(profpath);
+ free(prof_filename);
+ free(path);
+ return 0;
+
+ sechk_load_profile_error:
+ free(profpath);
+ free(prof_filename);
+ free(path);
+ errno = error;
+ return -1;
+}
+
+static int sechk_option_name_compare(const void *a, const void *b, void *data __attribute__ ((unused)))
+{
+ sechk_name_value_t *in_a, *in_b;
+
+ in_a = (sechk_name_value_t *) a;
+ in_b = (sechk_name_value_t *) b;
+
+ return strcmp(in_a->name, in_b->name);
+}
+
+int sechk_lib_module_clear_option(sechk_module_t * module, char *option)
+{
+ apol_vector_t *new_opts = NULL;
+ sechk_name_value_t *needle = NULL, *nv = NULL, *tmp = NULL;
+ int error = 0;
+ size_t i = 0;
+
+ if (!module || !option) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!(needle = sechk_name_value_new(option, NULL))) {
+ error = errno;
+ ERR(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ /* if not here nothing to do */
+ if (apol_vector_get_index(module->options, needle, sechk_option_name_compare, NULL, &i) < 0) {
+ sechk_name_value_free(needle);
+ return 0;
+ }
+
+ if (!(new_opts = apol_vector_create(sechk_name_value_free))) {
+ error = errno;
+ ERR(module->parent_lib->policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ /* add all options of a different name to a new vector to replace the old */
+ for (i = 0; i < apol_vector_get_size(module->options); i++) {
+ nv = apol_vector_get_element(module->options, i);
+ if (strcmp(nv->name, needle->name)) {
+ if (!(tmp = sechk_name_value_new(nv->name, nv->value))) {
+ error = errno;
+ WARN(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error));
+ goto err;
+ }
+ if (apol_vector_append(new_opts, (void *)tmp)) {
+ error = errno;
+ WARN(module->parent_lib->policy, "Clearing option %s: %s.", option, strerror(error));
+ goto err;
+ }
+ tmp = NULL; /* avoid double free */
+ }
+ }
+
+ sechk_name_value_free(needle);
+ apol_vector_destroy(&module->options);
+ module->options = new_opts;
+
+ return 0;
+
+ err:
+ sechk_name_value_free(tmp);
+ sechk_name_value_free(needle);
+ apol_vector_destroy(&new_opts);
+ errno = error;
+ return -1;
+}
+
+/* get the index of a module in the library by name */
+int sechk_lib_get_module_idx(const char *name, sechk_lib_t * lib)
+{
+ size_t i;
+ sechk_module_t *mod = NULL;
+
+ if (!name || !lib || !lib->modules) {
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ if (mod->name && !strcmp(name, mod->name))
+ return i;
+ }
+ errno = ENOENT;
+ return -1;
+}
+
+int sechk_proof_with_element_compare(const void *in_proof, const void *elem, void *unused __attribute__ ((unused)))
+{
+ const sechk_proof_t *proof = (const sechk_proof_t *)in_proof;
+
+ if (!proof)
+ return 1;
+
+ /* explicit pointer to integer cast */
+ return (int)((char *)proof->elem - (char *)elem);
+}
diff --git a/sechecker/sechecker.h b/sechecker/sechecker.h
new file mode 100644
index 0000000..4f0bd46
--- /dev/null
+++ b/sechecker/sechecker.h
@@ -0,0 +1,695 @@
+/**
+ * @file
+ * Defines the public interface for all sechecker modules and the library.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-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 SECHECKER_H
+#define SECHECKER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <config.h>
+
+#include <stdbool.h>
+
+#include <apol/policy.h>
+#include <apol/policy-path.h>
+#include <apol/policy-query.h>
+#include <apol/vector.h>
+#include <apol/util.h>
+
+#include <sefs/fcfile.hh>
+#include <libxml/xmlstring.h>
+
+/* These should be defined from the make environment */
+#ifndef PROF_SUBDIR
+#define PROF_SUBDIR "/sechecker-profiles"
+#endif
+#ifndef DEFAULT_PROFILE
+#define DEFAULT_PROFILE ""
+#endif
+
+/* defined flags for outformat */
+/* report components */
+#define SECHK_OUT_STATS 0x01
+#define SECHK_OUT_LIST 0x02
+#define SECHK_OUT_PROOF 0x04
+/* mode flags from command line and test profiles */
+/* NOTE: none is only valid in profiles */
+#define SECHK_OUT_NONE 0x00
+#define SECHK_OUT_QUIET 0x20
+#define SECHK_OUT_SHORT (SECHK_OUT_STATS|SECHK_OUT_LIST)
+#define SECHK_OUT_VERBOSE (SECHK_OUT_STATS|SECHK_OUT_PROOF)
+
+ typedef void (*free_fn_t) (void *x);
+
+/* severity categories */
+#define SECHK_SEV_NONE "none"
+#define SECHK_SEV_LOW "low"
+#define SECHK_SEV_MED "med"
+#define SECHK_SEV_HIGH "high"
+
+/* module requirement name strings */
+/** Require that the loaded policy has a given capability;
+ * values should be set as one of SECHK_REQ_CAP_* from below. */
+#define SECHK_REQ_POLICY_CAP "capability"
+/** Require that the running system supports a given feature;
+ * values should be set as one of SECHK_REQ_SYS_* from below. */
+#define SECHK_REQ_SYSTEM "system"
+/** Require a file_contexts file to be loaded.
+ * This requirement has no associated value text. */
+#define SECHK_REQ_FILE_CONTEXTS "file_contexts"
+/** Require a default_contexts file to be loaded.
+ * This requirement has no associated value text. */
+#define SECHK_REQ_DEFAULT_CONTEXTS "default_contexts"
+
+/* policy capability requirement strings: map to QPOL_CAP_* in policy_query.h */
+/** Require that the loaded policy supports attribute names. */
+#define SECHK_REQ_CAP_ATTRIB_NAMES "attribute names"
+/** Require that the loaded policy supports syntactic rules. */
+#define SECHK_REQ_CAP_SYN_RULES "syntactic rules"
+/** Require that the loaded policy supports line numbers. */
+#define SECHK_REQ_CAP_LINE_NOS "line numbers"
+/** Require that the loaded policy supports booleans and conditional statements. */
+#define SECHK_REQ_CAP_CONDITIONALS "conditionals"
+/** Require that the loaded policy supports MLS. */
+#define SECHK_REQ_CAP_MLS "mls"
+/** Require that the loaded policy supports module loading. */
+#define SECHK_REQ_CAP_MODULES "module loading"
+/** Require that the loaded policy includes av/te rules. */
+#define SECHK_REQ_CAP_RULES_LOADED "rules loaded"
+
+/* system requirement strings */
+/** Require that the running system is a SELinux system. */
+#define SECHK_REQ_SYS_SELINUX "selinux"
+/** Require that the running system supports MLS*/
+#define SECHK_REQ_SYS_MLS "mls"
+
+/** item and proof element types to denote casting of the void pointer */
+ typedef enum sechk_item_type
+ {
+ SECHK_ITEM_CLASS, /*!< qpol_class_t */
+ SECHK_ITEM_COMMON, /*!< qpol_common_t */
+ SECHK_ITEM_PERM, /*!< char * representing the permission name */
+ SECHK_ITEM_CONSTR, /*!< qpol_constraint_t */
+ SECHK_ITEM_VTRANS, /*!< qpol_validatetrans_t */
+ SECHK_ITEM_QLEVEL, /*!< qpol_level_t */
+ SECHK_ITEM_CAT, /*!< qpol_cat_t */
+ SECHK_ITEM_QMLSLEVEL, /*!< qpol_mls_level_t */
+ SECHK_ITEM_QMLSRANGE, /*!< qpol_mls_range_t */
+ SECHK_ITEM_AMLSLEVEL, /*!< apol_mls_level_t */
+ SECHK_ITEM_AMLSRANGE, /*!< apol_mls_range_t */
+ SECHK_ITEM_TYPE, /*!< qpol_type_t */
+ SECHK_ITEM_ATTRIB, /*!< qpol_type_t but is an atribute not a type */
+ SECHK_ITEM_ROLE, /*!< qpol_role_t */
+ SECHK_ITEM_USER, /*!< qpol_user_t */
+ SECHK_ITEM_COND, /*!< qpol_cond_t */
+ SECHK_ITEM_AVRULE, /*!< qpol_avrule_t */
+ SECHK_ITEM_TERULE, /*!< qpol_terule_t */
+ SECHK_ITEM_RALLOW, /*!< qpol_role_allow_t */
+ SECHK_ITEM_RTRAMS, /*!< qpol_role_trans_t */
+ SECHK_ITEM_RANGETRANS, /*!< qpol_range_trans_t */
+ SECHK_ITEM_BOOL, /*!< qpol_bool_t */
+ SECHK_ITEM_FSUSE, /*!< qpol_fs_use_t */
+ SECHK_ITEM_GENFSCON, /*!< qpol_genfscon_t */
+ SECHK_ITEM_ISID, /*!< qpol_isid_t */
+ SECHK_ITEM_NETIFCON, /*!< qpol_netifcon_t */
+ SECHK_ITEM_NODECON, /*!< qpol_nodecon_t */
+ SECHK_ITEM_PORTCON, /*!< qpol_portcon_t */
+ SECHK_ITEM_CONTEXT, /*!< qpol_context_t */
+ /* add more here as needed */
+ SECHK_ITEM_FCENT, /*!< sefs_entry_t */
+ SECHK_ITEM_STR, /*!< char* generic string */
+ SECHK_ITEM_DTR, /*!< apol_domain_trans_result_t */
+ SECHK_ITEM_OTHER, /*!< void* data is something else (module specific) */
+ SECHK_ITEM_NONE /*!< there is no proof element only text */
+ } sechk_item_type_e;
+
+/** Module results proof element: This represents a single reason for the
+ * inclusion of an item in the results. */
+ typedef struct sechk_proof
+ {
+ /** Component, rule, or other object relative to the policy */
+ void *elem;
+ /** The type of element stored by this proof */
+ sechk_item_type_e type;
+ /** Description of proof for prining the report */
+ char *text;
+ xmlChar *xml_out; /* currently unused but retained for future use */
+ /** Function to call if elem should be free()'d or NULL */
+ free_fn_t elem_free_fn;
+ } sechk_proof_t;
+
+/** Module results item:
+ * This represents an item for which results were found. */
+ typedef struct sechk_item
+ {
+ /** The policy item */
+ void *item;
+ /** Test result code for this item. This field is reserved for use
+ * only within the module creating the item. */
+ unsigned char test_result;
+ /** Vector of proof elements (of type sechk_proof_t) indicating
+ * why an item appears in the results. */
+ apol_vector_t *proof;
+ /** Function to call if item should be free()'d or NULL */
+ free_fn_t item_free_fn;
+ } sechk_item_t;
+
+/** Module results: This represents the results generated by a module's
+ * run function. This structure is used both to generate the report and
+ * to comunicate with other modules that depend on the generating module. */
+ typedef struct sechk_result
+ {
+ /** Name of the module that created the results. */
+ char *test_name;
+ /** The type of policy item processed by the module. */
+ sechk_item_type_e item_type;
+ /** Vector of items for which results were found (of type sechk_item_t). */
+ apol_vector_t *items;
+ } sechk_result_t;
+
+/** Generic name value pair:
+ * Used for storing options, dependencies and requirements. */
+ typedef struct sechk_name_value
+ {
+ char *name;
+ char *value;
+ } sechk_name_value_t;
+
+/** Module library:
+ * This structure tracks all modules that SEChecker can run,
+ * the policy, and other policy related data. */
+ typedef struct sechk_lib
+ {
+ /** Vector of the modules (of type sechk_module_t) */
+ apol_vector_t *modules;
+ /** The policy to analyze when running modules */
+ apol_policy_t *policy;
+ /** Vector of file contexts data (of type sefs_entry_t). */
+ apol_vector_t *fc_entries;
+ /** File name of the file_contexts file loaded. */
+ char *fc_path;
+ /** The file_contexts file object. */
+ sefs_fclist_t *fc_file;
+ /** The default output format for the report */
+ unsigned char outputformat;
+ /** The path for the selinux configuration file */
+ char *selinux_config_path;
+ /** File name of the policy loaded.*/
+ apol_policy_path_t *policy_path;
+ /** Minimum severity level specified for the report. */
+ const char *minsev;
+ } sechk_lib_t;
+
+ typedef struct sechk_module
+ {
+ /** Unique module name */
+ char *name;
+ /** Brief description of the module */
+ const char *brief_description;
+ /** Detailed description of the module. This should include a listing of
+ * of all steps performed by the module's checks. */
+ const char *detailed_description;
+ /** Description of options, requirements, and dependencies */
+ const char *opt_description;
+ /** Results generated by this module. */
+ sechk_result_t *result;
+ /** Vector (of type sechk_name_value_t) containing all user specified
+ * options for this module. */
+ apol_vector_t *options;
+ /** Vector (of type sechk_name_value_t) containing all conditions required
+ * by the module such as policy version or type. See profile documentation
+ * for a complete listing of possible requirements. */
+ apol_vector_t *requirements;
+ /** Vector (of type sechk_name_value_t) containing a list of modules
+ * which need to run before this module may access their results. */
+ apol_vector_t *dependencies;
+ /** Vector (of type sechk_fn_t) of all functions registered for this module.
+ * All modules are required to have at least three: init, run, and print. */
+ apol_vector_t *functions;
+ /** Default output format for the report. */
+ unsigned char outputformat;
+ /** This field is used by the library to indicate that the user or another
+ * module has selected this module to be run. */
+ bool selected;
+ /** The severity level of this module's results. One of SECHK_SEV_* above. */
+ const char *severity;
+ /** The module's private data. This includes data generated when processing
+ * options and from reading its dependencies' results. */
+ void *data;
+ /** Function to be used to free the private data. */
+ free_fn_t data_free;
+ /** Pointer to the module's parent library. */
+ const sechk_lib_t *parent_lib;
+ } sechk_module_t;
+
+/* Module function signatures */
+/**
+ * Function signature for the function to register a module with the library.
+ *
+ * @param lib The library with which to register.
+ *
+ * @return 0 on success and < 0 on failure; if the call fails, errno will be
+ * set and the library should be destroyed.
+ */
+ typedef int (*sechk_register_fn_t) (sechk_lib_t * lib);
+
+/**
+ * Function signature for functions registed by a module.
+ *
+ * @param mod The module performing the operation.
+ * @param policy The policy accessed by the module.
+ * @param arg Arbitrary third parameter for use by the function.
+ *
+ * @return 0 on success, or < 0 on fatal error. If the call fails,
+ * it is expected to set errno. Special: a run function is permitted
+ * to return > 0 upon finding results; only the run function may return > 0.
+ */
+ typedef int (*sechk_mod_fn_t) (sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+/* Module function names */
+#define SECHK_MOD_FN_INIT "init"
+#define SECHK_MOD_FN_RUN "run"
+#define SECHK_MOD_FN_PRINT "print"
+
+/** Registered function container: used to allow the library and modules
+ * to request functions of a specific name. */
+ typedef struct sechk_fn
+ {
+ /** Name of the function without any module prefix */
+ char *name;
+ /** The function. */
+ sechk_mod_fn_t fn;
+ } sechk_fn_t;
+
+/** Module name registration structure: used when the library tries to
+ * discover all known modules. */
+ typedef struct sechk_module_name_reg
+ {
+ /** The name of the module. */
+ char *name;
+ /** The register function for this module. */
+ sechk_register_fn_t fn;
+ } sechk_module_name_reg_t;
+
+/** Profile name registration structure; used when the library tries to
+ * discover all known installed profiles. */
+ typedef struct sechk_profile_name_reg
+ {
+ /** Name of the profile. */
+ char *name;
+ /** Path of the profile file. */
+ char *file;
+ /** Description of the modules run by the profile. */
+ char *desc;
+ } sechk_profile_name_reg_t;
+
+/* alloc methods */
+
+/**
+ * Create a new module library object.
+ *
+ * @return A newly allocated module library or NULL on ENOMEM.
+ * The caller is responsible for calling sechk_lib_destroy()
+ * to free memory used by the library returned.
+ */
+ sechk_lib_t *sechk_lib_new(void);
+
+/**
+ * Create a new module structure.
+ *
+ * @return A newly allocated module or NULL on ENOMEM.
+ * The caller is resbonsible for calling sechk_module_free()
+ * to free memory used by the module returned.
+ */
+ sechk_module_t *sechk_module_new(void);
+
+/**
+ * Create a new module function structre.
+ *
+ * @return A newly allocated module function structure or NULL on ENOMEM.
+ * The caller is responsible for calling sechk_fn_free() to free memory
+ * used by the function structure returned.
+ */
+ sechk_fn_t *sechk_fn_new(void);
+
+/**
+ * Create and initialize a new name value pair.
+ * The incoming strings are duplicated.
+ *
+ * @param name Name to assign.
+ * @param value Value to assign to name.
+ *
+ * @return A newly allocated name value pair of NULL on error; if the
+ * call fails errno will be set.
+ */
+ sechk_name_value_t *sechk_name_value_new(const char *name, const char *value);
+
+/**
+ * Create a new results structure.
+ *
+ * @return A newly allocated results structure or NULL on ENOMEM.
+ * The caller is responsible for calling sechk_result_destroy() to free
+ * the memory used by the returned result structure.
+ */
+ sechk_result_t *sechk_result_new(void);
+
+/**
+ * Create a new result item.
+ *
+ * @param fn Function to be used to free the item stored.
+ *
+ * @return A newly allocated result item or NULL on ENOMEM.
+ * The caller is responsible for calling sechk_item_free() to free
+ * the memory used by the returned item.
+ */
+ sechk_item_t *sechk_item_new(free_fn_t fn);
+
+/**
+ * Create a new result item proof entry.
+ *
+ * @param fn Function to be used to free the element stored.
+ *
+ * @return A newly allocated proof structure or NULL on ENOMEM.
+ * The caller is responsible for calling sechk_proof_free() to free
+ * the memory used by teh returned proof.
+ */
+ sechk_proof_t *sechk_proof_new(free_fn_t fn);
+
+/* free methods */
+
+/**
+ * Free all memory used by a module library and set it to NULL.
+ *
+ * @param The library to destroy.
+ */
+ void sechk_lib_destroy(sechk_lib_t ** lib);
+
+/**
+ * Free all memory used by a module function structure.
+ *
+ * @param fn_struct The function structure to free.
+ */
+ void sechk_fn_free(void *fn_struct);
+
+/**
+ * Free all memory used by a result structure and set it to NULL.
+ *
+ * @param res The result structure to destroy.
+ */
+ void sechk_result_destroy(sechk_result_t ** res);
+
+/**
+ * Free all memory used by a result item.
+ *
+ * @param item The result item to free.
+ */
+ void sechk_item_free(void *item);
+
+/**
+ * Free all memory used by a result item proof element.
+ *
+ * @param proof The proof element to free.
+ */
+ void sechk_proof_free(void *proof);
+
+/**
+ * Free all memory used by a module.
+ *
+ * @param module The module to free.
+ */
+ void sechk_module_free(void *module);
+
+/**
+ * Free all memory used by a name value pair.
+ *
+ * @param nv The name value pair to free.
+ */
+ void sechk_name_value_free(void *nv);
+
+/* register/check_dep/init/run/print - modules */
+/**
+ * Register all known modules with the library.
+ *
+ * @param regiser_fns NULL terminated array of module registration structures.
+ * @param lib The library with which to register the modules in the array.
+ *
+ * @return 0 on success or < 0 on error; if the call fails, errno will be
+ * set and the library should be destroyed.
+ */
+ int sechk_lib_register_modules(const sechk_module_name_reg_t * register_fns, sechk_lib_t * lib);
+
+/**
+ * Check that the dependencies of all selected modules can be met.
+ * This function will select additional modules if needed by those
+ * already selected to be run.
+ *
+ * @param lib The library containing the modules to check.
+ *
+ * @return 0 on success and < 0 on error; if the call fails,
+ * errno will be set.
+ */
+ int sechk_lib_check_module_dependencies(sechk_lib_t * lib);
+
+/**
+ * Check that the requirements of all selected modules are met. If the
+ * requirements are not met for a module and the library's default reporting
+ * mode is not SECHK_OUT_QUIET, the module will be deselected so that others
+ * might be checked. If the library is set to quiet, this function exits on
+ * the first module found to not meet its requirements. <b>This function
+ * should only be called after sechk_lib_check_module_dependencies()</b>
+ *
+ * @param lib The library containing the modules to check.
+ *
+ * @return 0 on success and < 0 on error; if the call fails,
+ * errno will be set.
+ */
+ int sechk_lib_check_module_requirements(sechk_lib_t * lib);
+
+/**
+ * Initialize all selected modules. <b>This function should only be called
+ * after both sechk_lib_check_module_dependencies() and
+ * sechk_lib_check_module_requirements() have been called.</b>
+ *
+ * @param lib The library containing the modules to initialize.
+ *
+ * @return 0 on success and < 0 on failure; if the call fails, errno will be
+ * set and the library should be destroyed.
+ */
+ int sechk_lib_init_modules(sechk_lib_t * lib);
+
+/**
+ * Run all selected modules. The modules must have been initialized.
+ *
+ * @param lib The library containing the modules to run.
+ *
+ * @return 0 on success or < 0 on error. Note that in quiet mode this
+ * function is considered to fail if a module finds results.
+ */
+ int sechk_lib_run_modules(sechk_lib_t * lib);
+
+/**
+ * Print a report of all selected modules' results to stdout.
+ * Modules must have been run.
+ *
+ * @param lib The library containing the modules with results to print.
+ *
+ * @return 0 on success and < 0 on error.
+ */
+ int sechk_lib_print_modules_report(sechk_lib_t * lib);
+
+/* module accessors */
+
+/**
+ * Find a module in the library.
+ *
+ * @param module_name The name of the module to find.
+ * @param lib The library to search.
+ *
+ * @return A pointer to the module or NULL if not found.
+ */
+ sechk_module_t *sechk_lib_get_module(const char *module_name, const sechk_lib_t * lib);
+
+/**
+ * Get a pointer to a function registered for a module.
+ *
+ * @param module_name Name of the module containing the function.
+ * @param function_name Name of the function with out any module prefix.
+ * @param lib The library containing the module.
+ *
+ * @return A pointer to the requested function, or NULL if either the module
+ * or the function cannot be found.
+ */
+ sechk_mod_fn_t sechk_lib_get_module_function(const char *module_name, const char *function_name, const sechk_lib_t * lib);
+
+/**
+ * Get the results of a module. If the module has not been run, it will be run
+ * and its results will be returned if it succeeds.
+ *
+ * @param module_name Name of the module containing the results.
+ * @param lib The library containing the module.
+ *
+ * @return The requested module's results or NULL on error. If the module
+ * was not previously run and it fails when run by this function, NULL
+ * will be returned. If the call fails, errno will be set.
+ */
+ sechk_result_t *sechk_lib_get_module_result(const char *module_name, const sechk_lib_t * lib);
+
+/* library utility functions */
+
+/**
+ * Load the policy the library will analyze.
+ *
+ * @param policy_mods Policy path object to use to load the policy.
+ * @param lib The library into which to load the policy.
+ *
+ * @return 0 on success and < 0 on failure.
+ */
+ int sechk_lib_load_policy(apol_policy_path_t * policy_mods, sechk_lib_t * lib);
+
+/**
+ * Load the file contexts file the library will use during analysis.
+ *
+ * @param fcfilelocation Path of the file contexts file to load, or
+ * NULL to search for system default file contexts.
+ * @param lib The library into which to load the file contexts.
+ *
+ * @return 0 on success and < 0 on failure.
+ */
+ int sechk_lib_load_fc(const char *fcfilelocation, sechk_lib_t * lib);
+
+/**
+ * Load a profile containing module options.
+ *
+ * @param prof_name Name of a known installed profile or the absolute path
+ * to a user created profile.
+ * @param lib The library containing the modules specified in the profile.
+ *
+ * @return 0 on success and < 0 on failure; if the call fails errno will be
+ * set and the library should be destroyed.
+ */
+ int sechk_lib_load_profile(const char *prof_name, sechk_lib_t * lib);
+
+/**
+ * Clear an option of all previous values.
+ *
+ * @param module Module containing the option to clear.
+ * @param option Name of the option to clear.
+ *
+ * @return 0 on success or < 0 on failure; if the call fails,
+ * errno will be set, and the module should be freed.
+ */
+ int sechk_lib_module_clear_option(sechk_module_t * module, char *option);
+
+/**
+ * Check that the library can meet a single requirement.
+ *
+ * @param req The requirement to check.
+ * @param lib The library to query.
+ *
+ * @return 1 if the requirement is met, and 0 if it is either unmet or
+ * if the library is unable to determine.
+ */
+ bool sechk_lib_check_requirement(sechk_name_value_t * req, sechk_lib_t * lib);
+
+/**
+ * Check that the library can meet a single module dependency.
+ *
+ * @param dep The dependency to check.
+ * @param lib The library to query for the existence of the dependency.
+ *
+ * @return 1 if the dependency exists, and 0 if it either does not or
+ * if the library is unable to determine.
+ */
+ bool sechk_lib_check_dependency(sechk_name_value_t * dep, sechk_lib_t * lib);
+
+/**
+ * Set the default output format for the library.
+ *
+ * @param out The format to use as a bit-wise or of SECHK_OUT_*.
+ * @param lib The library for which to set the output format.
+ *
+ * @return 0 on success and < 0 on failure; if the call fails,
+ * errno will be set.
+ */
+ int sechk_lib_set_outputformat(unsigned char out, sechk_lib_t * lib);
+
+/**
+ * Set the minimum severity level of the library.
+ *
+ * @param sev Severity level to set as the minimum level for reporting.
+ * Must be one of SECHK_SEV_*.
+ * @param lib The library for which to set the minimum severity level.
+ *
+ * @return 0 on success and < 0 on failure; if the call fials,
+ * errno will be set.
+ */
+ int sechk_lib_set_minsev(const char *sev, sechk_lib_t * lib);
+
+/**
+ * Get the index of a module in the library by name.
+ *
+ * @param name Name of the module for which to get the index.
+ * @param lib The library containing the desired module.
+ *
+ * @return index of the module or -1 if it was not found.
+ * If not found, errno will be set.
+ */
+ int sechk_lib_get_module_idx(const char *name, sechk_lib_t * lib);
+
+/* other utility functions */
+
+/**
+ * Copy a proof element. Note: the element in the proof is a shallow copy.
+ *
+ * @param orig The original proof to copy.
+ *
+ * @return a copy of the proof or NULL on error. If the call fails,
+ * errno will be set.
+ */
+ sechk_proof_t *sechk_proof_copy(sechk_proof_t * orig);
+
+/**
+ * Callback for vector comparison of proof elements.
+ * This callback takes two different type objects both cast to void
+ * it is important that the order of the parameters is correct or the
+ * vector code will fail when using this callback.
+ *
+ * @param in_proof One member of the vector of proofs.
+ * @param elem A policy item to compare to the proof's element.
+ * @param unused Unused. Needed to satisfy vector prototype.
+ *
+ * @return Pointer comparison value of < 0, 0 or > 0 if the element in the
+ * proof is respectively less than, equal to, or greater than that of the
+ * comparison element supplied.
+ */
+ int sechk_proof_with_element_compare(const void *in_proof, const void *elem, void *unused);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECHECKER_H */
diff --git a/sechecker/sechecker_cli.c b/sechecker/sechecker_cli.c
new file mode 100644
index 0000000..9fbbd96
--- /dev/null
+++ b/sechecker/sechecker_cli.c
@@ -0,0 +1,361 @@
+/**
+ * @file
+ * Main function and command line parser for the sechecker program.
+ *
+ * @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 <config.h>
+
+#include "sechecker.h"
+#include "register_list.h"
+#include <apol/policy.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2005-2007 Tresys Technology, LLC"
+
+extern sechk_module_name_reg_t sechk_register_list[];
+
+enum opt_values
+{
+ OPT_FCFILE = 256, OPT_MIN_SEV
+};
+
+/* command line options struct */
+static struct option const longopts[] = {
+ {"list", no_argument, NULL, 'l'},
+ {"help", optional_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"short", no_argument, NULL, 's'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"profile", required_argument, NULL, 'p'},
+ {"fcfile", required_argument, NULL, OPT_FCFILE},
+ {"module", required_argument, NULL, 'm'},
+ {"min-sev", required_argument, NULL, OPT_MIN_SEV},
+ {NULL, 0, NULL, 0}
+};
+
+/* display usage help */
+void usage(const char *arg0, bool brief)
+{
+ printf("Usage: sechecker [OPTIONS] -p profile [POLICY ...]\n");
+ printf(" sechecker [OPTIONS] -m module [POLICY ...]\n");
+ printf(" sechecker [OPTIONS] -p profile -m module [POLICY ...]\n");
+ printf("\n");
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", arg0);
+ } else {
+ printf("Perform modular checks on a SELinux policy.\n");
+ printf("\n");
+ printf(" -p PROF, --profile=PROF name or path of profile to load\n");
+ printf(" if used without -m, run all modules in profile\n");
+ printf(" -m MODULE, --module=MODULE MODULE to run\n");
+ printf(" --fcfile=FILE file_contexts file to load\n");
+ printf("\n");
+ printf(" -q, --quiet suppress output\n");
+ printf(" -s, --short print short output\n");
+ printf(" -v, --verbose print verbose output\n");
+ printf(" --min-sev={low|med|high} set the minimum severity to report\n");
+ printf("\n");
+ printf(" -l, --list print a list of profiles and modules and exit\n");
+ printf(" -h[MODULE], --help[=MODULE] print this help text or help for MODULE\n");
+ printf(" -V, --version print version information and exit\n");
+ printf("\n");
+ }
+}
+
+/* print list of modules and installed profiles */
+int sechk_print_list(sechk_lib_t * lib)
+{
+ const sechk_profile_name_reg_t *profiles;
+ size_t num_profiles, i;
+ sechk_module_t *mod = NULL;
+
+ printf("\nProfiles:\n");
+ profiles = sechk_register_list_get_profiles();
+ num_profiles = sechk_register_list_get_num_profiles();
+ for (i = 0; i < num_profiles; i++) {
+ printf("%20s\t%s\n", profiles[i].name, profiles[i].desc);
+ }
+ if (num_profiles == 0)
+ printf("<none>\n");
+
+ printf("Modules:\n");
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ printf("%20s\t%s\n", mod->name, mod->brief_description);
+ }
+ if (apol_vector_get_size(lib->modules) == 0)
+ printf("<none>\n");
+ printf("\n");
+ return 0;
+}
+
+/* main application */
+int main(int argc, char **argv)
+{
+ int optc = 0, retv = 0;
+ size_t i;
+ char *fcpath = NULL;
+ char *modname = NULL;
+ char *prof_name = NULL;
+ char *base_path = NULL;
+ apol_policy_path_t *pol_path = NULL;
+ apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ char *minsev = NULL;
+ unsigned char output_override = 0;
+ sechk_lib_t *lib;
+ sechk_module_t *mod = NULL;
+ bool list_stop = false;
+ bool module_help = false;
+ apol_vector_t *policy_mods = NULL;
+
+ while ((optc = getopt_long(argc, argv, "p:m:qsvlh::V", longopts, NULL)) != -1) {
+ switch (optc) {
+ case 'p':
+ prof_name = strdup(optarg);
+ break;
+ case 'm':
+ if (minsev) {
+ fprintf(stderr, "Error: --min-sev does not work with --module.\n");
+ exit(1);
+ }
+ modname = strdup(optarg);
+ break;
+ case OPT_FCFILE:
+ fcpath = strdup(optarg);
+ break;
+ case 'q':
+ if (output_override) {
+ fprintf(stderr, "Error: multiple output formats specified.\n");
+ usage(argv[0], 1);
+ exit(1);
+ } else {
+ output_override = SECHK_OUT_QUIET;
+ }
+ break;
+ case 's':
+ if (output_override) {
+ fprintf(stderr, "Error: multiple output formats specified.\n");
+ usage(argv[0], 1);
+ exit(1);
+ } else {
+ output_override = SECHK_OUT_SHORT;
+ }
+ break;
+ case 'v':
+ if (output_override) {
+ fprintf(stderr, "Error: multiple output formats specified.\n");
+ usage(argv[0], 1);
+ exit(1);
+ } else {
+ output_override = SECHK_OUT_VERBOSE;
+ }
+ break;
+ case OPT_MIN_SEV:
+ if (modname) {
+ fprintf(stderr, "Error: --min-sev does not work with --module.\n");
+ exit(1);
+ }
+ minsev = strdup(optarg);
+ break;
+ case 'l':
+ list_stop = true;
+ break;
+ case 'h':
+ if (optarg != NULL) {
+ modname = strdup(optarg);
+ module_help = true;
+ break;
+ }
+ usage(argv[0], 0);
+ exit(0);
+ case 'V':
+ printf("sechecker %s\n%s\n", VERSION, COPYRIGHT_INFO);
+ exit(0);
+ default:
+ usage(argv[0], 1);
+ exit(1);
+ }
+ }
+
+ if (!prof_name && !modname && !list_stop) {
+ fprintf(stderr, "Error: no module or profile specified\n\n");
+ usage(argv[0], 1);
+ exit(1);
+ }
+
+ /* create the module library */
+ lib = sechk_lib_new();
+ if (!lib)
+ goto exit_err;
+
+ /* print the list */
+ if (list_stop == true) {
+ sechk_print_list(lib);
+ goto exit;
+ }
+
+ /* print help for a module */
+ if (module_help == true) {
+ retv = sechk_lib_get_module_idx(modname, lib);
+ if (retv < 0) {
+ fprintf(stderr, "Error: Module %s does not exist.\n", modname);
+ goto exit_err;
+ }
+ mod = apol_vector_get_element(lib->modules, retv);
+ printf("\nModule name: %s\n%s\n%s\n", mod->name, mod->detailed_description, mod->opt_description);
+ goto exit;
+ }
+
+ /* load profile if specified */
+ if (prof_name) {
+ retv = sechk_lib_load_profile(prof_name, lib);
+ if (retv) {
+ retv = errno;
+ if (!output_override || !(output_override & ~(SECHK_OUT_QUIET))) {
+ fprintf(stderr, "Error: could not load profile %s\n", prof_name);
+ errno = retv;
+ perror("Error");
+ }
+ goto exit_err;
+ }
+ }
+
+ /* initialize the policy */
+ if (argc - optind) {
+ base_path = argv[optind];
+ optind++;
+ if (argc - optind) {
+ if (!(policy_mods = apol_vector_create(NULL)))
+ goto exit_err;
+ while (argc - optind) {
+ if (apol_vector_append(policy_mods, argv[optind++]))
+ goto exit_err;
+ path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ }
+ } else if (apol_file_is_policy_path_list(base_path) > 0) {
+ pol_path = apol_policy_path_create_from_file(base_path);
+ if (!pol_path) {
+ fprintf(stderr, "Error: invalid policy list\n");
+ goto exit_err;
+ }
+ }
+ if (!pol_path)
+ pol_path = apol_policy_path_create(path_type, base_path, policy_mods);
+ if (!pol_path)
+ goto exit_err;
+ if (sechk_lib_load_policy(pol_path, lib)) {
+ pol_path = NULL;
+ goto exit_err;
+ }
+ } else {
+ if (sechk_lib_load_policy(NULL, lib))
+ goto exit_err;
+ }
+ /* library now owns path object */
+ pol_path = NULL;
+
+ /* set the minimum severity */
+ if (minsev && sechk_lib_set_minsev(minsev, lib) < 0)
+ goto exit_err;
+
+ /* initialize the file contexts */
+ if (sechk_lib_load_fc(fcpath, lib) < 0)
+ goto exit_err;
+ /* initialize the output format */
+ if (output_override) {
+ if (sechk_lib_set_outputformat(output_override, lib) < 0)
+ goto exit_err;
+ }
+
+ /* if running only one module, deselect all others */
+ if (modname) {
+ retv = sechk_lib_get_module_idx(modname, lib);
+ if (retv == -1 || (size_t) retv >= apol_vector_get_size(lib->modules)) {
+ fprintf(stderr, "Error: module %s not found\n", modname);
+ goto exit_err;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ mod->selected = false;
+ }
+ mod = apol_vector_get_element(lib->modules, retv);
+ mod->selected = true;
+ }
+
+ /* process dependencies for selected modules */
+ if (sechk_lib_check_module_dependencies(lib) < 0)
+ goto exit_err;
+
+ /* process requirements for selected modules */
+ if (sechk_lib_check_module_requirements(lib) < 0)
+ goto exit_err;
+
+ /* initialize the modules */
+ if (sechk_lib_init_modules(lib))
+ goto exit_err;
+
+ /* run the modules */
+ if (sechk_lib_run_modules(lib))
+ goto exit_err;
+
+ /* if running only one module, deselect all others again before printing */
+ if (modname) {
+ retv = sechk_lib_get_module_idx(modname, lib);
+ if (retv == -1 || (size_t) retv >= apol_vector_get_size(lib->modules)) {
+ fprintf(stderr, "Error: module %s not found\n", modname);
+ goto exit_err;
+ }
+ for (i = 0; i < apol_vector_get_size(lib->modules); i++) {
+ mod = apol_vector_get_element(lib->modules, i);
+ mod->selected = false;
+ }
+ mod = apol_vector_get_element(lib->modules, retv);
+ mod->selected = true;
+ }
+
+ /* print the report */
+ if (sechk_lib_print_modules_report(lib))
+ goto exit_err;
+
+ exit:
+ free(fcpath);
+ apol_vector_destroy(&policy_mods);
+ free(minsev);
+ free(prof_name);
+ free(modname);
+ sechk_lib_destroy(&lib);
+ return 0;
+
+ exit_err:
+ free(fcpath);
+ apol_vector_destroy(&policy_mods);
+ free(minsev);
+ free(prof_name);
+ free(modname);
+ apol_policy_path_destroy(&pol_path);
+ sechk_lib_destroy(&lib);
+ return 1;
+}
diff --git a/sechecker/sechecker_help.txt b/sechecker/sechecker_help.txt
new file mode 100644
index 0000000..a28496a
--- /dev/null
+++ b/sechecker/sechecker_help.txt
@@ -0,0 +1,86 @@
+SELinux Policy Checker Tool Help File
+
+
+This file contains the basic help information for using sechecker, a
+program that runs a series of policy checks (modules) on a policy.
+Sechecker is designed to be extensible and configurable so that
+developers can easily add new policy checks and configure them to run
+in batches with different options.
+
+Each module analyzes a policy. If a policy is not specified on the
+command line, the tool uses the system policy by default. In
+addition, some checks will require the file_contexts file in order to
+run correctly. If the file_contexts file is not specified, the tool
+will default to using the system file_contexts file by default.
+
+Checks can be run one at a time on the command line (by specifying a
+module) or in a batch (by specifying a profile). The user can create
+a custom profile to specify which modules to run, as well as the
+modules' options.
+
+The return value of sechecker indicates whether a check failed on the
+policy. Therefore sechecker may be used in shell scripts or makefiles
+to do conditional branching.
+
+
+Report Output:
+--------------
+Sechecker generates a report with the output of each module that was
+run. The report includes an explanation of each module, the modules'
+severity, and the modules' results. There are three output options to
+specify what gets included in the report.
+
+1) quiet - do not print the report
+2) short - print the list of results for each module
+3) verbose - print the list of results for each module and the list of
+ proofs for each result
+
+
+Modules:
+--------
+A module encapsulates a single check on the policy. Modules may take
+options from the current profile; if no profile is given then modules
+will use default values. See the help for the specific module(s) to
+determine the parameters that may be overridden in a profile.
+
+Each module has a specified severity (high, med, low). These are
+defined as follows:
+
+1) "high": The module's results indicate an identifiable security
+ risk in the SELinux policy.
+
+2) "med": The module's results indicate a flaw in the SELinux policy
+ that changes the manner in which the policy is enforced; however,
+ it does not present an identifiable security risk.
+
+3) "low": The module's results indicate a flaw in the policy that
+ does not affect the manner in which the policy is enforced, but is
+ considered to be improper.
+
+
+Profiles:
+---------
+Three profiles are installed with the sechecker program:
+
+1) development: This profile includes several policy checks of low
+ and med severity. The checks are common tasks that a policy
+ developer will consider helpful for writing good policy.
+
+2) analysis: This profile includes several policy checks of med and
+ low severity that are of higher computational complexity than the
+ development profile and is not meant to be used frequently by
+ policy developers.
+
+3) all: This profile runs all known modules.
+
+Profiles can be created to run any set of modules with different
+options. The profile can specify the output format for each module.
+
+
+Other Options:
+--------------
+The user may specify a minimum module severity to report. For
+example, if the minimum severity is "med" and the "all" profile is
+used, all modules that are "med" or "high" will be run and the results
+for those modules will be reported by sechecker. The "low" severity
+modules listed in the profile will be ignored.
diff --git a/sechecker/sechk_parse.c b/sechecker/sechk_parse.c
new file mode 100644
index 0000000..ae73af2
--- /dev/null
+++ b/sechecker/sechk_parse.c
@@ -0,0 +1,285 @@
+/* Copyright (C) 2005 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
+ */
+
+/*
+ * Author: jmowery@tresys.com
+ *
+ */
+
+#include "sechecker.h"
+#include "sechk_parse.h"
+#include <apol/util.h>
+#include <libxml/xmlreader.h>
+#include <errno.h>
+#include <string.h>
+
+/* xml parser keywords */
+#define SECHK_PARSE_SECHECKER_TAG "sechecker"
+#define SECHK_PARSE_PROFILE_TAG "profile"
+#define SECHK_PARSE_MODULE_TAG "module"
+#define SECHK_PARSE_OPTION_TAG "option"
+#define SECHK_PARSE_ITEM_TAG "item"
+#define SECHK_PARSE_OUTPUT_TAG "output"
+#define SECHK_PARSE_VALUE_ATTRIB "value"
+#define SECHK_PARSE_NAME_ATTRIB "name"
+#define SECHK_PARSE_VERSION_ATTRIB "version"
+#define SECHK_PARSE_OUTPUT_NONE "none"
+#define SECHK_PARSE_OUTPUT_QUIET "quiet"
+#define SECHK_PARSE_OUTPUT_SHORT "short"
+#define SECHK_PARSE_OUTPUT_VERBOSE "verbose"
+
+static char *build_dtd_path(void)
+{
+ char *path = NULL;
+ size_t path_sz = 0;
+
+#ifdef PROFILE_INSTALL_DIR
+ if (apol_str_append(&path, &path_sz, "file://localhost/") == -1)
+ return NULL;
+
+ if (apol_str_append(&path, &path_sz, PROFILE_INSTALL_DIR) == -1)
+ return NULL;
+
+ if (apol_str_append(&path, &path_sz, "/sechecker.dtd") == -1)
+ return NULL;
+
+ return path;
+#endif
+
+ return NULL;
+}
+
+ /* Parsing functions */
+
+/* Parse the configuration file. */
+int sechk_lib_parse_xml_file(const char *filename, sechk_lib_t * lib)
+{
+ xmlTextReaderPtr reader = NULL;
+ xmlDtdPtr dtd = NULL;
+ xmlDocPtr xml = NULL;
+ xmlValidCtxtPtr ctxt = NULL;
+ int tmp, ret = 0;
+ char *dtd_path = NULL;
+
+ /* this initializes the XML library and checks potential ABI mismatches
+ * between the version it was compiled for and the actual shared
+ * library used. */
+ LIBXML_TEST_VERSION;
+ reader = xmlReaderForFile(filename, NULL, 0);
+ if (!reader) {
+ ret = errno;
+ if (ret != ENOENT)
+ fprintf(stderr, "Error: Could not create xmlReader.\n");
+ goto exit_err;
+ }
+
+ dtd_path = build_dtd_path();
+ if (!dtd_path) {
+ fprintf(stderr, "Error: getting DTD path\n");
+ goto exit_err;
+ }
+ dtd = xmlParseDTD(NULL, (const xmlChar *)dtd_path);
+ free(dtd_path);
+
+ if (!dtd) {
+ fprintf(stderr, "Error: parsing DTD\n");
+ goto exit_err;
+ }
+
+ xml = xmlParseFile(filename);
+ if (!xml) {
+ fprintf(stderr, "Error: parsing sechecker profile\n");
+ goto exit_err;
+ }
+
+ ctxt = xmlNewValidCtxt();
+ if (!ctxt) {
+ fprintf(stderr, "Error: out of memory\n");
+ goto exit_err;
+ }
+ /* validate profile against the DTD */
+ if (xmlValidateDtd(ctxt, xml, dtd) == 0) {
+ fprintf(stderr, "Error: SEChecker profile contains invalid XML. Aborting.\n");
+ goto exit_err;
+ }
+ xmlFreeValidCtxt(ctxt);
+ xmlFreeDoc(xml);
+ xmlFreeDtd(dtd);
+
+ while (1) {
+ ret = xmlTextReaderRead(reader);
+ if (ret == -1) {
+ ret = errno;
+ fprintf(stderr, "Error: Error reading xml.\n");
+ goto exit_err;
+ }
+ if (ret == 0) /* no more nodes to read */
+ break;
+
+ tmp = sechk_lib_process_xml_node(reader, lib);
+ if (tmp == -1)
+ goto exit_err;
+ if (tmp == 1) {
+ ret = xmlTextReaderNext(reader);
+ if (ret == 0)
+ break;
+ if (ret == -1) {
+ ret = errno;
+ fprintf(stderr, "Error in xmlTextReaderNext()\n");
+ goto exit_err;
+ }
+ }
+ }
+
+ /* cleanup function for the XML library */
+ xmlCleanupParser();
+ xmlFreeTextReader(reader);
+ return 0;
+
+ exit_err:
+ xmlCleanupParser();
+ if (reader)
+ xmlFreeTextReader(reader);
+ if (ret)
+ errno = ret;
+ return -1;
+}
+
+/* process a single node in the xml file */
+int sechk_lib_process_xml_node(xmlTextReaderPtr reader, sechk_lib_t * lib)
+{
+ xmlChar *attrib = NULL;
+ int idx;
+ sechk_name_value_t *nv = NULL;
+ static xmlChar *option = NULL;
+ static xmlChar *value = NULL;
+ static sechk_module_t *current_module = NULL;
+
+ switch (xmlTextReaderNodeType(reader)) {
+
+ case XML_ELEMENT_DECL: /* closing tags */
+ if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_MODULE_TAG) == 1) {
+ current_module = NULL;
+ } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OPTION_TAG) == 1) {
+ free(option);
+ option = NULL;
+ }
+ break;
+
+ case XML_ELEMENT_NODE: /* opening tags */
+
+ if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_SECHECKER_TAG) == 1) {
+ /* parsing the <sechecker> tag */
+ attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VERSION_ATTRIB);
+ if (attrib) {
+#ifdef SECHECKER_VERSION
+ if (atof((const char *)attrib) > atof(SECHECKER_VERSION)) {
+ fprintf(stderr,
+ "Error: sechecker version in profile is incorrect: expected %1.1f got %1.1f\n",
+ atof(SECHECKER_VERSION), atof((const char *)attrib));
+ goto exit_err;
+ }
+#endif
+
+ free(attrib);
+ attrib = NULL;
+ } else {
+ fprintf(stderr, "Warning: sechecker version is not specified.\n");
+ }
+ } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_MODULE_TAG) == 1) {
+ /* parsing the <module> tag */
+ attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_NAME_ATTRIB);
+ if (attrib) {
+ if ((idx = sechk_lib_get_module_idx((const char *)attrib, lib)) == -1) {
+ fprintf(stderr, "Warning: module %s not found.\n", (const char *)attrib);
+ return 1; /* not a fatal error */
+ } else {
+ /* set the values on the existing module */
+ current_module = apol_vector_get_element(lib->modules, idx);
+ current_module->selected = true;
+ }
+ free(attrib);
+ attrib = NULL;
+ } else {
+ fprintf(stderr, "Error: module name is not specified.\n");
+ goto exit_err;
+ }
+ } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OPTION_TAG) == 1) {
+ /* parsing the <option> tag */
+ if (!current_module) {
+ fprintf(stderr, "Error: 'option' specified outside the scope of a module.\n");
+ goto exit_err;
+ }
+ /* read the name of the option */
+ option = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_NAME_ATTRIB);
+ if (!option) {
+ fprintf(stderr, "Error: option name is not specified.\n");
+ goto exit_err;
+ }
+ /* clear the options with this name that were set by defualt for this module */
+ sechk_lib_module_clear_option(current_module, (char *)option);
+
+ } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_ITEM_TAG) == 1) {
+ /* parsing the <item> tag */
+ assert(current_module);
+ nv = sechk_name_value_new((char *)option, NULL);
+ /* read the value for this name value pair */
+ value = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VALUE_ATTRIB);
+ if (!value) {
+ fprintf(stderr, "Error: item value is not specified.\n");
+ goto exit_err;
+ }
+ nv->value = strdup((char *)value);
+ free(value);
+ value = NULL;
+ /* add the nv pair to the module options */
+ apol_vector_append(current_module->options, (void *)nv);
+ nv = NULL;
+ } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OUTPUT_TAG) == 1) {
+ if (!current_module) {
+ fprintf(stderr, "Error: 'output' specified outside the scope of a module.\n");
+ goto exit_err;
+ }
+ attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VALUE_ATTRIB);
+ if (attrib) {
+ if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_QUIET) == 1) {
+ current_module->outputformat = SECHK_OUT_QUIET;
+ } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_VERBOSE) == 1) {
+ current_module->outputformat = SECHK_OUT_VERBOSE;
+ } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_SHORT) == 1) {
+ current_module->outputformat = SECHK_OUT_SHORT;
+ } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_NONE) == 1) {
+ current_module->outputformat = SECHK_OUT_NONE;
+ } else {
+ fprintf(stderr, "Error: invalid output value %s.\n", attrib);
+ goto exit_err;
+ }
+ free(attrib);
+ attrib = NULL;
+ } else {
+ fprintf(stderr, "Error: output value is not specified.\n");
+ goto exit_err;
+ }
+ }
+ break;
+ }
+ return 0;
+
+ exit_err:
+ sechk_name_value_free(nv);
+ errno = EIO;
+ return -1;
+}
diff --git a/sechecker/sechk_parse.h b/sechecker/sechk_parse.h
new file mode 100644
index 0000000..1555e56
--- /dev/null
+++ b/sechecker/sechk_parse.h
@@ -0,0 +1,44 @@
+/* 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
+ */
+
+/*
+ * Author: jmowery@tresys.com
+ *
+ */
+
+#ifndef SECHK_PARSE_H
+#define SECHK_PARSE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+
+#include <libxml/xmlreader.h>
+#include <assert.h>
+
+#define sechk_lib_parse_profile(path, lib) sechk_lib_parse_xml_file(path, lib)
+
+ int sechk_lib_parse_xml_file(const char *filename, sechk_lib_t * lib);
+ int sechk_lib_process_xml_node(xmlTextReaderPtr reader, sechk_lib_t * lib);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif