summaryrefslogtreecommitdiffstats
path: root/sechecker/modules
diff options
context:
space:
mode:
Diffstat (limited to 'sechecker/modules')
-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
48 files changed, 14656 insertions, 0 deletions
diff --git a/sechecker/modules/attribs_wo_rules.c b/sechecker/modules/attribs_wo_rules.c
new file mode 100644
index 0000000..4f2c00e
--- /dev/null
+++ b/sechecker/modules/attribs_wo_rules.c
@@ -0,0 +1,520 @@
+/**
+ * @file
+ * Implementation of the attributes without rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "attribs_wo_rules.h"
+#include <apol/type-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "attribs_wo_rules";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int attribs_wo_rules_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "attributes not used in any rule";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds attributes in the policy that are not used in any rules; These\n"
+ "attributes will get thrown out by the compiler and have no effect on the \n"
+ "security environment. They are unnecessary and should be removed.\n";
+ mod->opt_description =
+ "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_rules_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &attribs_wo_rules_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data. */
+int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *attr_vector;
+ apol_role_query_t *role_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_vector_t *avrule_vector;
+ apol_vector_t *terule_vector;
+ apol_vector_t *role_vector;
+ qpol_iterator_t *constraint_iter;
+ qpol_iterator_t *node_iter = NULL;
+ qpol_iterator_t *name_iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int found = 0, error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ATTRIB;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+
+ apol_attr_get_by_query(policy, NULL, &attr_vector);
+ for (i = 0; i < apol_vector_get_size(attr_vector); i++) {
+ qpol_type_t *attr;
+ const char *attr_name;
+ attr = apol_vector_get_element(attr_vector, i);
+ qpol_type_get_name(q, attr, &attr_name);
+
+ /* access rules */
+ apol_avrule_query_set_source(policy, avrule_query, attr_name, 0);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ if (apol_vector_get_size(avrule_vector) > 0) {
+ apol_vector_destroy(&avrule_vector);
+ continue;
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ apol_avrule_query_set_source(policy, avrule_query, NULL, 0);
+ apol_avrule_query_set_target(policy, avrule_query, attr_name, 0);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ if (apol_vector_get_size(avrule_vector) > 0) {
+ apol_vector_destroy(&avrule_vector);
+ continue;
+ }
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ apol_vector_destroy(&avrule_vector);
+
+ /* type rules */
+ apol_terule_query_set_source(policy, terule_query, attr_name, 0);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ if (apol_vector_get_size(terule_vector) > 0) {
+ apol_vector_destroy(&terule_vector);
+ continue;
+ }
+ apol_vector_destroy(&terule_vector);
+
+ apol_terule_query_set_source(policy, terule_query, NULL, 0);
+ apol_terule_query_set_target(policy, terule_query, attr_name, 0);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ if (apol_vector_get_size(terule_vector) > 0) {
+ apol_vector_destroy(&terule_vector);
+ continue;
+ }
+ apol_terule_query_set_target(policy, terule_query, NULL, 0);
+ apol_vector_destroy(&terule_vector);
+
+ /* role trans */
+ apol_role_query_set_type(policy, role_query, attr_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ if (apol_vector_get_size(role_vector) > 0) {
+ apol_vector_destroy(&role_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_vector);
+
+ /* Check constraints */
+ constraint_iter = NULL;
+ node_iter = NULL;
+ name_iter = NULL;
+ found = 0;
+ qpol_policy_get_constraint_iter(q, &constraint_iter);
+ for (; !qpol_iterator_end(constraint_iter); qpol_iterator_next(constraint_iter)) {
+ qpol_constraint_t *constraint;
+
+ qpol_iterator_get_item(constraint_iter, (void **)&constraint);
+ qpol_constraint_get_expr_iter(q, constraint, &node_iter);
+
+ for (; !qpol_iterator_end(node_iter); qpol_iterator_next(node_iter)) {
+ qpol_constraint_expr_node_t *constraint_node;
+ uint32_t node_type;
+
+ qpol_iterator_get_item(node_iter, (void **)&constraint_node);
+ qpol_constraint_expr_node_get_expr_type(q, constraint_node, &node_type);
+
+ if (node_type == QPOL_CEXPR_TYPE_NAMES) {
+ qpol_constraint_expr_node_get_names_iter(q, constraint_node, &name_iter);
+
+ for (; !qpol_iterator_end(name_iter); qpol_iterator_next(name_iter)) {
+ char *name;
+
+ qpol_iterator_get_item(name_iter, (void **)&name);
+ if (!strcmp(name, attr_name)) {
+ found = 1;
+ free(name);
+ name = NULL;
+ break;
+ }
+ free(name);
+ name = NULL;
+ }
+ qpol_iterator_destroy(&name_iter);
+ if (found)
+ break;
+ }
+ }
+ qpol_iterator_destroy(&node_iter);
+ free(constraint);
+ if (found)
+ break;
+ }
+ qpol_iterator_destroy(&constraint_iter);
+ if (found)
+ continue;
+
+ /* if we get here then the attrib was not found anywhere in a rule so add it */
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)attr;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->text = strdup("attribute was not used in any rules.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_rules_run_fail;
+ }
+ }
+ apol_avrule_query_destroy(&avrule_query);
+ apol_role_query_destroy(&role_query);
+ apol_terule_query_destroy(&terule_query);
+ apol_vector_destroy(&attr_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ attribs_wo_rules_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd attributes.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following attributes do not appear in any rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/attribs_wo_rules.h b/sechecker/modules/attribs_wo_rules.h
new file mode 100644
index 0000000..e2869d5
--- /dev/null
+++ b/sechecker/modules/attribs_wo_rules.h
@@ -0,0 +1,63 @@
+/**
+ * @file
+ * Defines the interface for the attributes without rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ATTRIBS_WO_RULES
+#define ATTRIBS_WO_RULES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/avrule-query.h>
+#include <apol/terule-query.h>
+#include <apol/type-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int attribs_wo_rules_register(sechk_lib_t * lib);
+ int attribs_wo_rules_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_rules_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_rules_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+/* NOTE: While SEChecker is build statically, it is
+ * intended that no module directly call a function
+ * from another but instead use get_module_function()
+ * to get the desired function from the library. */
+
+ int attribs_wo_rules_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/attribs_wo_types.c b/sechecker/modules/attribs_wo_types.c
new file mode 100644
index 0000000..edac010
--- /dev/null
+++ b/sechecker/modules/attribs_wo_types.c
@@ -0,0 +1,399 @@
+/**
+ * @file
+ * Implementation of the attributes without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "attribs_wo_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "attribs_wo_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int attribs_wo_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "attributes with no types";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds attributes in the policy that are not associated with any\n"
+ "types. Attributes without types can cause type fields in rules to expand to\n"
+ "empty sets and thus become unreachable. This makes for misleading policy source\n" "files.\n";
+ mod->opt_description =
+ "Module requirements:\n" " attribute names\n" "Module dependencies:\n" " none\n" "Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = attribs_wo_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *attr_vector = NULL;
+ qpol_iterator_t *types = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ATTRIB;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+
+ apol_attr_get_by_query(policy, NULL, &attr_vector);
+ for (i = 0; i < apol_vector_get_size(attr_vector); i++) {
+ qpol_type_t *attr;
+ const char *attr_name;
+ int at_end;
+
+ attr = apol_vector_get_element(attr_vector, i);
+ qpol_type_get_name(q, attr, &attr_name);
+ qpol_type_get_type_iter(q, attr, &types);
+ at_end = qpol_iterator_end(types);
+ qpol_iterator_destroy(&types);
+ if (!at_end)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->text = (char *)calloc(strlen("attribute has no types") + strlen(attr_name) + 1, sizeof(char));
+ sprintf(proof->text, "attribute %s has no types", attr_name);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ }
+ item->item = (void *)attr;
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto attribs_wo_types_run_fail;
+ }
+ }
+ qpol_iterator_destroy(&types);
+ apol_vector_destroy(&attr_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ attribs_wo_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd attributes.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following attributes are not associated with any types.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * polciy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/attribs_wo_types.h b/sechecker/modules/attribs_wo_types.h
new file mode 100644
index 0000000..da11801
--- /dev/null
+++ b/sechecker/modules/attribs_wo_types.h
@@ -0,0 +1,48 @@
+/**
+ * @file
+ * Defines the interface for the attributes without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ATTRIBS_WO_TYPES
+#define ATTRIBS_WO_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+
+ int attribs_wo_types_register(sechk_lib_t * lib);
+ int attribs_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int attribs_wo_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/domain_and_file.c b/sechecker/modules/domain_and_file.c
new file mode 100644
index 0000000..418e2a5
--- /dev/null
+++ b/sechecker/modules/domain_and_file.c
@@ -0,0 +1,398 @@
+/**
+ * @file
+ * Implementation of the domain and file type module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "domain_and_file.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "domain_and_file";
+
+int domain_and_file_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "types treated as a domain and file type";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in the policy treated as both a domain and a file \n"
+ "type. See find_domains and find_file_types modules for details about the \n"
+ "heuristics used to determine these types. It is considered bad security\n"
+ "practice to use the same type for a domain and its data objects because it \n"
+ "requires that less restrictive access be granted to these types.\n";
+ mod->opt_description = "Module requirements:\n" " attribute names\n"
+ " file_contexts\n"
+ "Module dependencies:\n" " find_domains module\n" " find_file_types module\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* assign requirements */
+ nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES);
+ apol_vector_append(mod->requirements, (void *)nv);
+ nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL);
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* assign dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_file_types"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &domain_and_file_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domain_and_file_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domain_and_file_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *domain_res = NULL, *file_type_res = NULL;
+ size_t i, j, k;
+ sechk_mod_fn_t run_fn = NULL;
+ sechk_name_value_t *dep = NULL;
+ apol_vector_t *domain_vector;
+ apol_vector_t *type_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+
+ /* run dependencies */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ /* get results */
+ domain_res = sechk_lib_get_module_result("find_domains", mod->parent_lib);
+ if (!domain_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_domains");
+ goto domain_and_file_run_fail;
+ }
+ file_type_res = sechk_lib_get_module_result("find_file_types", mod->parent_lib);
+ if (!file_type_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_file_types");
+ goto domain_and_file_run_fail;
+ }
+
+ /* get lists */
+ domain_vector = (apol_vector_t *) domain_res->items;
+ type_vector = (apol_vector_t *) file_type_res->items;
+
+ /* build the both list */
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ sechk_item_t *type_item;
+ qpol_type_t *type;
+ const char *type_name;
+
+ type_item = apol_vector_get_element(type_vector, i);
+ type = type_item->item;
+ qpol_type_get_name(q, type, &type_name);
+ for (j = 0; j < apol_vector_get_size(domain_vector); j++) {
+ sechk_item_t *domain_item;
+ qpol_type_t *domain;
+ const char *domain_name;
+
+ domain_item = apol_vector_get_element(domain_vector, j);
+ domain = domain_item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+ if (!strcmp(domain_name, type_name)) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ item->item = (void *)domain;
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ for (k = 0; k < apol_vector_get_size(domain_item->proof); k++) {
+ sechk_proof_t *domain_proof;
+
+ domain_proof = apol_vector_get_element(domain_item->proof, k);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup(domain_proof->text);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ for (k = 0; k < apol_vector_get_size(type_item->proof); k++) {
+ sechk_proof_t *type_proof;
+
+ type_proof = apol_vector_get_element(type_item->proof, k);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup(type_proof->text);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domain_and_file_run_fail;
+ }
+ }
+ }
+ }
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ domain_and_file_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/domain_and_file.h b/sechecker/modules/domain_and_file.h
new file mode 100644
index 0000000..81b82c1
--- /dev/null
+++ b/sechecker/modules/domain_and_file.h
@@ -0,0 +1,46 @@
+/**
+ * @file
+ * Defines the interface for the domain and file type module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DOMAIN_AND_FILE
+#define DOMAIN_AND_FILE
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+ int domain_and_file_register(sechk_lib_t * lib);
+ int domain_and_file_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domain_and_file_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domain_and_file_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/domains_wo_roles.c b/sechecker/modules/domains_wo_roles.c
new file mode 100644
index 0000000..38b42a8
--- /dev/null
+++ b/sechecker/modules/domains_wo_roles.c
@@ -0,0 +1,386 @@
+/**
+ * @file
+ * Implementation of the domains without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "domains_wo_roles.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "domains_wo_roles";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int domains_wo_roles_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with no roles";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all domains in the policy not associated with a role. These \n"
+ "domains cannot have a valid security context. The object_r role is not \n" "considered in this check.\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign requirements */
+ apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES));
+
+ /* assign dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = domains_wo_roles_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. */
+int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int retv, error;
+ size_t i;
+ sechk_module_t *mod_ptr = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ apol_vector_t *domain_vector;
+ apol_vector_t *role_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ apol_role_query_t *role_query = NULL;
+ sechk_result_t *find_domains_res = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto domains_wo_roles_run_fail;
+ }
+
+ run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib);
+ if (!run_fn) {
+ error = errno;
+ ERR(policy, "%s", "Unable to find run function for module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL);
+ if (retv) {
+ error = errno;
+ ERR(policy, "%s", "Unable to run module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_domains");
+ goto domains_wo_roles_run_fail;
+ }
+
+ domain_vector = (apol_vector_t *) find_domains_res->items;
+
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto domains_wo_roles_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ qpol_type_t *domain;
+ const char *domain_name;
+
+ item = apol_vector_get_element(domain_vector, i);
+ domain = item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+
+ apol_role_query_set_type(policy, role_query, domain_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ if (apol_vector_get_size(role_vector) > 0) {
+ apol_vector_destroy(&role_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->text = strdup("Domain has no role.\n");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ item->item = (void *)domain;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto domains_wo_roles_run_fail;
+ }
+ }
+ apol_role_query_destroy(&role_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ domains_wo_roles_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are domains but not associated with any roles.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
diff --git a/sechecker/modules/domains_wo_roles.h b/sechecker/modules/domains_wo_roles.h
new file mode 100644
index 0000000..e46a9b3
--- /dev/null
+++ b/sechecker/modules/domains_wo_roles.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the domains without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DOMAINS_WO_ROLES
+#define DOMAINS_WO_ROLES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+
+ int domains_wo_roles_register(sechk_lib_t * lib);
+ int domains_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domains_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int domains_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_assoc_types.c b/sechecker/modules/find_assoc_types.c
new file mode 100644
index 0000000..0e72801
--- /dev/null
+++ b/sechecker/modules/find_assoc_types.c
@@ -0,0 +1,407 @@
+/**
+ * @file
+ * Implementation of the association types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_assoc_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_assoc_types";
+
+int find_assoc_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds types with an unlabeled initial sid. \n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_assoc_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t buff_sz = 0;
+ const qpol_isid_t *isid;
+ const char *type_name = NULL;
+ const qpol_type_t *type;
+ const qpol_context_t *context;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto find_assoc_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+
+ /* Initialize vectors */
+
+ qpol_policy_get_isid_by_name(q, "unlabeled", &isid);
+ if (!isid) {
+ error = errno;
+ goto find_assoc_types_run_fail;
+ }
+
+ if (apol_str_append(&buff, &buff_sz, "sid unlabeled ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &type);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (apol_str_append(&buff, &buff_sz, type_name) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ }
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ item->test_result = 1;
+ item->item = (void *)type;
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = buff;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_assoc_types_run_fail;
+ }
+
+ mod->result = res;
+
+ return 0;
+
+ find_assoc_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Error: wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd assoc type(s).\n", num_items);
+ }
+ /* The list reassoc component is a display of all items
+ * found without any supassocing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ i++;
+ i %= 4;
+ item = apol_vector_get_element(mod->result->items, j);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item)
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof reassoc component is a display of a list of items
+ * with an indented list of proof statements supassocing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < apol_vector_get_size(mod->result->items); j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_assoc_types.h b/sechecker/modules/find_assoc_types.h
new file mode 100644
index 0000000..23cda10
--- /dev/null
+++ b/sechecker/modules/find_assoc_types.h
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * Defines the interface for the association types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_ASSOC_TYPES
+#define FIND_ASSOC_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_assoc_types_register(sechk_lib_t * lib);
+ int find_assoc_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_assoc_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_domains.c b/sechecker/modules/find_domains.c
new file mode 100644
index 0000000..b59abac
--- /dev/null
+++ b/sechecker/modules/find_domains.c
@@ -0,0 +1,633 @@
+/**
+ * @file
+ * Implementation of the find domains utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_domains.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_domains";
+
+int find_domains_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This is a utility module which finds types in a policy that are treated as a \n"
+ "domain. A type is considered a domain if any of the following is true:\n"
+ "\n"
+ " 1) it has an attribute associated with domains\n"
+ " 2) it is the source of a TE rule for object class other than filesystem\n"
+ " 3) it is the default type in a type_transition rule for object class process \n"
+ " 4) it is associated with a role other than object_r\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n"
+ "Module dependencies:\n" " none\n" "Module options:\n" " domain_attributes can be set in a profile\n";
+ mod->severity = SECHK_SEV_NONE;
+ /* assign requirements */
+ apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES));
+
+ /* assign options */
+ apol_vector_append(mod->options, sechk_name_value_new("domain_attribute", "domain"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_init;
+ apol_vector_append(mod->functions, fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_run;
+ apol_vector_append(mod->functions, fn_struct);
+
+ mod->data_free = find_domains_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_print;
+ apol_vector_append(mod->functions, fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_domains_get_list;
+ apol_vector_append(mod->functions, fn_struct);
+
+ return 0;
+}
+
+int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_domains_data_t *datum = NULL;
+ size_t i, j;
+ qpol_type_t *attr = NULL;
+ apol_vector_t *attr_vector = NULL;
+ apol_attr_query_t *attr_query = apol_attr_query_create();
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_domains_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!(datum->domain_attribs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "domain_attribute")) {
+ apol_attr_query_set_attr(policy, attr_query, opt->value);
+ apol_attr_get_by_query(policy, attr_query, &attr_vector);
+ for (j = 0; j < apol_vector_get_size(attr_vector); j++) {
+ const char *domain_attrib;
+ attr = apol_vector_get_element(attr_vector, j);
+ qpol_type_get_name(q, attr, &domain_attrib);
+ if (apol_vector_append(datum->domain_attribs, (void *)domain_attrib) < 0) {
+ apol_vector_destroy(&attr_vector);
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+
+ }
+ }
+ apol_vector_destroy(&attr_vector);
+ }
+ }
+ apol_attr_query_destroy(&attr_query);
+ return 0;
+}
+
+int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ int error = 0;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ const char *type_name = NULL;
+ find_domains_data_t *datum = NULL;
+ size_t i, j, proof_idx;
+ apol_vector_t *domain_vector = NULL, *avrule_vector = NULL, *terule_vector = NULL, *role_vector = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_role_query_t *role_query = NULL;
+ qpol_iterator_t *domain_attr_iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (find_domains_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = error;
+ return -1;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+
+ if (apol_type_get_by_query(policy, NULL, &domain_vector) < 0) {
+ goto find_domains_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ qpol_type_t *type = apol_vector_get_element(domain_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (qpol_type_get_attr_iter(q, type, &domain_attr_iter) < 0) {
+ error = errno;
+ ERR(policy, "Can't get attributes for type %s", type_name);
+ goto find_domains_run_fail;
+ }
+
+ for (; !qpol_iterator_end(domain_attr_iter); qpol_iterator_next(domain_attr_iter)) {
+ const char *attr_name;
+ const qpol_type_t *attr;
+ size_t nfta;
+
+ qpol_iterator_get_item(domain_attr_iter, (void **)&attr);
+ qpol_type_get_name(q, attr, &attr_name);
+ for (nfta = 0; nfta < apol_vector_get_size(datum->domain_attribs); nfta++) {
+ const char *domain_attrib;
+
+ domain_attrib = apol_vector_get_element(datum->domain_attribs, nfta);
+ if (!strcmp(attr_name, domain_attrib)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->elem = (void *)attr;
+ asprintf(&proof->text, "%s has attribute %s", type_name, attr_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ }
+ }
+ qpol_iterator_destroy(&domain_attr_iter);
+
+ /* rule src check !filesystem associate */
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 0);
+ if (apol_avrule_get_by_query(policy, avrule_query, &avrule_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve AV rules");
+ goto find_domains_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ const qpol_avrule_t *avrule = NULL;
+ const qpol_class_t *class = NULL;
+ const char *class_name = NULL;
+
+ avrule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_object_class(q, avrule, &class);
+ qpol_class_get_name(q, class, &class_name);
+ if (strcmp("filesystem", class_name)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* type rule check file object */
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_terule_query_set_default(policy, terule_query, type_name);
+ apol_terule_query_append_class(policy, terule_query, "process");
+ if (apol_terule_get_by_query(policy, terule_query, &terule_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve TE rules");
+ goto find_domains_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(terule_vector); j++) {
+ qpol_terule_t *terule = NULL;
+ terule = apol_vector_get_element(terule_vector, j);
+
+ if (apol_vector_get_index(item->proof, terule, sechk_proof_with_element_compare, NULL, &proof_idx) == 0)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_TERULE;
+ proof->elem = terule;
+ proof->text = apol_terule_render(policy, terule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ apol_vector_destroy(&terule_vector);
+ apol_terule_query_destroy(&terule_query);
+
+ /* Check Roles */
+ if (!(role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ apol_role_query_set_type(policy, role_query, type_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ for (j = 0; j < apol_vector_get_size(role_vector); j++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = (qpol_role_t *) apol_vector_get_element(role_vector, j);
+ qpol_role_get_name(q, role, &role_name);
+ if (!strcmp("object_r", role_name))
+ continue;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ proof->elem = (void *)role;
+ asprintf(&proof->text, "role %s types %s;", role_name, type_name);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ goto find_domains_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+ apol_role_query_destroy(&role_query);
+
+ /* insert any results for this type */
+ if (item) {
+ item->item = type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_domains_run_fail;
+ }
+ }
+ item = NULL;
+ type = NULL;
+ type_name = NULL;
+ }
+ apol_vector_destroy(&domain_vector);
+
+ /* results are valid at this point */
+ mod->result = res;
+ return 0;
+
+ find_domains_run_fail:
+ qpol_iterator_destroy(&domain_attr_iter);
+ apol_vector_destroy(&domain_vector);
+ apol_vector_destroy(&avrule_vector);
+ apol_vector_destroy(&terule_vector);
+ apol_vector_destroy(&role_vector);
+ apol_avrule_query_destroy(&avrule_query);
+ apol_terule_query_destroy(&terule_query);
+ apol_role_query_destroy(&role_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+void find_domains_data_free(void *data)
+{
+ find_domains_data_t *datum = (find_domains_data_t *) data;
+
+ if (datum) {
+ apol_vector_destroy(&datum->domain_attribs);
+ }
+ free(data);
+}
+
+int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_domains_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ sechk_proof_t *proof = NULL;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp("find_domains", mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_domains_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET)) {
+ return 0; /* not an error - no output is requested */
+ }
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i domain types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are domains.\n");
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+find_domains_data_t *find_domains_data_new(void)
+{
+ find_domains_data_t *datum = NULL;
+
+ datum = (find_domains_data_t *) calloc(1, sizeof(find_domains_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_domains.h b/sechecker/modules/find_domains.h
new file mode 100644
index 0000000..917cd41
--- /dev/null
+++ b/sechecker/modules/find_domains.h
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Defines the interface for the find domains utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_DOMAINS
+#define FIND_DOMAINS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+#include <apol/role-query.h>
+#include <apol/terule-query.h>
+#include <apol/avrule-query.h>
+
+ typedef struct find_domains_data
+ {
+ apol_vector_t *domain_attribs;
+ int num_domain_attribs;
+ } find_domains_data_t;
+
+ void find_domains_data_free(void *data);
+ find_domains_data_t *find_domains_data_new(void);
+
+ int find_domains_register(sechk_lib_t * lib);
+ int find_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_file_types.c b/sechecker/modules/find_file_types.c
new file mode 100644
index 0000000..193e3f3
--- /dev/null
+++ b/sechecker/modules/find_file_types.c
@@ -0,0 +1,636 @@
+/**
+ * @file
+ * Implementation of the find file types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Randy Wicks rwicks@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_file_types.h"
+
+#include <qpol/genfscon_query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_file_types";
+
+int find_file_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in the policy treated as a file type. A type is \n"
+ "considered a file type if any of the following is true:\n"
+ "\n"
+ " 1) it has an attribute associated with file types\n"
+ " 2) it is the source of a rule to allow filesystem associate permission\n"
+ " 3) it is the default type of a type transition rule with an object class\n" " other than process\n"
+ " 4) it is specified in a context in the file_contexts file\n";
+ mod->opt_description = "Module requirements:\n" " attribute names\n"
+ " file_contexts\n"
+ "Module dependencies:\n" " none\n" "Module options:\n" " file_type_attribute can be modified in a profile\n";
+ mod->severity = SECHK_SEV_NONE;
+ /* assign requirements */
+ nv = sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES);
+ apol_vector_append(mod->requirements, (void *)nv);
+ nv = sechk_name_value_new(SECHK_REQ_FILE_CONTEXTS, NULL);
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* assign options */
+ nv = sechk_name_value_new("file_type_attribute", "file_type");
+ apol_vector_append(mod->options, (void *)nv);
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = find_file_types_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_file_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_file_types_data_t *datum = NULL;
+ apol_vector_t *attr_vector = NULL;
+ apol_attr_query_t *attr_query = apol_attr_query_create();
+ qpol_type_t *attr = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i = 0, j = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_file_types_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ if (!(datum->file_type_attribs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "file_type_attribute")) {
+ apol_attr_query_set_attr(policy, attr_query, opt->value);
+ apol_attr_get_by_query(policy, attr_query, &attr_vector);
+ for (j = 0; j < apol_vector_get_size(attr_vector); j++) {
+ const char *file_attrib;
+ attr = apol_vector_get_element(attr_vector, j);
+ qpol_type_get_name(q, attr, &file_attrib);
+ if (apol_vector_append(datum->file_type_attribs, (void *)file_attrib) < 0) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ apol_vector_destroy(&attr_vector);
+ }
+ }
+ apol_attr_query_destroy(&attr_query);
+ return 0;
+}
+
+int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_file_types_data_t *datum;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *res = NULL;
+ const char *type_name = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_terule_query_t *terule_query = NULL;
+ apol_vector_t *avrule_vector = NULL;
+ apol_vector_t *terule_vector = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, j, x;
+ char *buff = NULL;
+ int error = 0;
+
+ /* NEW */
+ size_t num_fc_entries = 0;
+ apol_vector_t *type_vector = NULL;
+ apol_vector_t *fc_entry_vector = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ datum = (find_file_types_data_t *) mod->data;
+ res->item_type = SECHK_ITEM_TYPE;
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ if (mod->parent_lib->fc_entries) {
+ if (mod->parent_lib->fc_path) {
+ fc_entry_vector = mod->parent_lib->fc_entries;
+ num_fc_entries = apol_vector_get_size(fc_entry_vector);
+ } else {
+ error = ENOENT;
+ ERR(policy, "%s", "Unable to find file contexts file");
+ goto find_file_types_run_fail;
+ }
+ }
+
+ /* Get an iterator for the types */
+ if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve types");
+ return -1;
+ }
+
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ qpol_iterator_t *file_attr_iter;
+
+ const qpol_type_t *type = apol_vector_get_element(type_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ if (qpol_type_get_attr_iter(q, type, &file_attr_iter) < 0) {
+ error = errno;
+ ERR(policy, "Could not get attributes for %s\n", type_name);
+ goto find_file_types_run_fail;
+ }
+
+ for (; !qpol_iterator_end(file_attr_iter); qpol_iterator_next(file_attr_iter)) {
+ const char *attr_name;
+ const qpol_type_t *attr;
+ size_t nfta;
+
+ qpol_iterator_get_item(file_attr_iter, (void **)&attr);
+ qpol_type_get_name(q, attr, &attr_name);
+ for (nfta = 0; nfta < apol_vector_get_size(datum->file_type_attribs); nfta++) {
+ const char *file_type_attrib;
+
+ file_type_attrib = apol_vector_get_element(datum->file_type_attribs, nfta);
+ if (!strcmp(attr_name, file_type_attrib)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ATTRIB;
+ proof->elem = (void *)attr;
+ asprintf(&proof->text, "has attribute %s", attr_name);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ }
+ qpol_iterator_destroy(&file_attr_iter);
+
+ /* rule src check filesystem associate */
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", "Could not retrieve AV rules");
+ goto find_file_types_run_fail;
+ }
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 0);
+ apol_avrule_query_append_class(policy, avrule_query, "filesystem");
+ apol_avrule_query_append_perm(policy, avrule_query, "associate");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (x = 0; x < apol_vector_get_size(avrule_vector); x++) {
+ qpol_avrule_t *avrule;
+ avrule = apol_vector_get_element(avrule_vector, x);
+ if (avrule) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = avrule;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* type rule check file object */
+ if (!(terule_query = apol_terule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", "Could not retrieve TE rules");
+ goto find_file_types_run_fail;
+ }
+ apol_terule_query_set_default(policy, terule_query, type_name);
+ apol_terule_get_by_query(policy, terule_query, &terule_vector);
+ for (x = 0; x < apol_vector_get_size(terule_vector); x++) {
+ const qpol_terule_t *terule;
+ const qpol_class_t *objclass;
+ const char *class_name;
+
+ terule = apol_vector_get_element(terule_vector, x);
+ qpol_terule_get_object_class(q, terule, &objclass);
+ qpol_class_get_name(q, objclass, &class_name);
+ if (strcmp(class_name, "process")) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_TERULE;
+ proof->elem = (void *)terule;
+ proof->text = apol_terule_render(policy, terule);
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item->test_result = 1;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&terule_vector);
+ apol_terule_query_destroy(&terule_query);
+
+ /* assigned in fc check */
+ if (fc_entry_vector) {
+ buff = NULL;
+ for (j = 0; j < num_fc_entries; j++) {
+ sefs_entry_t *fc_entry;
+ const char *fc_type_name = NULL;
+ fc_entry = apol_vector_get_element(fc_entry_vector, j);
+ const apol_context_t *context = sefs_entry_get_context(fc_entry);
+ if (!context)
+ continue;
+ fc_type_name = apol_context_get_type(context);
+ if (!strcmp(type_name, fc_type_name)) {
+ buff = sefs_entry_to_string(fc_entry);
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_FCENT;
+ proof->elem = fc_entry;
+ proof->text = buff;
+ buff = NULL;
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ }
+ }
+ /* insert any results for this type */
+ if (item) {
+ item->item = (void *)type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_file_types_run_fail;
+ }
+ }
+ item = NULL;
+ type = NULL;
+ type_name = NULL;
+ }
+ apol_vector_destroy(&type_vector);
+
+ /* results are valid at this point */
+ mod->result = res;
+
+ return 0;
+
+ find_file_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ apol_vector_destroy(&type_vector);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+void find_file_types_data_free(void *data)
+{
+ find_file_types_data_t *datum = (find_file_types_data_t *) data;
+
+ if (datum) {
+ apol_vector_destroy(&datum->file_type_attribs);
+ }
+ free(data);
+}
+
+int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_file_types_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_file_types_data_t *) mod->data;
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+ if (outformat & SECHK_OUT_STATS) {
+ num_items = apol_vector_get_size(mod->result->items);
+ printf("Found %zd file types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types are file types.\n\n");
+ }
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < apol_vector_get_size(mod->result->items); k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg
+ __attribute__ ((unused)))
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+find_file_types_data_t *find_file_types_data_new(void)
+{
+ find_file_types_data_t *datum = NULL;
+
+ datum = (find_file_types_data_t *) calloc(1, sizeof(find_file_types_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_file_types.h b/sechecker/modules/find_file_types.h
new file mode 100644
index 0000000..941862b
--- /dev/null
+++ b/sechecker/modules/find_file_types.h
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Defines the interface for the find file types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Randy Wicks rwicks@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_FILE_TYPES
+#define FIND_FILE_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/type-query.h>
+#include <apol/avrule-query.h>
+#include <apol/terule-query.h>
+
+ typedef struct find_file_types_data
+ {
+ apol_vector_t *file_type_attribs;
+ int num_file_type_attribs;
+ } find_file_types_data_t;
+
+ void find_file_types_data_free(void *data);
+ find_file_types_data_t *find_file_types_data_new(void);
+
+ int find_file_types_register(sechk_lib_t * lib);
+ int find_file_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_file_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_net_domains.c b/sechecker/modules/find_net_domains.c
new file mode 100644
index 0000000..dadd459
--- /dev/null
+++ b/sechecker/modules/find_net_domains.c
@@ -0,0 +1,501 @@
+/**
+ * @file
+ * Implementation of the network domain utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_net_domains.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_net_domains";
+
+int find_net_domains_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy considered to be network domains. \n"
+ "A type is considered a network domain if it is the subject of TE rules \n"
+ "involving certain object classes, which are currently defined as:\n"
+ " 1) netif\n"
+ " 2) tcp_socket\n"
+ " 3) udp_socket\n"
+ " 4) node\n" " 5) association\n" "These values can be overridden in this module's profile.";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n"
+ " net_obj\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* assign default options */
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "netif"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "tcp_socket"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "udp_socket"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "node"));
+ apol_vector_append(mod->options, sechk_name_value_new("net_obj", "association"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = find_net_domains_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_net_domains_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ find_net_domains_data_t *datum = NULL;
+ size_t i;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = find_net_domains_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (!(datum->net_objs = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ if (!strcmp(opt->name, "net_obj")) {
+ if (apol_vector_append(datum->net_objs, (void *)opt->value) < 0) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_net_domains_data_t *datum;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error = 0;
+ size_t i = 0, j = 0, k = 0;
+ apol_vector_t *avrule_vector;
+ apol_avrule_query_t *avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (find_net_domains_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (k = 0; k < apol_vector_get_size(avrule_vector); k++) {
+ const qpol_avrule_t *avrule;
+ const qpol_class_t *class;
+ const char *class_name;
+
+ avrule = apol_vector_get_element(avrule_vector, k);
+ qpol_avrule_get_object_class(q, avrule, &class);
+ qpol_class_get_name(q, class, &class_name);
+ for (i = 0; i < apol_vector_get_size(datum->net_objs); i++) {
+ const char *net_obj_name;
+
+ net_obj_name = apol_vector_get_element(datum->net_objs, i);
+ if (!strcmp(class_name, net_obj_name)) {
+ const qpol_type_t *source;
+ const char *source_name;
+
+ qpol_avrule_get_source_type(q, avrule, &source);
+ qpol_type_get_name(q, source, &source_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)avrule;
+ proof->text = apol_avrule_render(policy, avrule);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item = NULL;
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, source_name))
+ item = res_item;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)source;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_net_domains_run_fail;
+ }
+ item = NULL;
+ }
+ }
+ }
+ apol_avrule_query_destroy(&avrule_query);
+ apol_vector_destroy(&avrule_vector);
+ mod->result = res;
+
+ return 0;
+
+ find_net_domains_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module */
+void find_net_domains_data_free(void *data)
+{
+ find_net_domains_data_t *d = data;
+ apol_vector_destroy(&d->net_objs);
+ free(data);
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ find_net_domains_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (find_net_domains_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("\nFound %i network domains.", num_items);
+ }
+
+ /* The list renode component is a display of all items
+ * found without any supnodeing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renode component is a display of a list of items
+ * with an indented list of proof statements supnodeing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
+
+/* The find_net_domains_data_new function allocates and returns an
+ * initialized private data storage structure for this
+ * module. Initialization expected is as follows:
+ * all arrays (including strings) are initialized to NULL
+ * array sizes are set to 0
+ * any other pointers should be NULL
+ * indices into other arrays (such as type or permission indices)
+ * should be initialized to -1
+ * any other data should be initialized as needed by the check logic */
+find_net_domains_data_t *find_net_domains_data_new(void)
+{
+ find_net_domains_data_t *datum = NULL;
+
+ datum = (find_net_domains_data_t *) calloc(1, sizeof(find_net_domains_data_t));
+
+ return datum;
+}
diff --git a/sechecker/modules/find_net_domains.h b/sechecker/modules/find_net_domains.h
new file mode 100644
index 0000000..68eeb75
--- /dev/null
+++ b/sechecker/modules/find_net_domains.h
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * Defines the interface for the network domain utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NET_DOMAINS
+#define FIND_NET_DOMAINS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+/* The find_net_domains_data structure is used to hold the check specific
+ * private data of a module. */
+ typedef struct find_net_domains_data
+ {
+ apol_vector_t *net_objs;
+ } find_net_domains_data_t;
+
+ find_net_domains_data_t *find_net_domains_data_new(void);
+ void find_net_domains_data_free(void *data);
+
+ int find_net_domains_register(sechk_lib_t * lib);
+ int find_net_domains_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_net_domains_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_netif_types.c b/sechecker/modules/find_netif_types.c
new file mode 100644
index 0000000..e703687
--- /dev/null
+++ b/sechecker/modules/find_netif_types.c
@@ -0,0 +1,489 @@
+/**
+ * @file
+ * Implementation of the netif types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_netif_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_netif_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int find_netif_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a netif type. A type is\n"
+ "a netif type if it is used in the internace context in a netifcon statement or\n"
+ "the context of the netif initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_netif_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t i, buff_sz = 0;
+ apol_vector_t *netifcon_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "netif", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid netif ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_netif_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ free(tmp);
+ apol_context_destroy(&a_context);
+ goto find_netif_types_run_fail;
+ }
+ apol_context_destroy(&a_context);
+ free(tmp);
+ tmp = NULL;
+
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item->test_result = 1;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ item->item = (void *)context_type;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+
+ if (apol_netifcon_get_by_query(policy, NULL, &netifcon_vector) < 0) {
+ error = errno;
+ goto find_netif_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(netifcon_vector); i++) {
+ const char *msg_con_name = NULL;
+ const char *if_con_name = NULL;
+ qpol_netifcon_t *netifcon = NULL;
+ const qpol_context_t *msg_con = NULL;
+ const qpol_context_t *if_con = NULL;
+ const qpol_type_t *msg_type = NULL;
+ const qpol_type_t *if_type = NULL;
+ size_t j = 0;
+
+ netifcon = apol_vector_get_element(netifcon_vector, i);
+ qpol_netifcon_get_msg_con(q, netifcon, &msg_con);
+ qpol_netifcon_get_if_con(q, netifcon, &if_con);
+ qpol_context_get_type(q, msg_con, &msg_type);
+ qpol_context_get_type(q, if_con, &if_type);
+ qpol_type_get_name(q, msg_type, &msg_con_name);
+ qpol_type_get_name(q, if_type, &if_con_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_NETIFCON;
+ proof->elem = netifcon;
+ proof->text = apol_netifcon_render(policy, netifcon);
+ item = NULL;
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = (qpol_type_t *) res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, if_con_name))
+ item = res_item;
+ }
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)if_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_netif_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&netifcon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_netif_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text and prints the
+ * results to stdout. The outline below prints
+ * the standard format of a renetif section. Some modules may
+ * not have results in a format that can be represented by this
+ * outline and will need a different specification. It is
+ * required that each of the flags for output components be
+ * tested in this function (stats, list, proof, detailed, and brief) */
+int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i netif types.\n", num_items);
+ }
+
+ /* The list renetif component is a display of all items
+ * found without any supnetifing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renetif component is a display of a list of items
+ * with an indented list of proof statements supnetifing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_netif_types.h b/sechecker/modules/find_netif_types.h
new file mode 100644
index 0000000..859ee8a
--- /dev/null
+++ b/sechecker/modules/find_netif_types.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the netif types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NETIF_TYPES_H
+#define FIND_NETIF_TYPES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_netif_types_register(sechk_lib_t * lib);
+ int find_netif_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_netif_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_node_types.c b/sechecker/modules/find_node_types.c
new file mode 100644
index 0000000..f10be10
--- /dev/null
+++ b/sechecker/modules/find_node_types.c
@@ -0,0 +1,479 @@
+/**
+ * @file
+ * Implementation of the node types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_node_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_node_types";
+
+/* The register function registers all of a module's functions
+ * with the library. You should not need to edit this function
+ * unless you are adding additional functions you need other modules
+ * to call. See the note at the bottom of this function to do so. */
+int find_node_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Unknown module");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a node type. A type is\n"
+ "considered a node type if it is used in the context of a nodecon statement or\n"
+ "the context of the node initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_node_types_get_list;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t i, buff_sz = 0;
+ apol_vector_t *nodecon_vector = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "node", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid node ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_node_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ free(tmp);
+ goto find_node_types_run_fail;
+ }
+ apol_context_destroy(&a_context);
+ free(tmp);
+ tmp = NULL;
+
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item->test_result = 1;
+ }
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ item->item = (void *)context_type;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+
+ if (apol_nodecon_get_by_query(policy, NULL, &nodecon_vector) < 0) {
+ error = errno;
+ goto find_node_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(nodecon_vector); i++) {
+ const char *type_name;
+ size_t j;
+ const qpol_context_t *context;
+ const qpol_type_t *context_type;
+ qpol_nodecon_t *nodecon = apol_vector_get_element(nodecon_vector, i);
+ qpol_nodecon_get_context(q, nodecon, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &type_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->text = apol_nodecon_render(policy, nodecon);
+
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, type_name))
+ item = res_item;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)context_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_node_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&nodecon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_node_types_run_fail:
+ apol_vector_destroy(&nodecon_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the results to stdout. */
+int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i node types.\n", num_items);
+ }
+
+ /* The list renode component is a display of all items
+ * found without any supnodeing proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof renode component is a display of a list of items
+ * with an indented list of proof statements supnodeing the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_node_types.h b/sechecker/modules/find_node_types.h
new file mode 100644
index 0000000..44ac749
--- /dev/null
+++ b/sechecker/modules/find_node_types.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the node types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_NODE_TYPES_H
+#define FINE_NODE_TYPES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int find_node_types_register(sechk_lib_t * lib);
+ int find_node_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_node_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/find_port_types.c b/sechecker/modules/find_port_types.c
new file mode 100644
index 0000000..8e55bc3
--- /dev/null
+++ b/sechecker/modules/find_port_types.c
@@ -0,0 +1,513 @@
+/**
+ * @file
+ * Implementation of the port types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "find_port_types.h"
+#include <apol/netcon-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "find_port_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int find_port_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "utility module";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all types in a policy treated as a port type. A type is\n"
+ "considered a port type if it is used in the context of a a portcon statement or\n"
+ "the context of the port initial sid.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_NONE;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = find_port_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = &find_port_types_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ char *buff = NULL;
+ size_t buff_sz = 0, i, j;
+ apol_vector_t *portcon_vector;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+
+ /* search initial SIDs */
+ const qpol_isid_t *isid = NULL;
+ buff = NULL;
+ qpol_policy_get_isid_by_name(q, "port", &isid);
+ if (isid) {
+ const qpol_context_t *context;
+ apol_context_t *a_context;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+ char *tmp;
+
+ proof = NULL;
+ qpol_isid_get_context(q, isid, &context);
+ qpol_context_get_type(q, context, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ a_context = apol_context_create_from_qpol_context(policy, context);
+
+ if (apol_str_append(&buff, &buff_sz, "sid port ") != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ goto find_port_types_run_fail;
+ }
+
+ tmp = apol_context_render(policy, a_context);
+ if (apol_str_append(&buff, &buff_sz, tmp) != 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ apol_context_destroy(&a_context);
+ free(tmp);
+ goto find_port_types_run_fail;
+ }
+ free(tmp);
+ tmp = NULL;
+ apol_context_destroy(&a_context);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+
+ proof->type = SECHK_ITEM_ISID;
+ proof->elem = (void *)isid;
+ proof->text = buff;
+
+ /* Have we encountered this type before? If so, use that type. */
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, context_type_name))
+ item = res_item;
+ }
+
+ /* We have not encountered this type yet */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)context_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (apol_portcon_get_by_query(policy, NULL, &portcon_vector) < 0) {
+ error = errno;
+ goto find_port_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(portcon_vector); i++) {
+ const char *portcon_name = NULL;
+ const qpol_portcon_t *portcon = NULL;
+ const qpol_context_t *portcon_context = NULL;
+ const qpol_type_t *portcon_type = NULL;
+
+ portcon = apol_vector_get_element(portcon_vector, i);
+ qpol_portcon_get_context(q, portcon, &portcon_context);
+ qpol_context_get_type(q, portcon_context, &portcon_type);
+ qpol_type_get_name(q, portcon_type, &portcon_name);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_PORTCON;
+ proof->elem = (void *)portcon;
+ proof->text = apol_portcon_render(policy, portcon);
+ item = NULL;
+
+ /* Have we encountered this type before? If so, use that type. */
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item = NULL;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(res_type_name, portcon_name))
+ item = res_item;
+ }
+
+ /* We have not encountered this type yet */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)portcon_type;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto find_port_types_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&portcon_vector);
+
+ mod->result = res;
+
+ return 0;
+
+ find_port_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(buff);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, num_items = 0;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i port types.\n", num_items);
+ }
+
+ /* The list report component is a display of all items
+ * found without any supporting proof. The default method
+ * is to display a comma separated list four items to a line
+ * this may need to be changed for longer items. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with (or, if long, such as a
+ * rule, followed by) the severity. Each proof element is then
+ * displayed in an indented list one per line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (j = 0; j < num_items; j++) {
+ item = apol_vector_get_element(mod->result->items, j);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ if (item) {
+ printf("%s\n", type_name);
+ for (k = 0; k < apol_vector_get_size(item->proof); k++) {
+ proof = apol_vector_get_element(item->proof, k);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/find_port_types.h b/sechecker/modules/find_port_types.h
new file mode 100644
index 0000000..adb19bf
--- /dev/null
+++ b/sechecker/modules/find_port_types.h
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * Defines the interface for the port types utility module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIND_PORT_TYPES
+#define FIND_PORT_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/context-query.h>
+#include <apol/netcon-query.h>
+
+ int find_port_types_register(sechk_lib_t * lib);
+ int find_port_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int find_port_types_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/imp_range_trans.c b/sechecker/modules/imp_range_trans.c
new file mode 100644
index 0000000..8fbf361
--- /dev/null
+++ b/sechecker/modules/imp_range_trans.c
@@ -0,0 +1,513 @@
+/**
+ * @file
+ * Implementation of the impossible range_transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author: David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "imp_range_trans.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define SECHK_NO_ROLES 0x000002
+#define SECHK_BAD_USER_MLS_LOW 0x000040
+#define SECHK_BAD_USER_MLS_HIGH 0x000600
+#define SECHK_NO_USERS 0x008000
+#define SECHK_NO_EXEC_PERMS 0x020000
+
+static const char *const mod_name = "imp_range_trans";
+
+int imp_range_trans_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "finds impossible range transitions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds impossible range transitions in a policy.\n"
+ "A range transition is possible if and only if all of the following conditions\n"
+ "are satisfied:\n"
+ " 1) there exist TE rules allowing the range transition to occur\n"
+ " 2) there exist RBAC rules allowing the range transition to occur\n"
+ " 3) at least one user must be able to transition to the target MLS range\n";
+ mod->opt_description =
+ " Module requirements:\n" " MLS policy\n" " Module dependencies:\n" " none\n" " Module options:\n"
+ " none\n";
+ mod->severity = SECHK_SEV_MED;
+
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_MLS)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = imp_range_trans_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j;
+ apol_vector_t *range_trans_vector = NULL, *role_vector = NULL, *tmp_v = NULL;
+ apol_vector_t *user_vector = NULL, *users_w_roles = NULL, *users_w_range = NULL;
+ apol_vector_t *rule_vector = NULL;
+ const qpol_range_trans_t *rule;
+ const qpol_type_t *source = NULL;
+ const qpol_type_t *target = NULL;
+ const qpol_role_t *role = NULL;
+ const char *source_name = NULL, *target_name = NULL, *role_name = NULL;
+ apol_role_query_t *role_query = NULL;
+ apol_user_query_t *user_query = NULL;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_mls_range_t *range;
+ const qpol_mls_range_t *qpol_range;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ res->item_type = SECHK_ITEM_RANGETRANS;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+
+ if (apol_range_trans_get_by_query(policy, NULL, &range_trans_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve range transitions");
+ goto imp_range_trans_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(range_trans_vector); i++) {
+ /* collect information about the rule */
+ rule = apol_vector_get_element(range_trans_vector, i);
+ qpol_range_trans_get_source_type(q, rule, &source);
+ qpol_range_trans_get_target_type(q, rule, &target);
+ qpol_type_get_name(q, source, &source_name);
+ qpol_type_get_name(q, target, &target_name);
+ qpol_range_trans_get_range(q, rule, &qpol_range);
+ range = apol_mls_range_create_from_qpol_mls_range(policy, qpol_range);
+
+ /* find roles possible for source */
+ role_query = apol_role_query_create();
+ apol_role_query_set_type(policy, role_query, source_name);
+ apol_role_get_by_query(policy, role_query, &role_vector);
+ apol_role_query_destroy(&role_query);
+
+ /* find users with the possible roles */
+ if ((users_w_roles = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ goto imp_range_trans_run_fail;
+ }
+ user_query = apol_user_query_create();
+ for (j = 0; j < apol_vector_get_size(role_vector); j++) {
+ role = apol_vector_get_element(role_vector, j);
+ qpol_role_get_name(q, role, &role_name);
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &tmp_v);
+ apol_vector_cat(users_w_roles, tmp_v);
+ apol_vector_destroy(&tmp_v);
+ }
+ apol_vector_sort_uniquify(users_w_roles, NULL, NULL);
+ apol_user_query_destroy(&user_query);
+
+ /* find users with the transition range */
+ user_query = apol_user_query_create();
+ apol_user_query_set_range(policy, user_query, range, APOL_QUERY_SUB);
+ apol_user_get_by_query(policy, user_query, &users_w_range);
+ apol_user_query_destroy(&user_query);
+
+ /* find intersection of user sets */
+ user_vector = apol_vector_create_from_intersection(users_w_roles, users_w_range, NULL, NULL);
+
+ /* find avrules for allow <source> <target> : file execute; */
+ avrule_query = apol_avrule_query_create();
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, avrule_query, source_name, 1);
+ apol_avrule_query_set_target(policy, avrule_query, target_name, 1);
+ apol_avrule_query_append_class(policy, avrule_query, "file");
+ apol_avrule_query_append_perm(policy, avrule_query, "execute");
+ apol_avrule_get_by_query(policy, avrule_query, &rule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ /* check avrules */
+ if (!apol_vector_get_size(rule_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ asprintf(&proof->text, "Missing: allow %s %s : file execute;", source_name, target_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ proof = NULL;
+ }
+ apol_vector_destroy(&rule_vector);
+
+ /* check RBAC */
+ if (!apol_vector_get_size(role_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ asprintf(&proof->text, "No role associated with type %s", source_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ proof = NULL;
+ }
+
+ /* check users */
+ if (!apol_vector_get_size(user_vector)) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ if (!apol_vector_get_size(role_vector)) {
+ proof->text = strdup("No role also means no user");
+ } else if (!apol_vector_get_size(users_w_roles)) {
+ asprintf(&proof->text, "No users associated with roles for %s", source_name);
+ } else if (!apol_vector_get_size(users_w_range)) {
+ proof->text = strdup("No user has access to specified MLS range");
+ } else {
+ proof->text = strdup("No user meets MLS and RBAC requirements.");
+ }
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ error = ENOMEM;
+ goto imp_range_trans_run_fail;
+ }
+ item->item = (void *)rule;
+ item->test_result = 1;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&users_w_roles);
+ apol_vector_destroy(&users_w_range);
+
+ if (item) {
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto imp_range_trans_run_fail;
+ }
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&range_trans_vector);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ imp_range_trans_run_fail:
+ apol_vector_destroy(&range_trans_vector);
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&rule_vector);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&users_w_roles);
+ apol_vector_destroy(&users_w_range);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text and prints the
+ * results to stdout. */
+int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ qpol_range_trans_t *rt;
+ char *tmp;
+ size_t i = 0, k = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i impossible range transitions.\n", num_items);
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ rt = item->item;
+ printf("%s\n", (tmp = apol_range_trans_render(policy, rt)));
+ free(tmp);
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ rt = item->item;
+ printf("%s\n", (tmp = apol_range_trans_render(policy, rt)));
+ free(tmp);
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/imp_range_trans.h b/sechecker/modules/imp_range_trans.h
new file mode 100644
index 0000000..04ceba0
--- /dev/null
+++ b/sechecker/modules/imp_range_trans.h
@@ -0,0 +1,52 @@
+/**
+ * @file
+ * Defines the interface for the impossible range_transition module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author: David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IMP_RANGE_TRANS
+#define IMP_RANGE_TRANS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/user-query.h>
+#include <apol/range_trans-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/domain-trans-analysis.h>
+#include <apol/policy-query.h>
+
+ int imp_range_trans_register(sechk_lib_t * lib);
+ int imp_range_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int imp_range_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int imp_range_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IMP_RANGE_TRANS */
diff --git a/sechecker/modules/inc_dom_trans.c b/sechecker/modules/inc_dom_trans.c
new file mode 100644
index 0000000..fe6957d
--- /dev/null
+++ b/sechecker/modules/inc_dom_trans.c
@@ -0,0 +1,913 @@
+/**
+ * @file
+ * Defines the interface for the incomplete domain transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_dom_trans.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "inc_dom_trans";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int inc_dom_trans_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with partial transition permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds potential domain transitions missing key permissions. A valid\n"
+ "domain transition requires the following.\n"
+ "\n"
+ " 1) the starting domain can transition to the end domain for class process\n"
+ " 2) the end domain has some type as an entrypoint\n"
+ " 3) the starting domain can execute that extrypoint type\n"
+ " 4) (optional) a type transition rules specifying these three types\n";
+ mod->opt_description =
+ "Module requirements:\n"
+ " attribute names\n" "Module dependencies:\n" " find_domains\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ /* Dependencies */
+ apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains"));
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_dom_trans_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid paramaters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* wrapper for apol_domain_trans_result_destroy() */
+void dtr_free_wrap(void *x)
+{
+ apol_domain_trans_result_destroy((apol_domain_trans_result_t **) & x);
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. */
+int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL, *tmp_item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j, k, retv;
+ sechk_module_t *mod_ptr = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ sechk_result_t *find_domains_res = NULL;
+ apol_domain_trans_analysis_t *domain_trans = NULL;
+ apol_vector_t *domain_vector = NULL, *role_vector = NULL, *user_vector = NULL, *rbac_vector = NULL;
+ apol_vector_t *domain_trans_vector = NULL, *role_allow_vector = NULL;
+ apol_user_query_t *user_query = NULL;
+ apol_role_query_t *start_role_query = NULL, *end_role_query = NULL;
+ apol_role_trans_query_t *role_trans_query = NULL;
+ apol_role_allow_query_t *role_allow_query = NULL;
+ char *buff = NULL;
+ int buff_sz, error = 0;
+ const qpol_type_t *domain = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *domain_name = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = EINVAL;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ res->item_type = SECHK_ITEM_DTR;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (apol_policy_build_domain_trans_table(policy) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to build domain transition table");
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(domain_trans = apol_domain_trans_analysis_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(user_query = apol_user_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(role_trans_query = apol_role_trans_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(role_allow_query = apol_role_allow_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(start_role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(end_role_query = apol_role_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ run_fn = sechk_lib_get_module_function("find_domains", SECHK_MOD_FN_RUN, mod->parent_lib);
+ if (!run_fn) {
+ error = errno;
+ goto inc_dom_trans_run_fail;
+ }
+
+ retv = run_fn((mod_ptr = sechk_lib_get_module("find_domains", mod->parent_lib)), policy, NULL);
+ if (retv) {
+ error = errno;
+ ERR(policy, "%s", "Unable to find module find_domains");
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (!(find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib))) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results from module find_domains");
+ goto inc_dom_trans_run_fail;
+ }
+
+ domain_vector = (apol_vector_t *) find_domains_res->items;
+
+ for (i = 0; i < apol_vector_get_size(domain_vector); i++) {
+ tmp_item = apol_vector_get_element(domain_vector, i);
+ domain = tmp_item->item;
+ qpol_type_get_name(q, domain, &domain_name);
+ apol_domain_trans_analysis_set_start_type(policy, domain_trans, domain_name);
+ apol_domain_trans_analysis_set_direction(policy, domain_trans, APOL_DOMAIN_TRANS_DIRECTION_FORWARD);
+ apol_domain_trans_analysis_set_valid(policy, domain_trans, APOL_DOMAIN_TRANS_SEARCH_BOTH);
+ apol_domain_trans_analysis_do(policy, domain_trans, &domain_trans_vector);
+
+ for (j = 0; j < apol_vector_get_size(domain_trans_vector); j++) {
+ apol_domain_trans_result_t *dtr = NULL;
+ const qpol_type_t *start;
+ const qpol_type_t *ep;
+ const qpol_type_t *end;
+ const char *start_name;
+ const char *end_name;
+ const char *ep_name;
+ int result;
+ bool ok;
+
+ ok = false;
+ dtr = apol_vector_get_element(domain_trans_vector, j);
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ result = apol_domain_trans_table_verify_trans(policy, start, ep, end);
+ if (!result) {
+ apol_vector_t *start_role_vector, *end_role_vector, *common_role_vector;
+ apol_role_query_set_type(policy, start_role_query, start_name);
+ apol_role_get_by_query(policy, start_role_query, &start_role_vector);
+ apol_role_query_set_type(policy, end_role_query, end_name);
+ apol_role_get_by_query(policy, end_role_query, &end_role_vector);
+ if (!apol_vector_get_size(start_role_vector) || !apol_vector_get_size(end_role_vector)) {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!apol_vector_get_size(start_role_vector)) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need role for %s", start_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ if (!apol_vector_get_size(end_role_vector)) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need role for %s", end_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ item = NULL;
+ //if one of the domains has no roles continue; no more can be determined
+ apol_vector_destroy(&start_role_vector);
+ apol_vector_destroy(&end_role_vector);
+ continue;
+ }
+ common_role_vector =
+ apol_vector_create_from_intersection(start_role_vector, end_role_vector, NULL, NULL);
+ const char *role_name = NULL;
+ if (apol_vector_get_size(common_role_vector)) {
+ for (int k = 0; k < apol_vector_get_size(common_role_vector); k++) {
+ const qpol_role_t *common_role;
+
+ common_role = apol_vector_get_element(common_role_vector, k);
+ qpol_role_get_name(q, common_role, &role_name);
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &user_vector);
+ if (apol_vector_get_size(user_vector)) {
+ ok = true;
+ apol_vector_destroy(&user_vector);
+ break;
+ }
+ apol_vector_destroy(&user_vector);
+ }
+ if (!ok) {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "Need user for role %s", role_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item = NULL;
+ }
+ } else {
+ apol_vector_t *role_trans_vector;
+ bool need_ra = 0, need_user = 0;
+ char *rastring = NULL, *userstring = NULL;
+ apol_role_trans_query_set_target(policy, role_trans_query, ep_name, 1);
+ apol_role_trans_get_by_query(policy, role_trans_query, &role_trans_vector);
+ const char *source_role_name = NULL, *default_role_name = NULL;
+ for (k = 0; k < apol_vector_get_size(role_trans_vector); k++) {
+ qpol_role_trans_t *role_trans;
+ const qpol_role_t *source_role;
+ const qpol_role_t *default_role;
+ int index;
+
+ role_trans = apol_vector_get_element(role_trans_vector, k);
+ qpol_role_trans_get_source_role(q, role_trans, &source_role);
+ qpol_role_trans_get_default_role(q, role_trans, &default_role);
+ if ((apol_vector_get_index(start_role_vector, source_role, NULL, NULL, &index) == 0)
+ && (apol_vector_get_index(end_role_vector, default_role, NULL, NULL, &index) ==
+ 0)) {
+ apol_vector_t *source_role_user, *default_role_user, *common_role_user;
+
+ qpol_role_get_name(q, source_role, &source_role_name);
+ qpol_role_get_name(q, default_role, &default_role_name);
+ apol_role_allow_query_set_source(policy, role_allow_query,
+ source_role_name);
+ apol_role_allow_query_set_target(policy, role_allow_query,
+ default_role_name);
+ apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector);
+
+ apol_user_query_set_role(policy, user_query, source_role_name);
+ apol_user_get_by_query(policy, user_query, &source_role_user);
+ apol_user_query_set_role(policy, user_query, default_role_name);
+ apol_user_get_by_query(policy, user_query, &default_role_user);
+
+ common_role_user =
+ apol_vector_create_from_intersection(source_role_user,
+ default_role_user, NULL, NULL);
+ apol_vector_destroy(&source_role_user);
+ apol_vector_destroy(&default_role_user);
+ if (apol_vector_get_size(role_allow_vector) &&
+ apol_vector_get_size(common_role_user)) {
+ ok = true;
+ apol_vector_destroy(&role_allow_vector);
+ apol_vector_destroy(&common_role_user);
+ break;
+ }
+ if (!apol_vector_get_size(role_allow_vector)) {
+ // need role allow;
+ asprintf(&rastring, "allow %s %s;", source_role_name,
+ default_role_name);
+ if (!rastring) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_allow_vector);
+ if (!apol_vector_get_size(common_role_user)) {
+ // need user;
+ asprintf(&userstring, "need user with roles %s and %s",
+ source_role_name, default_role_name);
+ if (!userstring) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ apol_vector_destroy(&common_role_user);
+ }
+ }
+ apol_vector_destroy(&role_trans_vector);
+ if (!ok) {
+ if (!need_ra && !need_user) {
+ const qpol_role_t *source_role =
+ apol_vector_get_element(start_role_vector, 0);
+ const qpol_role_t *default_role =
+ apol_vector_get_element(end_role_vector, 0);
+ qpol_role_get_name(q, source_role, &source_role_name);
+ qpol_role_get_name(q, default_role, &default_role_name);
+ // need role_transition
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)
+ apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ asprintf(&proof->text, "role_transition %s %s %s;", source_role_name,
+ ep_name, default_role_name);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item = NULL;
+ } else {
+ //create item
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)
+ apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (need_ra) {
+ //create proof w/ text rastring
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ proof->text = rastring;
+ rastring = NULL;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ if (need_user) {
+ //create proof w/ text userstring
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ proof->text = userstring;
+ userstring = NULL;
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ item = NULL;
+ }
+ }
+ }
+ apol_vector_destroy(&start_role_vector);
+ apol_vector_destroy(&end_role_vector);
+ apol_vector_destroy(&common_role_vector);
+ } else {
+ item = sechk_item_new(dtr_free_wrap);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)apol_domain_trans_result_create_from_domain_trans_result(dtr);
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz =
+ 10 + strlen("allow : process transition;") + strlen(start_name) + strlen(end_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : process transition;", start_name, end_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_EXEC) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow : file execute;") + strlen(start_name) + strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : file execute;", start_name, ep_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow : file entrypoint;") + strlen(end_name) + strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s %s : file entrypoint;", end_name, ep_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_TYPE_TRANS) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz =
+ 10 + strlen("type_transition :process ;") + strlen(start_name) + strlen(end_name) +
+ strlen(ep_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "type_transition %s %s : process %s;", start_name, ep_name,
+ end_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+
+ if (result & APOL_DOMAIN_TRANS_RULE_SETEXEC) {
+ proof = sechk_proof_new(NULL);
+ proof->type = SECHK_ITEM_OTHER;
+ buff = NULL;
+ buff_sz = 10 + strlen("allow self : process setexec;") + strlen(start_name);
+ buff = (char *)calloc(buff_sz, sizeof(char));
+ if (!buff) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ snprintf(buff, buff_sz, "allow %s self : process setexec;", start_name);
+ proof->text = strdup(buff);
+ free(buff);
+ buff = NULL;
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_dom_trans_run_fail;
+ }
+ }
+ }
+ }
+ apol_vector_destroy(&domain_trans_vector);
+ }
+
+ mod->result = res;
+ apol_domain_trans_analysis_destroy(&domain_trans);
+ apol_user_query_destroy(&user_query);
+ apol_role_trans_query_destroy(&role_trans_query);
+ apol_role_query_destroy(&start_role_query);
+ apol_role_query_destroy(&end_role_query);
+ apol_role_allow_query_destroy(&role_allow_query);
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_dom_trans_run_fail:
+ sechk_item_free(item);
+ apol_vector_destroy(&user_vector);
+ apol_vector_destroy(&domain_trans_vector);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i incomplete transitions.\n", num_items);
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ /*
+ * printf("\nStart Type\t\tEntrypoint\t\tEnd Type\t\tMissing Rules\n");
+ * printf("----------\t\t----------\t\t--------\t\t-------------\n");
+ */
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ const qpol_type_t *start;
+ const qpol_type_t *end;
+ const qpol_type_t *ep;
+ const char *start_name, *end_name, *ep_name;
+ apol_domain_trans_result_t *dtr;
+
+ item = apol_vector_get_element(mod->result->items, i);
+ dtr = item->item;
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ printf("%s -> %s\tentrypoint: %s\n", start_name, end_name, ep_name);
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type) */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ const qpol_type_t *start;
+ const qpol_type_t *end;
+ const qpol_type_t *ep;
+ const char *start_name, *end_name, *ep_name;
+ apol_domain_trans_result_t *dtr;
+
+ item = apol_vector_get_element(mod->result->items, i);
+ dtr = item->item;
+ start = apol_domain_trans_result_get_start_type(dtr);
+ ep = apol_domain_trans_result_get_entrypoint_type(dtr);
+ end = apol_domain_trans_result_get_end_type(dtr);
+ if (start)
+ qpol_type_get_name(q, start, &start_name);
+ else
+ start_name = "<start_type>";
+ if (end)
+ qpol_type_get_name(q, end, &end_name);
+ else
+ end_name = "<end_type>";
+ if (ep)
+ qpol_type_get_name(q, ep, &ep_name);
+ else
+ ep_name = "<entrypoint_type>";
+
+ printf("%s -> %s\tentrypoint: %s\n\tMissing:\n", start_name, end_name, ep_name);
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ sechk_proof_t *proof;
+
+ proof = apol_vector_get_element(item->proof, j);
+ if (proof) {
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_dom_trans.h b/sechecker/modules/inc_dom_trans.h
new file mode 100644
index 0000000..02dffbf
--- /dev/null
+++ b/sechecker/modules/inc_dom_trans.h
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * Defines the interface for the incomplete domain transition module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_DOM_TRANS
+#define INC_DOM_TRANS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/domain-trans-analysis.h>
+#include <apol/user-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/role-query.h>
+
+#define SECHK_INC_DOM_TRANS_HAS_TT 0x08
+#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04
+#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02
+#define SECHK_INC_DOM_TRANS_HAS_EP 0x01
+#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC)
+
+ int inc_dom_trans_register(sechk_lib_t * lib);
+ int inc_dom_trans_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_dom_trans_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_dom_trans_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/inc_mount.c b/sechecker/modules/inc_mount.c
new file mode 100644
index 0000000..4e9f8b1
--- /dev/null
+++ b/sechecker/modules/inc_mount.c
@@ -0,0 +1,520 @@
+/**
+ * @file
+ * Implementation of the incomplete mount permissions module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_mount.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "inc_mount";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int inc_mount_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "no library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "domains with partial mount permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds domains that have incomplete mount permissions.\n"
+ "In order for a mount operation to be allowed by the policy the following rules\n"
+ "must be present: \n"
+ "\n"
+ " 1) allow somedomain_d sometype_t : filesystem { mount };\n"
+ " 2) allow somedomain_d sometype_t : dir { mounton };\n"
+ "\n" "This module finds domains that have only one of the rules listed above.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_mount_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+
+int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j;
+ bool both = false, add_proof = false;
+ int error = 0;
+ char *tmp = NULL;
+ apol_vector_t *mount_vector;
+ apol_vector_t *mounton_vector;
+ apol_avrule_query_t *mount_avrule_query = NULL;
+ apol_avrule_query_t *mounton_avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ if (!(mount_avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ if (!(mounton_avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+
+ /* Get avrules for filesystem mount */
+ apol_avrule_query_set_rules(policy, mount_avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_append_class(policy, mount_avrule_query, "filesystem");
+ apol_avrule_query_append_perm(policy, mount_avrule_query, "mount");
+ apol_avrule_get_by_query(policy, mount_avrule_query, &mount_vector);
+
+ /* Get avrules for dir mounton */
+ apol_avrule_query_set_rules(policy, mounton_avrule_query, QPOL_RULE_ALLOW);
+ apol_avrule_query_append_class(policy, mounton_avrule_query, "dir");
+ apol_avrule_query_append_perm(policy, mounton_avrule_query, "mounton");
+ apol_avrule_get_by_query(policy, mounton_avrule_query, &mounton_vector);
+
+ for (i = 0; i < apol_vector_get_size(mount_vector); i++) {
+ const qpol_avrule_t *mount_rule;
+ const qpol_type_t *mount_source;
+ const qpol_type_t *mount_target;
+ const char *mount_source_name, *mount_target_name;
+
+ both = false;
+ add_proof = true;
+ mount_rule = apol_vector_get_element(mount_vector, i);
+ qpol_avrule_get_source_type(q, mount_rule, &mount_source);
+ qpol_avrule_get_target_type(q, mount_rule, &mount_target);
+ qpol_type_get_name(q, mount_source, &mount_source_name);
+ qpol_type_get_name(q, mount_target, &mount_target_name);
+
+ for (j = 0; j < apol_vector_get_size(mounton_vector); j++) {
+ const qpol_avrule_t *mounton_rule;
+ const qpol_type_t *mounton_source;
+ const qpol_type_t *mounton_target;
+ const char *mounton_source_name, *mounton_target_name;
+
+ mounton_rule = apol_vector_get_element(mounton_vector, j);
+ qpol_avrule_get_source_type(q, mounton_rule, &mounton_source);
+ qpol_avrule_get_target_type(q, mounton_rule, &mounton_target);
+ qpol_type_get_name(q, mounton_source, &mounton_source_name);
+ qpol_type_get_name(q, mounton_target, &mounton_target_name);
+
+ /* Check to see if they match */
+ if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name))
+ both = true;
+ }
+ if (!both) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)mount_rule;
+ tmp = apol_avrule_render(policy, mount_rule);
+ asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : dir mounton ;\n",
+ tmp, mount_source_name, mount_target_name);
+ free(tmp);
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(mount_source_name, res_type_name) || !strcmp(mount_target_name, res_type_name))
+ add_proof = false;
+ }
+ if (add_proof) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item->item = (void *)mount_source;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ sechk_proof_free(proof);
+ proof = NULL;
+ }
+ }
+
+ for (i = 0; i < apol_vector_get_size(mounton_vector); i++) {
+ const qpol_avrule_t *mounton_rule;
+ const qpol_type_t *mounton_source;
+ const qpol_type_t *mounton_target;
+ const char *mounton_source_name, *mounton_target_name;
+
+ both = false;
+ add_proof = true;
+ mounton_rule = apol_vector_get_element(mounton_vector, i);
+ qpol_avrule_get_source_type(q, mounton_rule, &mounton_source);
+ qpol_avrule_get_target_type(q, mounton_rule, &mounton_target);
+ qpol_type_get_name(q, mounton_source, &mounton_source_name);
+ qpol_type_get_name(q, mounton_target, &mounton_target_name);
+
+ for (j = 0; j < apol_vector_get_size(mount_vector); j++) {
+ const qpol_avrule_t *mount_rule;
+ const qpol_type_t *mount_source;
+ const qpol_type_t *mount_target;
+ const char *mount_source_name, *mount_target_name;
+
+ mount_rule = apol_vector_get_element(mount_vector, j);
+ qpol_avrule_get_source_type(q, mount_rule, &mount_source);
+ qpol_avrule_get_target_type(q, mount_rule, &mount_target);
+ qpol_type_get_name(q, mount_source, &mount_source_name);
+ qpol_type_get_name(q, mount_target, &mount_target_name);
+
+ if (!strcmp(mount_source_name, mounton_source_name) && !strcmp(mount_target_name, mounton_target_name))
+ both = true;
+ }
+ if (!both) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ proof->type = SECHK_ITEM_AVRULE;
+ proof->elem = (void *)mounton_rule;
+ tmp = apol_avrule_render(policy, mounton_rule);
+ asprintf(&proof->text, "Have Rule:\n\t\t%s\n\tMissing:\n\t\tallow %s %s : filesystem mount ;\n",
+ tmp, mounton_source_name, mounton_target_name);
+ free(tmp);
+ for (j = 0; j < apol_vector_get_size(res->items); j++) {
+ sechk_item_t *res_item;
+ const qpol_type_t *res_type;
+ const char *res_type_name;
+
+ res_item = apol_vector_get_element(res->items, j);
+ res_type = res_item->item;
+ qpol_type_get_name(q, res_type, &res_type_name);
+ if (!strcmp(mounton_source_name, res_type_name) || !strcmp(mounton_target_name, res_type_name))
+ add_proof = false;
+ }
+ if (add_proof) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(NULL, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item->item = (void *)mounton_source;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_mount_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ sechk_proof_free(proof);
+ proof = NULL;
+ }
+ }
+ apol_vector_destroy(&mount_vector);
+ apol_vector_destroy(&mounton_vector);
+
+ mod->result = res;
+ apol_avrule_query_destroy(&mount_avrule_query);
+ apol_avrule_query_destroy(&mounton_avrule_query);
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_mount_run_fail:
+ apol_vector_destroy(&mount_vector);
+ apol_vector_destroy(&mounton_vector);
+ apol_avrule_query_destroy(&mount_avrule_query);
+ apol_avrule_query_destroy(&mounton_avrule_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ free(tmp);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k, l, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd types.\n", num_items);
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item (e.g. rules with a given type)
+ * this field also lists the computed severity of each item
+ * (see sechk_item_sev in sechecker.c for details on calculation)
+ * items are printed on a line either with the severity.
+ * Each proof element is then displayed in an indented list one per
+ * line below it. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_mount.h b/sechecker/modules/inc_mount.h
new file mode 100644
index 0000000..18d5179
--- /dev/null
+++ b/sechecker/modules/inc_mount.h
@@ -0,0 +1,54 @@
+/**
+ * @file
+ * Defines the interface for the incomplete mount permissions module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_MOUNT
+#define INC_MOUNT
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+#define SECHK_MOUNT_ONLY_MOUNT 0x01
+#define SECHK_MOUNT_ONLY_MOUNTON 0x02
+
+/* Module functions:
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int inc_mount_register(sechk_lib_t * lib);
+ int inc_mount_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_mount_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_mount_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/inc_net_access.c b/sechecker/modules/inc_net_access.c
new file mode 100644
index 0000000..a8903ea
--- /dev/null
+++ b/sechecker/modules/inc_net_access.c
@@ -0,0 +1,1852 @@
+/**
+ * @file
+ * Defines the interface for the incomplete network access module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "inc_net_access.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char *const mod_name = "inc_net_access";
+
+/* The register function registers all of a module's functions
+ * with the library. You should not need to edit this function
+ * unless you are adding additional functions you need other modules
+ * to call. See the note at the bottom of this function to do so. */
+int inc_net_access_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "finds network domains with inadequate permissions";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all network domains in a policy which do not have the \n"
+ "required permissions needed to facilitate network communication. For network\n"
+ "domains to communicate, the following conditions must be true:\n"
+ " 1) the domain must have read or receive permissions on a socket of the same\n"
+ " type\n"
+ " 2) the domain must have send or receive permissions on an IPsec association\n"
+ " (see find_assoc_types)\n"
+ " 3) the domain must have send or receive permissions on netif objects for a\n"
+ " netif type (see find_netif_types)\n"
+ " 4) the domain must have send or receive permissions on node objects for a\n"
+ " node type (see find_node_types)\n"
+ " 5) the domain must have send or receive permissions on port objects for a\n"
+ " port type (see find_port_types)\n";
+ mod->opt_description =
+ " Module requirements:\n"
+ " none\n" " Module dependencies:\n" " find_net_domains\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+ /* assign dependencies */
+ if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_net_domains")) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = inc_net_access_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file.
+ * Add any option processing logic as indicated below. */
+int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* This set of defines represents individual permission bits for
+ * the permissions needed to have complete network access */
+/* allow domain self : sock_file {read write getattr}; */
+#define PERM_SELF_SOCK_FILE_READ 0x00000001
+#define PERM_SELF_SOCK_FILE_WRITE 0x00000002
+#define PERM_SELF_SOCK_FILE_GETATTR 0x00000004
+/* allow domain self : tcp_socket {create read write}; */
+#define PERM_SELF_TCP_SOC_READ 0x00000008
+#define PERM_SELF_TCP_SOC_WRITE 0x00000010
+#define PERM_SELF_TCP_SOC_CREATE 0x00000020
+/* allow domain self : udp_socket {create read write}; */
+#define PERM_SELF_UDP_SOC_READ 0x00000040
+#define PERM_SELF_UDP_SOC_WRITE 0x00000080
+#define PERM_SELF_UDP_SOC_CREATE 0x00000100
+/* allow domain if_type : netif {tcp_send udp_send tcp_recv tcp_send}; */
+#define PERM_NETIF_TCP_SEND 0x00000200
+#define PERM_NETIF_UDP_SEND 0x00000400
+#define PERM_NETIF_TCP_RECV 0x00000800
+#define PERM_NETIF_UDP_RECV 0x00001000
+/* allow domain node_type : node {tcp_send udp_send tcp_recv tcp_send}; */
+#define PERM_NODE_TCP_SEND 0x00002000
+#define PERM_NODE_UDP_SEND 0x00004000
+#define PERM_NODE_TCP_RECV 0x00008000
+#define PERM_NODE_UDP_RECV 0x00010000
+/* allow domain port_type : tcp_socket {send_msg recv_msg}; */
+#define PERM_PORT_TCP_SEND 0x00020000
+#define PERM_PORT_TCP_RECV 0x00040000
+/* allow domain port_type : udp_socket {send_msg recv_msg}; */
+#define PERM_PORT_UDP_SEND 0x00080000
+#define PERM_PORT_UDP_RECV 0x00100000
+/* allow domain assoc_type : association {sendto recvfrom}; */
+#define PERM_ASSOC_SEND 0x00200000
+#define PERM_ASSOC_RECV 0x00400000
+
+/* this set of defines represents masks for individual rules */
+#define RULE_TCP_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_UDPs_SOCK_FILE (PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_UDPr_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_GETATTR)
+#define RULE_TCP_SELF_SOC (PERM_SELF_TCP_SOC_READ|PERM_SELF_TCP_SOC_WRITE|PERM_SELF_TCP_SOC_CREATE)
+#define RULE_UDPs_SELF_SOC (PERM_SELF_UDP_SOC_WRITE|PERM_SELF_UDP_SOC_CREATE)
+#define RULE_UDPr_SELF_SOC (PERM_SELF_UDP_SOC_READ|PERM_SELF_UDP_SOC_CREATE)
+#define RULE_TCP_NETIF (PERM_NETIF_TCP_SEND|PERM_NETIF_TCP_RECV)
+#define RULE_UDPs_NETIF (PERM_NETIF_UDP_SEND)
+#define RULE_UDPr_NETIF (PERM_NETIF_UDP_RECV)
+#define RULE_TCP_NODE (PERM_NODE_TCP_SEND|PERM_NODE_TCP_RECV)
+#define RULE_UDPs_NODE (PERM_NODE_UDP_SEND)
+#define RULE_UDPr_NODE (PERM_NODE_UDP_RECV)
+#define RULE_TCP_PORT (PERM_PORT_TCP_SEND|PERM_PORT_TCP_RECV)
+#define RULE_UDPs_PORT (PERM_PORT_UDP_SEND)
+#define RULE_UDPr_PORT (PERM_PORT_UDP_RECV)
+#define RULE_TCP_ASSOC (PERM_ASSOC_SEND|PERM_ASSOC_RECV)
+#define RULE_UDPs_ASSOC (PERM_ASSOC_SEND)
+#define RULE_UDPr_ASSOC (PERM_ASSOC_RECV)
+
+/* This set of defines represents mask sets to represent access types */
+#define UDP_RECV_PERM_SET (RULE_UDPr_SOCK_FILE|RULE_UDPr_SELF_SOC|RULE_UDPr_NETIF|RULE_UDPr_NODE|RULE_UDPr_PORT|RULE_UDPr_ASSOC)
+#define UDP_SEND_PERM_SET (RULE_UDPs_SOCK_FILE|RULE_UDPs_SELF_SOC|RULE_UDPs_NETIF|RULE_UDPs_NODE|RULE_UDPs_PORT|RULE_UDPs_ASSOC)
+#define TCP_FULL_PERM_SET (RULE_TCP_SOCK_FILE|RULE_TCP_SELF_SOC|RULE_TCP_NETIF|RULE_TCP_NODE|RULE_TCP_PORT|RULE_TCP_ASSOC)
+#define COMMON_ACCESS_SET (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR|PERM_ASSOC_SEND|PERM_ASSOC_RECV)
+
+typedef struct net_state
+{
+ uint32_t perms;
+ apol_vector_t *netifs;
+ apol_vector_t *nodes;
+ apol_vector_t *tcpsocs;
+ apol_vector_t *udpsocs;
+ apol_vector_t *assocs;
+} net_state_t;
+
+typedef struct name_perm
+{
+ const char *name; /* will be from policy do not free */
+ uint32_t perms;
+} name_perm_t;
+
+static void net_state_destroy(net_state_t ** n)
+{
+ if (!n || !(*n))
+ return;
+
+ apol_vector_destroy(&((*n)->netifs));
+ apol_vector_destroy(&((*n)->nodes));
+ apol_vector_destroy(&((*n)->tcpsocs));
+ apol_vector_destroy(&((*n)->udpsocs));
+ apol_vector_destroy(&((*n)->assocs));
+ free(*n);
+ *n = NULL;
+}
+
+static net_state_t *net_state_create(void)
+{
+ net_state_t *n = NULL;
+
+ n = calloc(1, sizeof(*n));
+ n->netifs = apol_vector_create(free);
+ n->nodes = apol_vector_create(free);
+ n->tcpsocs = apol_vector_create(free);
+ n->udpsocs = apol_vector_create(free);
+ n->assocs = apol_vector_create(free);
+
+ return n;
+}
+
+static int name_perm_comp(const void *a, const void *b, void *arg __attribute__ ((unused)))
+{
+ const name_perm_t *x = a;
+ const name_perm_t *y = b;
+
+ return strcmp(x->name, y->name);
+}
+
+static name_perm_t *name_perm_create(const char *name)
+{
+ name_perm_t *np = NULL;
+
+ np = calloc(1, sizeof(*np));
+ np->name = name;
+
+ return np;
+}
+
+static int name_perm_vector_has_incomplete_perms(apol_vector_t * v, uint32_t mask)
+{
+ uint32_t tmp;
+ name_perm_t *np = NULL;
+ size_t i = 0;
+
+ if (!apol_vector_get_size(v))
+ return 1;
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ np = apol_vector_get_element(v, i);
+ tmp = np->perms & mask;
+ if (tmp != mask)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void name_perm_vector_add_perm(apol_vector_t * v, const char *name, uint32_t perm)
+{
+ name_perm_t *np = NULL;
+ size_t i = 0;
+ int retv;
+
+ np = name_perm_create(name);
+ retv = apol_vector_get_index(v, np, name_perm_comp, NULL, &i);
+ if (retv) {
+ np->perms = perm;
+ apol_vector_append(v, (void *)np);
+ } else {
+ free(np); /* already exists free temp one */
+ np = apol_vector_get_element(v, i);
+ np->perms |= perm;
+ }
+}
+
+static char *generate_tcp_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == TCP_FULL_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has TCP access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete TCP access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SOCK_FILE;
+ missing = attempt ^ RULE_TCP_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SELF_SOC;
+ missing = attempt ^ RULE_TCP_SELF_SOC;
+ asprintf(&tmp, "allow %s self : tcp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_TCP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_TCP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_TCP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_TCP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_TCP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_TCP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_TCP_NETIF;
+ missing = attempt ^ RULE_TCP_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (attempt & PERM_NETIF_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (missing & PERM_NETIF_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { tcp_send tcp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_TCP_NODE;
+ missing = attempt ^ RULE_TCP_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (attempt & PERM_NODE_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "tcp_send "))
+ goto err;
+ }
+ if (missing & PERM_NODE_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "tcp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { tcp_send tcp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->tcpsocs); i++) {
+ np = apol_vector_get_element(state->tcpsocs, i);
+ attempt = state->perms & RULE_TCP_PORT;
+ missing = attempt ^ RULE_TCP_PORT;
+ asprintf(&tmp, "allow %s %s : tcp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (attempt & PERM_PORT_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_TCP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (missing & PERM_PORT_TCP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->tcpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : tcp_socket { send_msg recv_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_TCP_ASSOC;
+ missing = attempt ^ RULE_TCP_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (missing & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto recvfrom };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_udp_send_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == UDP_SEND_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has UDP send access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP send access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPs_SOCK_FILE;
+ missing = attempt ^ RULE_UDPs_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPs_SELF_SOC;
+ missing = attempt ^ RULE_UDPs_SELF_SOC;
+ asprintf(&tmp, "allow %s self : udp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_UDP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_UDP_SOC_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (missing & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_UDPs_NETIF;
+ missing = attempt ^ RULE_UDPs_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_send };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_UDPs_NODE;
+ missing = attempt ^ RULE_UDPs_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "udp_send "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_send };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) {
+ np = apol_vector_get_element(state->udpsocs, i);
+ attempt = state->perms & RULE_UDPs_PORT;
+ missing = attempt ^ RULE_UDPs_PORT;
+ asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_UDP_SEND) {
+ if (apol_str_append(&text, &text_sz, "send_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->udpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { send_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_UDPs_ASSOC;
+ missing = attempt ^ RULE_UDPs_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { sendto };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_udp_recv_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0, missing = 0;
+ name_perm_t *np = NULL;
+
+ if (state->perms == UDP_RECV_PERM_SET) {
+ if (apol_str_append(&text, &text_sz, "Domain has UDP receive access, but some accesses are incomplete."))
+ goto err;
+ } else {
+ if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP receive access."))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPr_SOCK_FILE;
+ missing = attempt ^ RULE_UDPr_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:"))
+ goto err;
+ attempt = state->perms & RULE_UDPr_SELF_SOC;
+ missing = attempt ^ RULE_UDPr_SELF_SOC;
+ asprintf(&tmp, "allow %s self : udp_socket { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_UDP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_SELF_UDP_SOC_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (missing & PERM_SELF_UDP_SOC_CREATE) {
+ if (apol_str_append(&text, &text_sz, "create "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->netifs); i++) {
+ np = apol_vector_get_element(state->netifs, i);
+ attempt = state->perms & RULE_UDPr_NETIF;
+ missing = attempt ^ RULE_UDPr_NETIF;
+ asprintf(&tmp, "allow %s %s : netif { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NETIF_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NETIF_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->netifs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <netif_type> : netif { udp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tnode permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->nodes); i++) {
+ np = apol_vector_get_element(state->nodes, i);
+ attempt = state->perms & RULE_UDPr_NODE;
+ missing = attempt ^ RULE_UDPr_NODE;
+ asprintf(&tmp, "allow %s %s : node { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_NODE_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_NODE_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "udp_recv "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->nodes)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <node_type> : node { udp_recv };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) {
+ np = apol_vector_get_element(state->udpsocs, i);
+ attempt = state->perms & RULE_UDPr_PORT;
+ missing = attempt ^ RULE_UDPr_PORT;
+ asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_PORT_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_PORT_UDP_RECV) {
+ if (apol_str_append(&text, &text_sz, "recv_msg "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->udpsocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <port_type> : udp_socket { recv_msg };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_UDPr_ASSOC;
+ missing = attempt ^ RULE_UDPr_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ if (missing) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (missing & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ if (!apol_vector_get_size(state->assocs)) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, domain))
+ goto err;
+ if (apol_str_append(&text, &text_sz, " <association_type> : association { recvfrom };"))
+ goto err;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+static char *generate_common_only_proof_text(const char *domain, net_state_t * state)
+{
+ char *text = NULL, *tmp = NULL;
+ size_t text_sz = 0, i;
+ uint32_t attempt = 0;
+ name_perm_t *np = NULL;
+
+ if (apol_str_append
+ (&text, &text_sz,
+ "Domain has incomplete network access.\n\tDomain has no protocol specific permissions only the following:"))
+ goto err;
+
+ if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:"))
+ goto err;
+ attempt = state->perms & RULE_TCP_SOCK_FILE;
+ asprintf(&tmp, "allow %s self : sock_file { ", domain);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_SELF_SOCK_FILE_READ) {
+ if (apol_str_append(&text, &text_sz, "read "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_WRITE) {
+ if (apol_str_append(&text, &text_sz, "write "))
+ goto err;
+ }
+ if (attempt & PERM_SELF_SOCK_FILE_GETATTR) {
+ if (apol_str_append(&text, &text_sz, "getattr "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+
+ if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:"))
+ goto err;
+ for (i = 0; i < apol_vector_get_size(state->assocs); i++) {
+ np = apol_vector_get_element(state->assocs, i);
+ attempt = state->perms & RULE_TCP_ASSOC;
+ asprintf(&tmp, "allow %s %s : association { ", domain, np->name);
+ if (attempt) {
+ if (apol_str_append(&text, &text_sz, "\n\t\tHas: "))
+ goto err;
+ if (apol_str_append(&text, &text_sz, tmp))
+ goto err;
+ if (attempt & PERM_ASSOC_SEND) {
+ if (apol_str_append(&text, &text_sz, "sendto "))
+ goto err;
+ }
+ if (attempt & PERM_ASSOC_RECV) {
+ if (apol_str_append(&text, &text_sz, "recvfrom "))
+ goto err;
+ }
+ if (apol_str_append(&text, &text_sz, "};"))
+ goto err;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+
+ if (apol_str_append(&text, &text_sz, "\n"))
+ goto err;
+
+ return text;
+
+ err:
+ free(text);
+ free(tmp);
+ return NULL;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL, *tmp_item = NULL;
+ sechk_proof_t *proof = NULL;
+ sechk_result_t *net_domain_res = NULL;
+ sechk_name_value_t *dep = NULL;
+ sechk_mod_fn_t run_fn = NULL;
+ size_t i = 0, j = 0;
+ int error = 0;
+ apol_avrule_query_t *avrule_query = NULL;
+ apol_vector_t *avrule_vector = NULL, *net_domain_vector = NULL;
+ const qpol_type_t *net_domain = NULL, *tmp_type = NULL;
+ const char *net_domain_name = NULL, *tgt_name = NULL;
+ char *perm_name = NULL;
+ const qpol_avrule_t *rule = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ net_state_t *state = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_net_access_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto inc_net_access_run_fail;
+ }
+
+ /* run dependencies */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ net_domain_res = sechk_lib_get_module_result("find_net_domains", mod->parent_lib);
+ if (!net_domain_res) {
+ error = errno;
+ ERR(policy, "%s", "Unable to get results for module find_net_domains");
+ goto inc_net_access_run_fail;
+ }
+ net_domain_vector = (apol_vector_t *) net_domain_res->items;
+
+ avrule_query = apol_avrule_query_create();
+ if (!avrule_query) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW);
+
+ for (i = 0; i < apol_vector_get_size(net_domain_vector); i++) {
+ tmp_item = apol_vector_get_element(net_domain_vector, i);
+ net_domain = tmp_item->item;
+ qpol_type_get_name(q, net_domain, &net_domain_name);
+ state = net_state_create();
+
+ /* find any self sock_file perms */
+ apol_avrule_query_set_source(policy, avrule_query, net_domain_name, 1);
+ apol_avrule_query_set_target(policy, avrule_query, net_domain_name, 1);
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "sock_file");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_SOCK_FILE_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_SOCK_FILE_WRITE;
+ } else if (!strcmp(perm_name, "getattr")) {
+ state->perms |= PERM_SELF_SOCK_FILE_GETATTR;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any self tcp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "tcp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_TCP_SOC_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_TCP_SOC_WRITE;
+ } else if (!strcmp(perm_name, "create")) {
+ state->perms |= PERM_SELF_TCP_SOC_CREATE;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any self udp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "udp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "read")) {
+ state->perms |= PERM_SELF_UDP_SOC_READ;
+ } else if (!strcmp(perm_name, "write")) {
+ state->perms |= PERM_SELF_UDP_SOC_WRITE;
+ } else if (!strcmp(perm_name, "create")) {
+ state->perms |= PERM_SELF_UDP_SOC_CREATE;
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any if_t netif perms */
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "netif");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "tcp_send")) {
+ state->perms |= PERM_NETIF_TCP_SEND;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_SEND);
+ } else if (!strcmp(perm_name, "tcp_recv")) {
+ state->perms |= PERM_NETIF_TCP_RECV;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_RECV);
+ } else if (!strcmp(perm_name, "udp_send")) {
+ state->perms |= PERM_NETIF_UDP_SEND;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_SEND);
+ } else if (!strcmp(perm_name, "udp_recv")) {
+ state->perms |= PERM_NETIF_UDP_RECV;
+ name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any node_t node perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "node");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "tcp_send")) {
+ state->perms |= PERM_NODE_TCP_SEND;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_SEND);
+ } else if (!strcmp(perm_name, "tcp_recv")) {
+ state->perms |= PERM_NODE_TCP_RECV;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_RECV);
+ } else if (!strcmp(perm_name, "udp_send")) {
+ state->perms |= PERM_NODE_UDP_SEND;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_SEND);
+ } else if (!strcmp(perm_name, "udp_recv")) {
+ state->perms |= PERM_NODE_UDP_RECV;
+ name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any port_t tcp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "tcp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ /* skip self */
+ if (!strcmp(net_domain_name, tgt_name))
+ continue;
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "send_msg")) {
+ state->perms |= PERM_PORT_TCP_SEND;
+ name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_SEND);
+ } else if (!strcmp(perm_name, "recv_msg")) {
+ state->perms |= PERM_PORT_TCP_RECV;
+ name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any port_t udp_socket perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "udp_socket");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ /* skip self */
+ if (!strcmp(net_domain_name, tgt_name))
+ continue;
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "send_msg")) {
+ state->perms |= PERM_PORT_UDP_SEND;
+ name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_SEND);
+ } else if (!strcmp(perm_name, "recv_msg")) {
+ state->perms |= PERM_PORT_UDP_RECV;
+ name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* find any assoc_t association perms */
+ apol_avrule_query_append_class(policy, avrule_query, NULL);
+ apol_avrule_query_append_class(policy, avrule_query, "association");
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_target_type(q, rule, &tmp_type);
+ qpol_type_get_name(q, tmp_type, &tgt_name);
+ qpol_avrule_get_perm_iter(q, rule, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)(&perm_name));
+ if (!strcmp(perm_name, "sendto")) {
+ state->perms |= PERM_ASSOC_SEND;
+ name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_SEND);
+ } else if (!strcmp(perm_name, "recvfrom")) {
+ state->perms |= PERM_ASSOC_RECV;
+ name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_RECV);
+ } /* no general case else */
+ free(perm_name);
+ perm_name = NULL;
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&avrule_vector);
+
+ /* if has tcp perms check for missing ones */
+ if ((state->perms & ((~(COMMON_ACCESS_SET)) & (TCP_FULL_PERM_SET))) &&
+ ((state->perms & RULE_TCP_SOCK_FILE) != RULE_TCP_SOCK_FILE ||
+ (state->perms & RULE_TCP_SELF_SOC) != RULE_TCP_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_TCP_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_TCP_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->tcpsocs, RULE_TCP_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_TCP_ASSOC))) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_tcp_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has udp send perms check for missing perms */
+ if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_SEND_PERM_SET))) &&
+ ((state->perms & RULE_UDPs_SOCK_FILE) != RULE_UDPs_SOCK_FILE ||
+ (state->perms & RULE_UDPs_SELF_SOC) != RULE_UDPs_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPs_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPs_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPs_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPs_ASSOC))) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_udp_send_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has udp reveive perms check for missing perms */
+ if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_RECV_PERM_SET))) &&
+ ((state->perms & RULE_UDPr_SOCK_FILE) != RULE_UDPr_SOCK_FILE ||
+ (state->perms & RULE_UDPr_SELF_SOC) != RULE_UDPr_SELF_SOC ||
+ name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPr_NETIF) ||
+ name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPr_NODE) ||
+ name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPr_PORT) ||
+ name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPr_ASSOC))) {
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_udp_recv_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+ /* if has only common access perms report that */
+ if (!(state->perms & (~(COMMON_ACCESS_SET)))) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item->item = (void *)net_domain;
+ item->test_result = 1;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ proof->text = generate_common_only_proof_text(net_domain_name, state);
+ //TODO check that it succeeded
+ if (apol_vector_append(item->proof, (void *)proof)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ proof = NULL;
+ }
+
+ if (item) {
+ if (apol_vector_append(res->items, (void *)item)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto inc_net_access_run_fail;
+ }
+ item = NULL;
+ }
+ net_state_destroy(&state);
+ }
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ inc_net_access_run_fail:
+ apol_avrule_query_destroy(&avrule_query);
+ apol_vector_destroy(&avrule_vector);
+ qpol_iterator_destroy(&iter);
+ free(perm_name);
+ net_state_destroy(&state);
+ sechk_item_free(item);
+ sechk_proof_free(proof);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i network domains with insufficient permissions.\n", num_items);
+ }
+
+ /* Print current permissions then the permissions that are missing */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+
+ i = 0;
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/inc_net_access.h b/sechecker/modules/inc_net_access.h
new file mode 100644
index 0000000..746db40
--- /dev/null
+++ b/sechecker/modules/inc_net_access.h
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * Defines the interface for the incomplete network access module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INC_NET_ACCESS_H
+#define INC_NET_ACCESS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+
+/* Module functions:
+ * Do not change any of these prototypes or you will not be
+ * able to run the module in the library */
+ int inc_net_access_register(sechk_lib_t * lib);
+ int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_allow.c b/sechecker/modules/roles_wo_allow.c
new file mode 100644
index 0000000..3d55bc8
--- /dev/null
+++ b/sechecker/modules/roles_wo_allow.c
@@ -0,0 +1,387 @@
+/**
+ * @file
+ * Implementation of the roles without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_allow.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_allow";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_allow_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "roles with no roleallow rules";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles defined in the policy that are not used in any role\n"
+ "allow rules. It is not possible to transition to or from any role that does not\n" "have any role allow rules.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_allow_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ apol_vector_t *role_allow_vector;
+ apol_role_allow_query_t *role_allow_query = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ if ((role_allow_query = apol_role_allow_query_create()) == NULL) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ apol_role_allow_query_set_source(policy, role_allow_query, role_name);
+ apol_role_allow_query_set_source_any(policy, role_allow_query, 1);
+ apol_role_allow_get_by_query(policy, role_allow_query, &role_allow_vector);
+ if (apol_vector_get_size(role_allow_vector) > 0) {
+ apol_vector_destroy(&role_allow_vector);
+ continue;
+ }
+ apol_vector_destroy(&role_allow_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ proof->text = strdup("Role has no allow.\n");
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ item->item = (void *)role;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_allow_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&role_allow_vector);
+ apol_role_allow_query_destroy(&role_allow_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_allow_run_fail:
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&role_allow_vector);
+ apol_role_allow_query_destroy(&role_allow_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_role_t *role;
+ const char *role_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles do not appear in any allow rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_allow.h b/sechecker/modules/roles_wo_allow.h
new file mode 100644
index 0000000..c9dd44e
--- /dev/null
+++ b/sechecker/modules/roles_wo_allow.h
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * Defines the interface for the roles without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_ALLOW
+#define ROLES_WO_ALLOW
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+#include <apol/rbacrule-query.h>
+
+ int roles_wo_allow_register(sechk_lib_t * lib);
+ int roles_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_types.c b/sechecker/modules/roles_wo_types.c
new file mode 100644
index 0000000..ed38580
--- /dev/null
+++ b/sechecker/modules/roles_wo_types.c
@@ -0,0 +1,330 @@
+/**
+ * @file
+ * Implementation of the roles without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_types.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_types";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_types_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign descriptions */
+ mod->brief_description = "roles with no types";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles in the policy that have no types. A role with no types \n"
+ "cannot form a valid context.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_types_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Ivalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ qpol_iterator_t *type_iter = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Ivalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+ int at_end;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ qpol_role_get_type_iter(apol_policy_get_qpol(policy), role, &type_iter);
+ at_end = qpol_iterator_end(type_iter);
+ qpol_iterator_destroy(&type_iter);
+ if (!at_end)
+ continue;
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ proof->type = SECHK_ITEM_ROLE;
+ asprintf(&proof->text, "role %s has no types", role_name);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ item->item = (void *)role;
+ item->test_result = 1;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_types_run_fail;
+ }
+ }
+ apol_vector_destroy(&role_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_types_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_role_t *role;
+ const char *role_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles have no associated types:\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_types.h b/sechecker/modules/roles_wo_types.h
new file mode 100644
index 0000000..1a241d0
--- /dev/null
+++ b/sechecker/modules/roles_wo_types.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the roles without types module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_TYPES
+#define ROLES_WO_TYPES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/role-query.h>
+
+ int roles_wo_types_register(sechk_lib_t * lib);
+ int roles_wo_types_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_types_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_types_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/roles_wo_users.c b/sechecker/modules/roles_wo_users.c
new file mode 100644
index 0000000..c590880
--- /dev/null
+++ b/sechecker/modules/roles_wo_users.c
@@ -0,0 +1,392 @@
+/**
+ * @file
+ * Defines the interface for the roles without users module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "roles_wo_users.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "roles_wo_users";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int roles_wo_users_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "roles not assigned to users";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds roles that are not assigned to users. If a role is not \n"
+ "assigned to a user it cannot form a valid context.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = roles_wo_users_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *role_vector;
+ apol_vector_t *user_vector;
+ apol_user_query_t *user_query = NULL;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ res->item_type = SECHK_ITEM_ROLE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+
+ if (!(user_query = apol_user_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+
+ if (apol_role_get_by_query(policy, NULL, &role_vector) < 0) {
+ error = errno;
+ ERR(policy, "%s", "Unable to retrieve roles");
+ return -1;
+ }
+
+ for (i = 0; i < apol_vector_get_size(role_vector); i++) {
+ const qpol_role_t *role;
+ const char *role_name;
+
+ role = apol_vector_get_element(role_vector, i);
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+
+ if (!strcmp(role_name, "object_r"))
+ continue;
+
+ apol_user_query_set_role(policy, user_query, role_name);
+ apol_user_get_by_query(policy, user_query, &user_vector);
+ if (apol_vector_get_size(user_vector) > 0) {
+ apol_vector_destroy(&user_vector);
+ continue;
+ }
+ apol_vector_destroy(&user_vector);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item->item = (void *)role;
+ item->test_result = 1;
+ proof->type = SECHK_ITEM_ROLE;
+ proof->text = strdup("This role is not assigned to any user.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto roles_wo_users_run_fail;
+ }
+ item = NULL;
+ proof = NULL;
+ }
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_user_query_destroy(&user_query);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ roles_wo_users_run_fail:
+ apol_vector_destroy(&role_vector);
+ apol_vector_destroy(&user_vector);
+ apol_user_query_destroy(&user_query);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ const qpol_role_t *role;
+ const char *role_name;
+ size_t i = 0, j = 0, num_items;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd roles.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following roles are not associated with any users.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ role = (qpol_role_t *) item->item;
+ qpol_role_get_name(apol_policy_get_qpol(policy), role, &role_name);
+ printf("%s%s", role_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+
+ return 0;
+}
diff --git a/sechecker/modules/roles_wo_users.h b/sechecker/modules/roles_wo_users.h
new file mode 100644
index 0000000..261bebb
--- /dev/null
+++ b/sechecker/modules/roles_wo_users.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the roles without users module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ROLES_WO_USERS
+#define ROLES_WO_USERS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+#include <apol/role-query.h>
+
+/* Module functions:
+ * NOTE: while using a modular format SEChecker is built
+ * statically; this means that all modules and their functions
+ * are in the same namespace. */
+ int roles_wo_users_register(sechk_lib_t * lib);
+ int roles_wo_users_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int roles_wo_users_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/spurious_audit.c b/sechecker/modules/spurious_audit.c
new file mode 100644
index 0000000..21698df
--- /dev/null
+++ b/sechecker/modules/spurious_audit.c
@@ -0,0 +1,778 @@
+/**
+ * @file
+ * Implementation of the spurious audit rule module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Ryan Jordan rjordan@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sechecker.h"
+#include "spurious_audit.h"
+#include <apol/policy-query.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "spurious_audit";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int spurious_audit_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "no library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s%s%s", "module unknown, \"", mod_name, "\"");
+ errno = ENOENT;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "audit rules with no effect";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds audit rules in the policy which do not affect the auditing of\n"
+ "the policy. This could happen in the following situations:\n"
+ "\n"
+ " 1) there is an allow rule with the same key and permissions for a dontaudit\n"
+ " rule\n"
+ " 2) there is an auditallow rule without an allow rule with the same key or\n"
+ " with permissions that do not appear in an allow rule with the same key.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(errno));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = spurious_audit_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error, rule_found;
+ apol_avrule_query_t *query = 0;
+ apol_vector_t *allow_rules = NULL, *auditallow_rules = NULL;
+ apol_vector_t *dontaudit_rules = NULL, *perm_vector1 = NULL;
+ apol_vector_t *perm_vector2 = NULL, *perm_intersection = NULL;
+ apol_vector_t *tmp_v = NULL;
+ size_t i, j, k, l, tmp_counter;
+ const qpol_avrule_t *rule1, *rule2;
+ const qpol_type_t *source, *target;
+ const qpol_class_t *object;
+ qpol_iterator_t *perm_iter1, *perm_iter2;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ char *string1, *string2, *tmp;
+ const char *src_name, *tgt_name, *obj_name, *perms;
+
+ error = rule_found = 0;
+ allow_rules = auditallow_rules = dontaudit_rules = perm_vector1 = perm_vector2 = perm_intersection = NULL;
+ rule1 = rule2 = 0;
+ source = target = NULL;
+ perm_iter1 = perm_iter2 = NULL;
+ string1 = string2 = tmp = NULL;
+ src_name = tgt_name = obj_name = perms = NULL;
+
+ if (!mod || !policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ res->item_type = SECHK_ITEM_AVRULE;
+
+ query = apol_avrule_query_create();
+ if (!query) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_AUDITALLOW);
+ if (apol_avrule_get_by_query(policy, query, &auditallow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_DONTAUDIT);
+ if (apol_avrule_get_by_query(policy, query, &dontaudit_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* First error case: Allow && Don't Audit */
+ for (i = 0; i < apol_vector_get_size(dontaudit_rules); i++) {
+ /* get first (DONT_AUDIT) rule */
+ rule1 = (qpol_avrule_t *) apol_vector_get_element(dontaudit_rules, i);
+ if (!rule1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* get source, target, object for Don't Audit rule */
+ if (qpol_avrule_get_source_type(q, rule1, &source)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_target_type(q, rule1, &target)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_object_class(q, rule1, &object)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* extract name strings from source, target, object */
+ if (qpol_type_get_name(q, source, &src_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_type_get_name(q, target, &tgt_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_class_get_name(q, object, &obj_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* configure Allow rule query to match above Don't Audit rule */
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, query, src_name, 1);
+ apol_avrule_query_set_target(policy, query, tgt_name, 1);
+ apol_avrule_query_append_class(policy, query, NULL);
+ apol_avrule_query_append_class(policy, query, obj_name);
+
+ /* get vector of matching ALLOW rules */
+ if (apol_avrule_get_by_query(policy, query, &allow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (apol_vector_get_size(allow_rules) != 0) {
+ /* Bad News: Allow && Don't Audit */
+ for (j = 0; j < apol_vector_get_size(allow_rules); j++) {
+ /* get second (Allow) rule */
+ rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j);
+ if (!rule2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* get permission iterators for both rules, and make vectors from them */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector2 = apol_vector_create_from_iter(perm_iter2, free);
+ if (!perm_vector2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* create intersection of permissions */
+ perm_intersection = apol_vector_create_from_intersection(perm_vector1,
+ perm_vector2, apol_str_strcmp, NULL);
+ if (!perm_intersection) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (apol_vector_get_size(perm_intersection) != 0) {
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = (void *)rule2; /* proof is the allow rule */
+ proof->type = SECHK_ITEM_AVRULE;
+ /* text will show the permissions that conflict */
+ tmp_counter = 0;
+ for (k = 0; k < apol_vector_get_size(perm_intersection); k++) {
+ apol_str_append(&(proof->text), &tmp_counter,
+ (char *)apol_vector_get_element(perm_intersection, k));
+ if (k != (apol_vector_get_size(perm_intersection) - 1))
+ apol_str_append(&(proof->text), &tmp_counter, ", ");
+ }
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ item->item = (void *)rule1; /* item is the dontaudit rule */
+ }
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+
+ } else {
+ /* these two rules don't overlap, no problem */
+ }
+ /* clean up */
+ rule2 = NULL;
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ }
+ apol_vector_destroy(&allow_rules);
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ if (item)
+ apol_vector_append(res->items, (void *)item);
+
+ item = NULL;
+ }
+ apol_vector_destroy(&allow_rules);
+ }
+ apol_vector_destroy(&dontaudit_rules);
+
+ /* Second error case: AuditAllow w/out Allow */
+ for (i = 0; i < apol_vector_get_size(auditallow_rules); i++) {
+ /* get first (AuditAllow) rule */
+ rule1 = (qpol_avrule_t *) apol_vector_get_element(auditallow_rules, i);
+ if (!rule1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ /* get first rule's source, target, object class */
+ if (qpol_avrule_get_source_type(q, rule1, &source)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_target_type(q, rule1, &target)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_avrule_get_object_class(q, rule1, &object)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ /* extract name strings from source, target, object */
+ if (qpol_type_get_name(q, source, &src_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_type_get_name(q, target, &tgt_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (qpol_class_get_name(q, object, &obj_name)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* configure ALLOW rule query to match above rule */
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW);
+ apol_avrule_query_set_source(policy, query, src_name, 1);
+ apol_avrule_query_set_target(policy, query, tgt_name, 1);
+ apol_avrule_query_append_class(policy, query, obj_name);
+
+ if (apol_avrule_get_by_query(policy, query, &allow_rules)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (!apol_vector_get_size(allow_rules)) {
+ /* No ALLOW rule for given AUDIT_ALLOW rule */
+
+ /* Make proof: missing allow rule */
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = NULL;
+ proof->type = SECHK_ITEM_AVRULE;
+
+ /* grab permisisons of auditallow rule, and make text */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ tmp_counter = 0;
+ for (j = 0; j < apol_vector_get_size(perm_vector1); j++) {
+ if (apol_str_append(&(proof->text), &tmp_counter, (char *)apol_vector_get_element(perm_vector1, j))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (j != (apol_vector_get_size(perm_vector1) - 1)) {
+ if (apol_str_append(&(proof->text), &tmp_counter, " ")) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ }
+ apol_vector_destroy(&perm_vector1);
+ qpol_iterator_destroy(&perm_iter1);
+
+ /* Make item: inconsistent auditallow rule */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ item->item = (void *)rule1;
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+
+ /* Add item to test result */
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ if (item)
+ apol_vector_append(res->items, (void *)item);
+ item = NULL;
+ apol_vector_destroy(&allow_rules);
+ continue;
+ }
+
+ /* Here we have AuditAllow rule and Allow rule(s) with same key */
+ /* Checking to make sure they have the same permissions */
+
+ /* Make vector of AuditAllow permissions */
+ if (qpol_avrule_get_perm_iter(q, rule1, &perm_iter1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ perm_vector1 = apol_vector_create_from_iter(perm_iter1, free);
+ if (!perm_vector1) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ /* Get permissions vector for Allow rule(s) */
+ for (j = 0; j < apol_vector_get_size(allow_rules); j++) {
+ /* get Allow rule */
+ rule2 = (qpol_avrule_t *) apol_vector_get_element(allow_rules, j);
+ if (!rule2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (qpol_avrule_get_perm_iter(q, rule2, &perm_iter2)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+
+ if (!perm_vector2) {
+ perm_vector2 = apol_vector_create(free);
+ if (!perm_vector2) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+
+ /* concatenate permissions from this rule, check for errors, all in one go */
+ if (apol_vector_cat(perm_vector2, (tmp_v = apol_vector_create_from_iter(perm_iter2, NULL)))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ apol_vector_destroy(&tmp_v);
+ goto spurious_audit_run_fail;
+ }
+ apol_vector_destroy(&tmp_v);
+ }
+
+ /* Find intersection of permission, put into a vector */
+ perm_intersection = apol_vector_create_from_intersection(perm_vector1, perm_vector2, apol_str_strcmp, NULL);
+
+ if (apol_vector_get_size(perm_intersection) != apol_vector_get_size(perm_vector1)) {
+ /* Auditallow rule audits things that are not allowed */
+
+ /* item for result is the AuditAllow rule */
+ if (!item) {
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));;
+ goto spurious_audit_run_fail;
+ }
+ }
+ item->item = (void *)rule1;
+ /* proof is the lack of Allow rule */
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ proof->elem = NULL;
+ proof->type = SECHK_ITEM_AVRULE;
+
+ /* the next series of if statements prints the following:
+ * missing: allow <src_name> <tgt_name> : <obj_name> { perms }; */
+ tmp_counter = 0;
+ for (j = 0; j < apol_vector_get_size(perm_vector1); j++) {
+ string1 = (char *)apol_vector_get_element(perm_vector1, j);
+ if (apol_vector_get_index(perm_intersection, (void *)string1, apol_str_strcmp, NULL, &l) < 0) {
+ if (apol_str_append(&(proof->text), &tmp_counter, string1)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ if (apol_str_append(&(proof->text), &tmp_counter, " ")) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ string1 = NULL;
+ }
+
+ if (!item->proof) {
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(item->proof, (void *)proof);
+ proof = NULL;
+ if (!res->items) {
+ res->items = apol_vector_create(sechk_item_free);
+ if (!res->items) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto spurious_audit_run_fail;
+ }
+ }
+ apol_vector_append(res->items, (void *)item);
+ item = NULL;
+ }
+
+ /* clean up */
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ apol_vector_destroy(&allow_rules);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ }
+
+ apol_vector_destroy(&auditallow_rules);
+ apol_avrule_query_destroy(&query);
+
+ mod->result = res;
+
+ /* If module finds something that would be considered a fail
+ * on the policy return 1 here */
+ if (apol_vector_get_size(res->items) > 0)
+ return 1;
+
+ return 0;
+
+ spurious_audit_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ apol_vector_destroy(&allow_rules);
+ apol_vector_destroy(&auditallow_rules);
+ apol_vector_destroy(&dontaudit_rules);
+ apol_vector_destroy(&perm_vector1);
+ apol_vector_destroy(&perm_vector2);
+ apol_vector_destroy(&perm_intersection);
+ qpol_iterator_destroy(&perm_iter1);
+ qpol_iterator_destroy(&perm_iter2);
+ apol_avrule_query_destroy(&query);
+ free(tmp);
+ tmp = NULL;
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text and prints the
+ * results to stdout. */
+int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0;
+ uint32_t ruletype;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ char *tmp;
+
+ if (!mod || !policy) {
+ ERR(NULL, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "%s%s%s", "wrong module (", mod->name, ")");
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "%s%s%s", "module ", mod->name, "has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ i = apol_vector_get_size(mod->result->items);
+ printf("Found %zd rule%s.\n", i, (i == 1) ? "" : "s");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item)));
+ free(tmp);
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items
+ * with an indented list of proof statements supporting the result
+ * of the check for that item. */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s\n", (tmp = apol_avrule_render(policy, (qpol_avrule_t *) item->item)));
+
+ qpol_avrule_get_rule_type(q, (qpol_avrule_t *) item->item, &ruletype);
+ if (ruletype == QPOL_RULE_DONTAUDIT) {
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\tinconsistent: ");
+ printf("%s\n", apol_avrule_render(policy, (qpol_avrule_t *) proof->elem));
+ printf("\tinconsistent permissions:\n");
+ printf("\t%s\n", proof->text);
+ }
+ } else if (ruletype == QPOL_RULE_AUDITALLOW) {
+ printf("\tmissing: ");
+ printf("%s\n", strstr(apol_avrule_render(policy, (qpol_avrule_t *) item->item), "allow"));
+ printf("\tmissing permissions:\n");
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
diff --git a/sechecker/modules/spurious_audit.h b/sechecker/modules/spurious_audit.h
new file mode 100644
index 0000000..19b93f6
--- /dev/null
+++ b/sechecker/modules/spurious_audit.h
@@ -0,0 +1,53 @@
+/**
+ * @file
+ * Defines the interface for the spurious audit rule module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Ryan Jordan rjordan@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SPURIOUS_AUDIT
+#define SPURIOUS_AUDIT
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+#define SECHK_SPUR_AU_AA_MISS 0x01
+#define SECHK_SPUR_AU_AA_PART 0x02
+#define SECHK_SPUR_AU_DA_FULL 0x04
+#define SECHK_SPUR_AU_DA_PART 0x08
+
+/* Module functions: */
+ int spurious_audit_register(sechk_lib_t * lib);
+ int spurious_audit_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int spurious_audit_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int spurious_audit_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/template/profiles.readme b/sechecker/modules/template/profiles.readme
new file mode 100644
index 0000000..f781ee0
--- /dev/null
+++ b/sechecker/modules/template/profiles.readme
@@ -0,0 +1,142 @@
+How to write a profile for SEChecker
+=====================================
+
+Table of Contents
+========================
+1. Use of Profiles
+2. Format of the Profile
+ 2.0 <sechecker>
+ 2.1 <profile>
+ 2.2 <module>
+ 2.3 <output>
+ 2.4 <option>
+3. Example Profile
+
+1. Use of Profiles
+==========================
+SEChecker has a wide variety of modules which perform various tests
+on the policy and/or system. To make the management and running of
+these modules easier, several profiles are defined.
+
+A profile is used to run a set of modules with options set in a way
+that the resulting report reflects a specific security goal.
+
+To write your own profile, create a new XML file named <profile name>.prof.
+The format of the file is detailed below.
+
+2. Format of the Profile
+=========================
+A profile is an XML file loaded by SEChecker to run a specific set of tests.
+The profile recognizes the following tags
+
+2.0 <sechecker>
+===========================
+The sechecker tag should be the first open tag in the file and the final
+tag to be closed. The tag has a single attribute version, which should
+be set to the current version of SEChecker you are using. To find your
+version number, run: "sechecker --version".
+
+<sechecker version="1.0">
+
+Be sure to remember to close this tag at the end of the file.
+
+2.1 <profile>
+===========================
+The profile tag tells the parser that SEChecker should interpret this
+file as a profile. This tag has no attributes.
+
+<profile>
+
+Close this tag just before the sechecker tag is closed at the end of the file
+
+2.2 <module>
+===========================
+The module tag tells SEChecker that a particular module should be run for
+this profile. The only attribute is name.
+
+<module name="mod_name">
+
+This tag is closed after all other tags related to that module
+
+2.3 <output>
+=========================
+The output tag tells SEChecker to use this output format for the module
+in which it appears. This tag is optional and has one attribute, value.
+
+<output value="short"/>
+
+This tag should close itself. The valid values are:
+ none - do not print anything in the report; only run this module
+ as dependency of another module.
+ quiet - print only the stats and header in the report
+ short - print the header, stats, and a list of items found by the
+ module without any accompanying proof
+ long - print the header, stats, and a list of items found by the
+ module with proof of the result following each item
+ verbose - print all possible output including the header, stats,
+ a list of items and a list of items with proof
+
+NOTE: any of the above values other than "none" are overridden by the
+ command line output flags. Setting an output value in a profile
+ overrides the default setting in the configuration file for this
+ profile only.
+
+2.4 <option>
+=======================
+The option tag allows a profile to specify additional options for a module.
+The option tag has two mandatory attributes, "name" and "value".
+The values of these attributes is specific to the module for which the
+option is specified. Options specified in a profile are used in addition
+to those in the configuration file.
+
+<option name="option_name" value="some_value"/>
+
+This tag closes itself. As its name implies this tag is optional.
+
+3. Example Profile
+======================
+The following is a brief example of a profile
+
+<sechecker version="1.0">
+<profile>
+
+ <module name="mod1">
+ </module>
+
+ <module name="mod2">
+ <output value="none"/>
+ <option name="attribute" value="my_attrib"/>
+ </module>
+
+ <module name="mod3">
+ <option name="foo" value="bar"/>
+ </module>
+
+ <module name="mod4">
+ <output value="short"/>
+ </module>
+
+ <module name="mod5">
+ <output value="quiet"/>
+ <option name="type" value="shadow_t"/>
+ </module>
+
+</profile>
+</sechecker>
+
+The result of this profile would be:
+- run mod1 with default configuration;
+ print with default settings
+- run mod2 with the additional attribute my_attrib,
+ but don't print its results
+- run mod3 with option foo set to bar (in addition to any other settings);
+ print with default settings
+- run mod4;
+ print in short output
+- run mod5 with additional type shadow_t;
+ print using quiet output
+
+If there are also modules mod6 and mod7, neither would be run unless
+one of the other modules (mod1-5) had a dependency on them.
+
+
diff --git a/sechecker/modules/template/template.howto b/sechecker/modules/template/template.howto
new file mode 100644
index 0000000..09151e0
--- /dev/null
+++ b/sechecker/modules/template/template.howto
@@ -0,0 +1,13 @@
+Instructions for using the template to add new modules
+========================================================
+1. copy the xx.c and xx.h files to the modules directory
+2. rename the files and replace the text xx with the
+ module name in both files
+3. add the register function for your module xx_register
+ to the register_list.h and register_list.c entries
+4. add options and any requirements or dependencies to
+ the decription in the register function
+5. fill out TODO sections of the template with logic for
+ your module
+6. recompile
+
diff --git a/sechecker/modules/template/xx.c b/sechecker/modules/template/xx.c
new file mode 100644
index 0000000..20f7f5f
--- /dev/null
+++ b/sechecker/modules/template/xx.c
@@ -0,0 +1,393 @@
+/**
+ * @file
+ * Implementation of the xx module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* NOTE: TODO This is a module template, which includes all the necessary
+ * infrastructure to implement a basic SEChecker module. To use this template
+ * first replace all instances of the string xx with the name of the module,
+ * then edit or complete all sections marked TODO as instructed. */
+
+#include <config.h>
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include "xx.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem of the file
+ * name; it should also match the prefix of all functions defined in this
+ * module and the private data storage structure */
+static const char *const mod_name = "xx";
+
+/* The register function registers all of a module's functions
+ * with the library. TODO: Edit the description fields to include all
+ * options, requirements, and dependencies. Also provide a brief summary
+ * of the steps performed in this module's checks. If you are adding
+ * additional functions you need other modules to call, see the note at
+ * the bottom of this function to do so. */
+int xx_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+ sechk_name_value_t *nv = NULL;
+
+ if (!lib) {
+ ERR(NULL, "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the register list file and their name and options
+ * are stored in the module vector of the library. The name is looked up to
+ * determine where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(lib->policy, "Module unknown \"%s\"", mod_name);
+ errno = ENOENT;
+ return -1;
+ }
+
+ mod->parent_lib = lib;
+
+ /* TODO: assign the descriptions */
+ mod->brief_description = "";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "TODO: detailed description for this module.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = "TODO: set proper severity";
+
+ /* TODO: assign default options (remove if none)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->options, (void *)nv);
+
+ /* TODO: assign requirements (remove if none)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->requirements, (void *)nv);
+
+ /* TODO: assign dependencies (remove if not needed)
+ * fill name and value and repeat as needed */
+ nv = sechk_name_value_new("", "");
+ apol_vector_append(mod->dependencies, (void *)nv);
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_init;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_run;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ /* TODO: if the module does not have a private data structure
+ * set this function pointer to NULL */
+ mod->data_free = xx_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(lib->policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = xx_print;
+ apol_vector_append(mod->functions, (void *)fn_struct);
+
+ /* TODO: (optional) add any other functions needed here,
+ * add a block as above for each additional function */
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object and
+ * initializes its values. Add any option processing logic as indicated below.
+ * TODO: add options processing logic */
+int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_name_value_t *opt = NULL;
+ xx_data_t *datum = NULL;
+ int error = 0;
+ size_t i = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)\n", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* If the module doesnot have a privte data sturcture replace the following
+ * block with "mod->data = NULL" */
+ datum = xx_data_new();
+ if (!datum) {
+ error = errno;
+ ERR(policy, "Error: %s\n", strerror(error));
+ errno = error;
+ return -1;
+ }
+ mod->data = datum;
+
+ for (i = 0; i < apol_vector_get_size(mod->options); i++) {
+ opt = apol_vector_get_element(mod->options, i);
+ /* TODO: check options
+ * check strings opt->name and opt->value of each option
+ * to set the members of the private data storage object
+ * (pointed to by datum).
+ * i.e. if (!strcmp(...)) {} else if (!strcmp((...)) etc.
+ * There should be relatively few options for any one module.
+ * If too many options are needed consider splitting the check
+ * into multiple modules and using dependencies. It is desirable
+ * for all checks to be a simple and granular as is possible */
+ }
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found
+ * TODO: add check logic */
+int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ xx_data_t *datum;
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ int error = 0;
+
+ /* TODO: define any aditional variables needed */
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (xx_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto xx_run_fail;
+ }
+ /* TODO: set res->item_type to indicate which array the item_id indexes
+ * use values from the sechk_item_type_e enum (see sechecker.h) */
+
+ /* TODO: check logic here
+ * Perform check here. Create and initialize items and proof as found,
+ * appending to the appropriate vectors.
+ * For examples of the type of code to use here see other modules. */
+
+ mod->result = res;
+
+ /* If module finds something that would be considered a failure
+ * of the policy return 1 here */
+ if (apol_vector_get_size(res->items) > 0)
+ return 1;
+
+ return 0;
+
+ xx_run_fail:
+ /* TODO: free any other memory allocated during check logic */
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module
+ * TODO: be sure to free any allocated space in the private data */
+void xx_data_free(void *data)
+{
+ xx_data_t *datum = (xx_data_t *) data;
+
+ if (datum) {
+ /* TODO: free any allocated members of the module's
+ * private data structure */
+ }
+
+ free(data);
+}
+
+/* The print function generates the text and prints the results to stdout. The
+ * outline below prints the standard format of a report section. Some modules
+ * may not have results in a format that can be represented by this outline and
+ * will need a different specification. It is required that each of the flags
+ * for output components be tested in this function (stats, list, proof,
+ * detailed, and brief) TODO: fill in the indicated information in the report
+ * fields as indicated below. Some alteration may be necessary for checks that
+ * perform different analyses */
+int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ xx_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (xx_data_t *) mod->data;
+ outformat = mod->outputformat;
+
+ if (!mod->result) {
+ ERR(policy, "Module %s has not been run", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* TODO: display the statistics of the results
+ * typical text is "Found %i <itemtype>.\n"
+ * additional information may be printed here depending upon
+ * the amount of data gathered in the check */
+ if (outformat & SECHK_OUT_STATS) {
+ /* TODO: "Found %i <itemtype>.\n": enter itemtype */
+ printf("Found %zd .\n", apol_vector_get_size(mod->result->items));
+ /* TODO: any additional generated statistics */
+ }
+ /* The list report component is a display of all items found without any
+ * supporting proof. The default method is to display a comma separated list
+ * four items to a line this may need to be changed for longer items.
+ * TODO: you will need to enter the string representation of
+ * each item as the second parameter in the printf statement
+ * in place of the empty string.
+ * NOTE: if the item is a type of rule print only one per line. */
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ i++;
+ /* TODO: (optional) change the number below to
+ * print more or less than 4 items per line */
+ i %= 4;
+ /* TODO: second parameter: item name */
+ printf("%s%s", "", (i ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ /* The proof report component is a display of a list of items with an
+ * indented list of proof statements supporting the result of the check for
+ * that item (e.g. rules with a given type). Each proof element is then
+ * displayed in an indented list one per line below it.
+ * TODO: the name of the item should be entered below.
+ * NOTE: certain checks may need to further modify this report component if
+ * the results cannot be presented in this format */
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (i = 0; i < apol_vector_get_size(mod->result->items); i++) {
+ item = apol_vector_get_element(mod->result->items, i);
+ printf("%s", ""); /* TODO: item name */
+ printf(" - severity: %s\n", sechk_item_sev(item));
+ for (j = 0; j < apol_vector_get_size(item->proof); j++) {
+ proof = apol_vector_get_element(item->proof, j);
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+/* The xx_data_new function allocates and returns an initialized private data
+ * storage structure for this module.
+ * TODO: initialize any non-zero/non-null data (if needed) below */
+xx_data_t *xx_data_new(void)
+{
+ xx_data_t *datum = NULL;
+
+ datum = (xx_data_t *) calloc(1, sizeof(xx_data_t));
+
+ /* TODO: initialize data */
+
+ return datum;
+}
diff --git a/sechecker/modules/template/xx.h b/sechecker/modules/template/xx.h
new file mode 100644
index 0000000..d8c18b8
--- /dev/null
+++ b/sechecker/modules/template/xx.h
@@ -0,0 +1,72 @@
+/**
+ * @file
+ * Defines the interface for the xx module.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* NOTE: TODO This is a module template, which includes all the necessary
+ * infrastructure to implement a basic SEChecker module. To use this template
+ * first replace all instances of the string xx with the name of the module,
+ * then edit or complete all sections marked TODO as instructed. Do not forget
+ * to add an entry in the register_list files (see these files for further
+ * instruction) */
+
+#include "sechecker.h"
+#include <apol/policy.h>
+
+/* The xx_data structure is used to hold the check specific
+ * private data of a module.
+ * TODO: Add any members you need to perform the check or if the module is not
+ * going to need private data remove this declaration and the data_new() and
+ * data_free() functions */
+typedef struct xx_data
+{
+ /* TODO: define members of this data structure
+ * for module's private data */
+} xx_data_t;
+
+/* The following functions are used to allocate and initialize the private data
+ * storage structure for this module and to free all memory used by it. */
+xx_data_t *xx_data_new(void);
+void xx_data_free(void *data);
+
+/* The register function places the needed information about the module in the
+ * library, including description fields and the functions available. TODO: be
+ * sure to add an entry for this function in the register_list files. */
+int xx_register(sechk_lib_t * lib);
+
+/* Module functions:
+ * The following three functions (init, run, and print) must exist for all
+ * modules. NOTE: while using a modular format SEChecker is built statically;
+ * this means that all modules and their functions are in the same namespace.
+ * Be sure to choose a unique name for each module and to set the module name
+ * prefix xx everywhere */
+int xx_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+int xx_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+int xx_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+/* TODO: (optional) Declare any other functions needed by other modules here.
+ * The prototype of the function must be int xx_fn(sechk_module_t *mod,
+ * apol_policy_t *policy, void *arg). For use by the get_module_function()
+ * function, be sure to add a block in the xx_register function to register
+ * your function.
+ * NOTE: While SEChecker is build statically, it is intended that no module
+ * directly call a function from another but instead use get_module_function()
+ * to get the desired function from the library. */
diff --git a/sechecker/modules/types_wo_allow.c b/sechecker/modules/types_wo_allow.c
new file mode 100644
index 0000000..2d0112a
--- /dev/null
+++ b/sechecker/modules/types_wo_allow.c
@@ -0,0 +1,442 @@
+/**
+ * @file
+ * Implementation of the types without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "types_wo_allow.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "types_wo_allow";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int types_wo_allow_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "types with no allow rules";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds types defined in the policy that are not used in any allow\n"
+ "rules. A type that is never granted an allow rule in the policy is a dead type.\n"
+ "This means that all attempted access to the type will be denied including\n"
+ "attempts to relabel to a (usable) type. The type may need to be removed from\n"
+ "the policy or some intended access should be granted to the type.\n";
+ mod->opt_description =
+ "Module requirements:\n" " none\n" "Module dependencies:\n" " none\n" "Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup("get_list");
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = types_wo_allow_get_list;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. This function allocates the result
+ * structure and fills in all relavant item and proof data. */
+int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ bool used = false;
+ apol_vector_t *type_vector;
+ apol_vector_t *avrule_vector;
+ apol_avrule_query_t *avrule_query = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+
+ if (!(avrule_query = apol_avrule_query_create())) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+
+ if (apol_type_get_by_query(policy, NULL, &type_vector) < 0) {
+ error = errno;
+ goto types_wo_allow_run_fail;
+ }
+
+ for (i = 0; i < apol_vector_get_size(type_vector); i++) {
+ const qpol_type_t *type;
+ const char *type_name;
+ size_t j;
+
+ used = false;
+ type = apol_vector_get_element(type_vector, i);
+ qpol_type_get_name(q, type, &type_name);
+
+ /* Check source for allow type */
+ apol_avrule_query_set_source(policy, avrule_query, type_name, 1);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ uint32_t rule_type;
+ qpol_avrule_t *rule;
+
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_rule_type(q, rule, &rule_type);
+ if (rule_type == QPOL_RULE_ALLOW)
+ used = true;
+ }
+ apol_vector_destroy(&avrule_vector);
+ if (used)
+ continue;
+
+ /* Check target for allow type */
+ apol_avrule_query_set_source(policy, avrule_query, NULL, 0);
+ apol_avrule_query_set_target(policy, avrule_query, type_name, 1);
+ apol_avrule_get_by_query(policy, avrule_query, &avrule_vector);
+ for (j = 0; j < apol_vector_get_size(avrule_vector); j++) {
+ uint32_t rule_type;
+ qpol_avrule_t *rule;
+
+ rule = apol_vector_get_element(avrule_vector, j);
+ qpol_avrule_get_rule_type(q, rule, &rule_type);
+ if (rule_type == QPOL_RULE_ALLOW)
+ used = true;
+ }
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_set_target(policy, avrule_query, NULL, 0);
+ if (used)
+ continue;
+
+ /* not used anywhere */
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ item->test_result = 1;
+ item->item = (void *)type;
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ proof->type = SECHK_ITEM_TYPE;
+ proof->text = strdup("This type does not appear in any allow rules.");
+ if (!proof->text) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto types_wo_allow_run_fail;
+ }
+ }
+ apol_vector_destroy(&type_vector);
+ apol_vector_destroy(&avrule_vector);
+ apol_avrule_query_destroy(&avrule_query);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ types_wo_allow_run_fail:
+ apol_vector_destroy(&type_vector);
+ apol_vector_destroy(&avrule_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print function generates the text printed in the
+ * report and prints it to stdout. */
+int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k = 0, l = 0, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %i types.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following types do not appear in any allow rules.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ j %= 4;
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ }
+ printf("\n");
+ }
+ type = NULL;
+ type_name = NULL;
+
+ return 0;
+}
+
+int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy __attribute__ ((unused)), void *arg)
+{
+ apol_vector_t **v = arg;
+
+ if (!mod || !arg) {
+ ERR(NULL, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(NULL, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+ if (!mod->result) {
+ ERR(NULL, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ v = &mod->result->items;
+ return 0;
+}
diff --git a/sechecker/modules/types_wo_allow.h b/sechecker/modules/types_wo_allow.h
new file mode 100644
index 0000000..325c786
--- /dev/null
+++ b/sechecker/modules/types_wo_allow.h
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * Defines the interface for the types without allow rules module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TYPES_WO_ALLOW
+#define TYPES_WO_ALLOW
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/avrule-query.h>
+#include <apol/type-query.h>
+
+ int types_wo_allow_register(sechk_lib_t * lib);
+ int types_wo_allow_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int types_wo_allow_get_list(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sechecker/modules/unreachable_doms.c b/sechecker/modules/unreachable_doms.c
new file mode 100644
index 0000000..4653c2d
--- /dev/null
+++ b/sechecker/modules/unreachable_doms.c
@@ -0,0 +1,1053 @@
+/**
+ * @file
+ * Implementation of the unreachable domains module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "unreachable_doms.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy);
+static bool in_isid_ctx(const char *type_name, apol_policy_t * policy);
+static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum);
+/* for some reason we have to define this here to remove compile warnings */
+extern ssize_t getline(char **lineptr, size_t * n, FILE * stream);
+
+/* This string is the name f the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "unreachable_doms";
+
+int unreachable_doms_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "unreachable domains";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all domains in a policy which are unreachable. A domain is\n"
+ "unreachable if any of the following apply:\n"
+ " 1) There is insufficient type enforcement policy to allow a transition,\n"
+ " 2) There is insufficient RBAC policy to allow a transition,\n"
+ " 3) There are no users with proper roles to allow a transition.\n"
+ "However, if any of the above rules indicate an unreachable domain, yet the\n"
+ "domain appears in the system default contexts file, it is considered reachable.\n";
+ mod->opt_description = " Module requirements:\n" " attribute names\n"
+#ifdef LIBSELINUX
+ " default_contexts file\n"
+#endif
+ " Module dependencies:\n" " find_domains module\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_MED;
+
+ /* assign requirements */
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_POLICY_CAP, SECHK_REQ_CAP_ATTRIB_NAMES)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#ifdef LIBSELINUX
+ if (apol_vector_append(mod->requirements, sechk_name_value_new(SECHK_REQ_DEFAULT_CONTEXTS, NULL)) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#endif
+
+ /* assign dependencies */
+ if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_domains")) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = unreachable_doms_data_free;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = unreachable_doms_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum = NULL;
+ const char *ctx_file_path = NULL;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = unreachable_doms_data_new();
+ if (!datum) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ mod->data = datum;
+
+ /* Parse default contexts file */
+ if (!(datum->ctx_vector = apol_vector_create(free))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+#ifdef LIBSELINUX
+ ctx_file_path = selinux_default_context_path();
+ if (!ctx_file_path) {
+ ERR(policy, "%s", "Unable to find default contexts file");
+ errno = ENOENT;
+ return -1;
+ } else {
+ bool retv = parse_default_contexts(ctx_file_path, datum->ctx_vector, policy);
+ if (!retv) {
+ ERR(policy, "%s", "Unable to parse default contexts file");
+ errno = EIO;
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+typedef enum dom_need
+{
+ KEEP_SEARCHING = 0, /* keep checking way to reach not found yet */
+ USER, /* missing a user for role(s) associated with the type */
+ COMMON_USER, /* missing user for the role in a transition to that type */
+ ROLE_TRANS, /* transition is valid but need a role transition as well */
+ ROLE_ALLOW, /* transition is valid and has a role_transition but not role allow */
+ RBAC, /* there is a transition but insufficient RBAC rules to permit or to determie a user */
+ VALID_TRANS, /* only transitions to the type are invalid ones needs one or more rules to complete */
+ ROLE, /* type has no associated role */
+ TRANSITION, /* no transition exists */
+ DONE /* done searching a valid way to reach the type has been found */
+} dom_need_e;
+
+/**
+ * Finds user witn at least one role from each vector.
+ * @param policy The policy.
+ * @param src_roles The first set of roles.
+ * @param tgt_roles The second set of roles.
+ * @return 1 if a common user can be found 0 other wise.
+ */
+static int exists_common_user(apol_policy_t * policy, apol_vector_t * src_roles, apol_vector_t * tgt_roles,
+ const qpol_role_t ** which_sr, const qpol_role_t ** which_tr, const qpol_user_t ** which_u)
+{
+ int retv = 0;
+ apol_user_query_t *uq;
+ const char *name = NULL;
+ const qpol_role_t *role = NULL;
+ const qpol_user_t *user = NULL;
+ qpol_iterator_t *iter = NULL;
+ apol_vector_t *user_v = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, j, k;
+
+ if (!policy || !src_roles || !tgt_roles)
+ return 0;
+
+ if (which_sr)
+ *which_sr = NULL;
+ if (which_tr)
+ *which_tr = NULL;
+ if (which_u)
+ *which_u = NULL;
+
+ if (!(uq = apol_user_query_create()))
+ return 0;
+
+ for (i = 0; i < apol_vector_get_size(src_roles); i++) {
+ role = apol_vector_get_element(src_roles, i);
+ if (which_sr)
+ *which_sr = role;
+ qpol_role_get_name(q, role, &name);
+ apol_user_query_set_role(policy, uq, name);
+ apol_user_get_by_query(policy, uq, &user_v);
+ for (j = 0; j < apol_vector_get_size(user_v); j++) {
+ user = apol_vector_get_element(user_v, j);
+ qpol_user_get_role_iter(q, user, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_iterator_get_item(iter, (void **)&role);
+ if (!apol_vector_get_index(tgt_roles, role, NULL, NULL, &k)) {
+ retv = 1;
+ if (which_tr)
+ *which_tr = role;
+ if (which_u)
+ *which_u = user;
+ goto exists_done;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ apol_vector_destroy(&user_v);
+ }
+
+ exists_done:
+ qpol_iterator_destroy(&iter);
+ apol_vector_destroy(&user_v);
+ apol_user_query_destroy(&uq);
+ return retv;
+}
+
+/* The run function performs the check. This function runs only once even if
+ * called multiple times. This function allocates the result structure and
+ * fills in all relevant item and proof data.
+ * Return Values:
+ * -1 System error
+ * 0 The module "succeeded" - no negative results found
+ * 1 The module "failed" - some negative results found */
+int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum;
+ sechk_name_value_t *dep = NULL;
+ sechk_result_t *res = NULL, *find_domains_res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i, j, k, l;
+ sechk_mod_fn_t run_fn = NULL;
+ int error = 0, trans_missing = 0;
+ apol_vector_t *dom_vector = NULL, *dom_results = NULL, *dom_roles = NULL;
+ apol_vector_t *valid_rev_trans = NULL, *invalid_rev_trans = NULL;
+ apol_vector_t *start_roles = NULL, *intersect_roles = NULL;
+ apol_vector_t *tmp_users = NULL, *role_users = NULL;
+ apol_vector_t *role_trans_vector = NULL, *role_allow_vector = NULL;
+ apol_domain_trans_analysis_t *dta = NULL;
+ apol_domain_trans_result_t *dtr = NULL;
+ const char *tmp_name = NULL, *cur_dom_name = NULL;
+ const char *tmp2 = NULL, *tmp3 = NULL;
+ const qpol_type_t *cur_dom = NULL, *ep_type = NULL, *start_type = NULL;
+ const qpol_type_t *last_type = NULL;
+ const qpol_role_t *last_role = NULL, *src_role = NULL, *dflt_role = NULL;
+ const qpol_role_t *last_dflt = NULL;
+ const qpol_user_t *last_user = NULL;
+ dom_need_e need = KEEP_SEARCHING;
+ apol_role_query_t *role_q = NULL;
+ apol_user_query_t *user_q = NULL;
+ apol_role_trans_query_t *rtq = NULL;
+ apol_role_allow_query_t *raq = NULL;
+ const qpol_role_trans_t *role_trans = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ datum = (unreachable_doms_data_t *) mod->data;
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto unreachable_doms_run_fail;
+ }
+ res->item_type = SECHK_ITEM_TYPE;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto unreachable_doms_run_fail;
+ }
+
+ /* run dependencies and get results */
+ for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) {
+ dep = apol_vector_get_element(mod->dependencies, i);
+ run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib);
+ run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL);
+ }
+
+ find_domains_res = sechk_lib_get_module_result("find_domains", mod->parent_lib);
+ dom_results = find_domains_res->items;
+ if (!(dom_vector = apol_vector_create(NULL))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ for (i = 0; i < apol_vector_get_size(dom_results); i++) {
+ item = apol_vector_get_element(dom_results, i);
+ if (apol_vector_append(dom_vector, (void *)(item->item))) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ }
+ item = NULL;
+ dom_results = NULL; /* no need to destroy, belongs to another module. */
+
+ /* initialize query objects */
+ dta = apol_domain_trans_analysis_create();
+ if (!dta) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ apol_domain_trans_analysis_set_direction(policy, dta, APOL_DOMAIN_TRANS_DIRECTION_REVERSE);
+
+ role_q = apol_role_query_create();
+ if (!role_q) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ user_q = apol_user_query_create();
+ if (!user_q) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ rtq = apol_role_trans_query_create();
+ if (!rtq) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ raq = apol_role_allow_query_create();
+ if (!raq) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+
+ /* dom_vector now contains all types considered domains */
+ for (i = 0; i < apol_vector_get_size(dom_vector); i++) {
+ cur_dom = apol_vector_get_element(dom_vector, i);
+ qpol_type_get_name(q, cur_dom, &cur_dom_name);
+ need = KEEP_SEARCHING;
+
+ if (
+#ifdef LIBSELINUX
+ in_def_ctx(cur_dom_name, datum) ||
+#endif
+ in_isid_ctx(cur_dom_name, policy))
+ continue;
+
+ /* collect information about roles and transitions to this domain */
+ apol_role_query_set_type(policy, role_q, cur_dom_name);
+ apol_role_get_by_query(policy, role_q, &dom_roles);
+ apol_policy_reset_domain_trans_table(policy);
+ apol_domain_trans_analysis_set_start_type(policy, dta, cur_dom_name);
+ apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_VALID);
+ apol_domain_trans_analysis_do(policy, dta, &valid_rev_trans);
+ apol_policy_reset_domain_trans_table(policy);
+ apol_domain_trans_analysis_set_valid(policy, dta, APOL_DOMAIN_TRANS_SEARCH_INVALID);
+ apol_domain_trans_analysis_do(policy, dta, &invalid_rev_trans);
+
+ /* for valid transitions - validate RBAC, and then users */
+ for (j = 0; j < apol_vector_get_size(valid_rev_trans); j++) {
+ dtr = apol_vector_get_element(valid_rev_trans, j);
+ start_type = apol_domain_trans_result_get_start_type(dtr);
+ ep_type = apol_domain_trans_result_get_entrypoint_type(dtr);
+ qpol_type_get_name(q, start_type, &tmp_name);
+ apol_role_query_set_type(policy, role_q, tmp_name);
+ apol_role_get_by_query(policy, role_q, &start_roles);
+ intersect_roles = apol_vector_create_from_intersection(dom_roles, start_roles, NULL, NULL);
+ if (apol_vector_get_size(intersect_roles) > 0) {
+ /* find user with role in intersect */
+ role_users = apol_vector_create(NULL);
+ for (k = 0; k < apol_vector_get_size(intersect_roles); k++) {
+ last_role = apol_vector_get_element(intersect_roles, k);
+ qpol_role_get_name(q, last_role, &tmp_name);
+ apol_user_query_set_role(policy, user_q, tmp_name);
+ apol_user_get_by_query(policy, user_q, &tmp_users);
+ if (apol_vector_cat(role_users, tmp_users)) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ apol_vector_destroy(&tmp_users);
+ }
+ if (apol_vector_get_size(role_users) > 0)
+ need = DONE;
+ else
+ need = USER;
+ apol_vector_destroy(&role_users);
+ }
+ if (need == DONE)
+ break;
+ /* look for role_transitions */
+ qpol_type_get_name(q, ep_type, &tmp_name);
+ apol_role_trans_query_set_target(policy, rtq, tmp_name, 1);
+ apol_role_trans_get_by_query(policy, rtq, &role_trans_vector);
+ for (k = 0; need != DONE && k < apol_vector_get_size(role_trans_vector); k++) {
+ role_trans = apol_vector_get_element(role_trans_vector, k);
+ qpol_role_trans_get_source_role(q, role_trans, &src_role);
+ qpol_role_trans_get_default_role(q, role_trans, &dflt_role);
+ if (apol_vector_get_index(start_roles, src_role, NULL, NULL, &l)
+ || apol_vector_get_index(dom_roles, dflt_role, NULL, NULL, &l))
+ continue; /* start domain must have the source role and cur_dom must have default role or transition does not apply */
+ if (exists_common_user(policy, start_roles, dom_roles, NULL, NULL, NULL)) {
+ qpol_role_get_name(q, src_role, &tmp_name);
+ apol_role_allow_query_set_source(policy, raq, tmp_name);
+ qpol_role_get_name(q, dflt_role, &tmp_name);
+ apol_role_allow_query_set_target(policy, raq, tmp_name);
+ apol_role_allow_get_by_query(policy, raq, &role_allow_vector);
+ if (apol_vector_get_size(role_allow_vector) > 0) {
+ need = DONE;
+ } else {
+ need = ROLE_ALLOW;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ }
+ apol_vector_destroy(&role_allow_vector);
+ } else {
+ need = COMMON_USER;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ }
+ }
+ /* no roles usable in intersection and no transitions so pick first set with common user */
+ if (apol_vector_get_size(role_trans_vector) == 0) {
+ if (exists_common_user(policy, start_roles, dom_roles, &src_role, &dflt_role, &last_user)) {
+ need = ROLE_TRANS;
+ last_role = src_role;
+ last_dflt = dflt_role;
+ last_type = ep_type;
+ } else {
+ need = RBAC;
+ }
+ }
+ apol_vector_destroy(&role_trans_vector);
+ if (need == DONE)
+ break;
+ }
+ /* if no valid transition found - check what is needed to complete invalid ones */
+ if (need == KEEP_SEARCHING) {
+ for (j = 0; j < apol_vector_get_size(invalid_rev_trans); j++) {
+ dtr = apol_vector_get_element(invalid_rev_trans, j);
+ start_type = apol_domain_trans_result_get_start_type(dtr);
+ ep_type = apol_domain_trans_result_get_entrypoint_type(dtr);
+ trans_missing = apol_domain_trans_table_verify_trans(policy, start_type, ep_type, cur_dom);
+ need = VALID_TRANS;
+ /* since incomplete transitions can be missing types break if we
+ * found one with all three types specified, else keep the last one */
+ if (start_type && ep_type)
+ break;
+ }
+ }
+ /* if no transition exists (valid or otherwise) check that at least one role and user pair is valid */
+ if (need == KEEP_SEARCHING) {
+ role_users = apol_vector_create(NULL);
+ for (j = 0; j < apol_vector_get_size(dom_roles); j++) {
+ last_role = apol_vector_get_element(dom_roles, j);
+ qpol_role_get_name(q, last_role, &tmp_name);
+ apol_user_query_set_role(policy, user_q, tmp_name);
+ apol_user_get_by_query(policy, user_q, &tmp_users);
+ apol_vector_cat(role_users, tmp_users);
+ apol_vector_destroy(&tmp_users);
+ }
+ if (apol_vector_get_size(dom_roles) == 0) {
+ need = ROLE;
+ } else if (apol_vector_get_size(role_users) == 0) {
+ need = USER;
+ } else {
+ need = TRANSITION;
+ }
+ apol_vector_destroy(&role_users);
+ }
+ /* if something needs to be reported do so now */
+ if (need != DONE) {
+ assert(need != KEEP_SEARCHING);
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ item->item = (void *)cur_dom;
+ item->test_result = (unsigned char)need;
+ item->proof = apol_vector_create(sechk_proof_free);
+ if (!item->proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof->type = SECHK_ITEM_NONE;
+ proof->elem = NULL;
+ switch (need) {
+ case USER:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ if (asprintf(&proof->text, "No user associated with role %s for %s", tmp_name, cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case COMMON_USER:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ if (asprintf
+ (&proof->text, "Role transition required but no user associated with role %s and %s",
+ tmp_name, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE_TRANS:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ qpol_type_get_name(q, last_type, &tmp3);
+ if (asprintf(&proof->text, "Missing: role_transition %s %s %s;", tmp_name, tmp3, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE_ALLOW:
+ {
+ qpol_role_get_name(q, last_role, &tmp_name);
+ qpol_role_get_name(q, last_dflt, &tmp2);
+ if (asprintf
+ (&proof->text,
+ "Role transition required but missing role allow rule.\n\tMissing: allow %s %s;",
+ tmp_name, tmp2) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case RBAC:
+ {
+ if (asprintf
+ (&proof->text,
+ "Valid domain transition to %s exists but indufficient RBAC rules to permit it.",
+ cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case VALID_TRANS:
+ {
+ if (start_type)
+ qpol_type_get_name(q, start_type, &tmp2);
+ else
+ tmp2 = "<start_type>";
+ if (ep_type)
+ qpol_type_get_name(q, ep_type, &tmp3);
+ else
+ tmp3 = "<entrypont>";
+ if (asprintf
+ (&proof->text,
+ "Partial transition to %s found:\n\t%s: allow %s %s : process transition;\n\t%s: allow %s %s : file execute;\n\t%s: allow %s %s : file entrypoint;\n\t%s one of:\n\tallow %s self : process setexec;\n\ttype_transition %s %s : process %s;",
+ cur_dom_name,
+ ((trans_missing & APOL_DOMAIN_TRANS_RULE_PROC_TRANS) ? "Missing" : "Has"), tmp2,
+ cur_dom_name, ((trans_missing & APOL_DOMAIN_TRANS_RULE_EXEC) ? "Missing" : "Has"),
+ tmp2, tmp3, ((trans_missing & APOL_DOMAIN_TRANS_RULE_ENTRYPOINT) ? "Missing" : "Has"),
+ cur_dom_name, tmp3,
+ ((trans_missing & (APOL_DOMAIN_TRANS_RULE_TYPE_TRANS | APOL_DOMAIN_TRANS_RULE_SETEXEC))
+ ? "May need" : "Has"), cur_dom_name, tmp2, tmp3, cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case ROLE:
+ {
+ if (asprintf(&proof->text, "No role associated with domain %s", cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case TRANSITION:
+ {
+ if (asprintf(&proof->text, "There are no transitions to domain %s", cur_dom_name) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ break;
+ }
+ case DONE:
+ case KEEP_SEARCHING:
+ default:
+ {
+ assert(0);
+ error = EDOM;
+ goto unreachable_doms_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ proof = NULL;
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(error));
+ goto unreachable_doms_run_fail;
+ }
+ item = NULL;
+ }
+ apol_vector_destroy(&dom_roles);
+ apol_vector_destroy(&valid_rev_trans);
+ apol_vector_destroy(&invalid_rev_trans);
+ }
+
+ apol_vector_destroy(&dom_vector);
+ apol_domain_trans_analysis_destroy(&dta);
+ apol_role_query_destroy(&role_q);
+ apol_user_query_destroy(&user_q);
+ apol_role_trans_query_destroy(&rtq);
+ apol_role_allow_query_destroy(&raq);
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ unreachable_doms_run_fail:
+ apol_vector_destroy(&dom_vector);
+ apol_domain_trans_analysis_destroy(&dta);
+ apol_role_query_destroy(&role_q);
+ apol_user_query_destroy(&user_q);
+ apol_role_trans_query_destroy(&rtq);
+ apol_role_allow_query_destroy(&raq);
+ apol_vector_destroy(&dom_roles);
+ apol_vector_destroy(&valid_rev_trans);
+ apol_vector_destroy(&invalid_rev_trans);
+ apol_vector_destroy(&tmp_users);
+ apol_vector_destroy(&role_users);
+ apol_vector_destroy(&role_trans_vector);
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The free function frees the private data of a module */
+void unreachable_doms_data_free(void *data)
+{
+ unreachable_doms_data_t *d = data;
+ if (!data)
+ return;
+
+ free(d->ctx_file_path);
+ apol_vector_destroy(&d->ctx_vector);
+ free(data);
+}
+
+/* The print function generates the text and prints the results to stdout. */
+int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unreachable_doms_data_t *datum = NULL;
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i = 0, j = 0, k, l, num_items;
+ const qpol_type_t *type;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ const char *type_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ datum = (unreachable_doms_data_t *) mod->data;
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd unreachable domains.\n", num_items);
+ }
+
+ if (outformat & SECHK_OUT_LIST) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ type = (qpol_type_t *) item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+
+ if (outformat & SECHK_OUT_PROOF) {
+ if (apol_vector_get_size(datum->ctx_vector) > 0) {
+ printf("Found %zd domains in %s:\n", apol_vector_get_size(datum->ctx_vector),
+ selinux_default_context_path());
+ for (j = 0; j < apol_vector_get_size(datum->ctx_vector); j++) {
+ type_name = apol_vector_get_element(datum->ctx_vector, j);
+ printf("\t%s\n", type_name);
+ }
+ }
+
+ printf("\n");
+ for (k = 0; k < num_items; k++) {
+ item = apol_vector_get_element(mod->result->items, k);
+ if (item) {
+ type = item->item;
+ qpol_type_get_name(q, type, &type_name);
+ printf("%s\n", (char *)type_name);
+ for (l = 0; l < apol_vector_get_size(item->proof); l++) {
+ proof = apol_vector_get_element(item->proof, l);
+ if (proof)
+ printf("\t%s\n", proof->text);
+ }
+ }
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+/* The unreachable_doms_data_new function allocates and returns an initialized
+ * private data storage structure for this module. */
+unreachable_doms_data_t *unreachable_doms_data_new(void)
+{
+ unreachable_doms_data_t *datum = NULL;
+
+ datum = (unreachable_doms_data_t *) calloc(1, sizeof(unreachable_doms_data_t));
+
+ return datum;
+}
+
+/* Parses default_contexts and adds source domains to datum->ctx_list.
+ * The vector will contain newly allocated strings. */
+static bool parse_default_contexts(const char *ctx_file_path, apol_vector_t * ctx_vector, apol_policy_t * policy)
+{
+ int str_sz, i, charno, error = 0, retv;
+ FILE *ctx_file;
+ char *line = NULL, *src_role = NULL, *src_dom = NULL, *dst_role = NULL, *dst_dom = NULL;
+ size_t line_len = 0;
+ bool uses_mls = false;
+
+ printf("Using default contexts: %s\n", ctx_file_path);
+ ctx_file = fopen(ctx_file_path, "r");
+ if (!ctx_file) {
+ error = errno;
+ ERR(policy, "Opening default contexts file %s", ctx_file_path);
+ goto parse_default_contexts_fail;
+ }
+
+ while (!feof(ctx_file)) {
+ retv = getline(&line, &line_len, ctx_file);
+ if (retv == -1) {
+ if (feof(ctx_file)) {
+ break;
+ } else {
+ error = errno;
+ ERR(policy, "%s", "Reading default contexts file");
+ goto parse_default_contexts_fail;
+ }
+ }
+
+ uses_mls = false;
+ str_sz = APOL_STR_SZ + 128;
+ i = 0;
+
+ /* source role */
+ src_role = malloc(str_sz);
+ if (!src_role) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+
+ memset(src_role, 0x0, str_sz);
+ charno = 0;
+ while (line[i] != ':') {
+ if (!isspace(line[i])) {
+ src_role[i] = line[i];
+ charno++;
+ }
+ i++;
+ }
+ i++; /* skip ':' */
+
+ /* source type */
+ src_dom = malloc(str_sz);
+ if (!src_dom) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(src_dom, 0x0, str_sz);
+ charno = 0;
+ while (1) {
+ if (isspace(line[i]))
+ break;
+ /* Check for MLS */
+ if (line[i] == ':') {
+ uses_mls = true;
+ i++; /* skip ':' */
+ while (!isspace(line[i]))
+ i++;
+ }
+ if (uses_mls)
+ break;
+
+ src_dom[charno] = line[i];
+ charno++;
+ i++;
+ }
+
+ /* dest role */
+ dst_role = malloc(str_sz);
+ if (!dst_role) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(dst_role, 0x0, str_sz);
+ charno = 0;
+ while (line[i] != ':') {
+ if (!isspace(line[i])) {
+ dst_role[charno] = line[i];
+ charno++;
+ }
+
+ i++;
+ }
+ i++; /* skip ':' */
+
+ /* dest type */
+ dst_dom = malloc(str_sz);
+ if (!dst_dom) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ memset(dst_dom, 0x0, str_sz);
+ charno = 0;
+ while (line[i]) {
+ if (uses_mls)
+ if (line[i] == ':')
+ break;
+
+ if (!isspace(line[i]))
+ dst_dom[charno] = line[i];
+
+ charno++;
+ i++;
+ }
+
+ if (apol_vector_append(ctx_vector, (void *)strdup(src_dom)) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto parse_default_contexts_fail;
+ }
+ free(line);
+ line = NULL;
+ free(src_role);
+ free(src_dom);
+ free(dst_role);
+ free(dst_dom);
+ }
+ free(line);
+ fclose(ctx_file);
+ return true;
+ parse_default_contexts_fail:
+ if (ctx_file != NULL) {
+ fclose(ctx_file);
+ }
+ free(line);
+ free(src_role);
+ free(src_dom);
+ free(dst_role);
+ free(dst_dom);
+ errno = error;
+ return false;
+}
+
+/* Returns true if type_idx is in datum->ctx_list */
+static bool in_def_ctx(const char *type_name, unreachable_doms_data_t * datum)
+{
+ size_t i;
+ if (apol_vector_get_index(datum->ctx_vector, type_name, apol_str_strcmp, NULL, &i) < 0) {
+ return false;
+ }
+ return true;
+}
+
+/* Returns true if type is a type assigned to an isid */
+static bool in_isid_ctx(const char *type_name, apol_policy_t * policy)
+{
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ qpol_policy_get_isid_iter(q, &iter);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ const qpol_isid_t *isid;
+ const qpol_context_t *ocon;
+ const qpol_type_t *context_type;
+ const char *context_type_name;
+
+ qpol_iterator_get_item(iter, (void **)&isid);
+ qpol_isid_get_context(q, isid, &ocon);
+ qpol_context_get_type(q, ocon, &context_type);
+ qpol_type_get_name(q, context_type, &context_type_name);
+ if (!strcmp(type_name, context_type_name)) {
+ qpol_iterator_destroy(&iter);
+ return true;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ return false;
+}
diff --git a/sechecker/modules/unreachable_doms.h b/sechecker/modules/unreachable_doms.h
new file mode 100644
index 0000000..660de76
--- /dev/null
+++ b/sechecker/modules/unreachable_doms.h
@@ -0,0 +1,73 @@
+/**
+ * @file
+ * Defines the interface for the unreachable domains module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef UNREACHABLE_DOMS
+#define UNREACHABLE_DOMS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+#include <apol/role-query.h>
+#include <apol/isid-query.h>
+#include <apol/rbacrule-query.h>
+#include <apol/domain-trans-analysis.h>
+#include <selinux/selinux.h>
+
+#define SECHK_INC_DOM_TRANS_HAS_TT 0x08
+#define SECHK_INC_DOM_TRANS_HAS_EXEC 0x04
+#define SECHK_INC_DOM_TRANS_HAS_TRANS 0x02
+#define SECHK_INC_DOM_TRANS_HAS_EP 0x01
+#define SECHK_INC_DOM_TRANS_COMPLETE (SECHK_INC_DOM_TRANS_HAS_EP|SECHK_INC_DOM_TRANS_HAS_TRANS|SECHK_INC_DOM_TRANS_HAS_EXEC)
+
+#define APOL_STR_SZ 128
+
+/* The unreachable_doms_data structure is used to hold the check specific
+ * private data of a module. */
+ typedef struct unreachable_doms_data
+ {
+ char *ctx_file_path;
+ /* vector of strings, read from default contexts file */
+ apol_vector_t *ctx_vector;
+ } unreachable_doms_data_t;
+
+ unreachable_doms_data_t *unreachable_doms_data_new(void);
+ void unreachable_doms_data_free(void *data);
+
+ int unreachable_doms_register(sechk_lib_t * lib);
+ int unreachable_doms_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int unreachable_doms_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int unreachable_doms_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UNREACHABLE_DOMS */
diff --git a/sechecker/modules/users_wo_roles.c b/sechecker/modules/users_wo_roles.c
new file mode 100644
index 0000000..a98d94d
--- /dev/null
+++ b/sechecker/modules/users_wo_roles.c
@@ -0,0 +1,321 @@
+/**
+ * @file
+ * Implementation of the users without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "users_wo_roles.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* This string is the name of the module and should match the stem
+ * of the file name; it should also match the prefix of all functions
+ * defined in this module and the private data storage structure */
+static const char *const mod_name = "users_wo_roles";
+
+/* The register function registers all of a module's functions
+ * with the library. */
+int users_wo_roles_register(sechk_lib_t * lib)
+{
+ sechk_module_t *mod = NULL;
+ sechk_fn_t *fn_struct = NULL;
+
+ if (!lib) {
+ ERR(NULL, "%s", "No library");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Modules are declared by the config file and their name and options
+ * are stored in the module array. The name is looked up to determine
+ * where to store the function structures */
+ mod = sechk_lib_get_module(mod_name, lib);
+ if (!mod) {
+ ERR(NULL, "%s", "Module unknown");
+ errno = EINVAL;
+ return -1;
+ }
+ mod->parent_lib = lib;
+
+ /* assign the descriptions */
+ mod->brief_description = "users with no roles";
+ mod->detailed_description =
+ "--------------------------------------------------------------------------------\n"
+ "This module finds all the SELinux users in the policy that have no associated\n"
+ "roles. Users without roles may appear in the label of a file system object;\n"
+ "however, these users cannot login to the system or run any process. Since these\n"
+ "users cannot be used on the system, a policy change is recomended to remove the\n"
+ "users or provide some intended access.\n";
+ mod->opt_description =
+ " Module requirements:\n" " none\n" " Module dependencies:\n" " none\n" " Module options:\n" " none\n";
+ mod->severity = SECHK_SEV_LOW;
+ /* register functions */
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_INIT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_init;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_RUN);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_run;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mod->data_free = NULL;
+
+ fn_struct = sechk_fn_new();
+ if (!fn_struct) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->name = strdup(SECHK_MOD_FN_PRINT);
+ if (!fn_struct->name) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ fn_struct->fn = users_wo_roles_print;
+ if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* The init function creates the module's private data storage object
+ * and initializes its values based on the options parsed in the config
+ * file. */
+int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ mod->data = NULL;
+
+ return 0;
+}
+
+/* The run function performs the check. This function runs only once
+ * even if called multiple times. All test logic should be placed below
+ * as instructed. This function allocates the result structure and fills
+ * in all relavant item and proof data. */
+int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ sechk_result_t *res = NULL;
+ sechk_item_t *item = NULL;
+ sechk_proof_t *proof = NULL;
+ size_t i;
+ apol_vector_t *user_vector;
+ int error = 0;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* if already run return */
+ if (mod->result)
+ return 0;
+
+ res = sechk_result_new();
+ if (!res) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+ res->test_name = strdup(mod_name);
+ if (!res->test_name) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ res->item_type = SECHK_ITEM_USER;
+ if (!(res->items = apol_vector_create(sechk_item_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+
+ apol_user_get_by_query(policy, NULL, &user_vector);
+ for (i = 0; i < apol_vector_get_size(user_vector); i++) {
+ qpol_user_t *user;
+ qpol_iterator_t *role_iter;
+
+ user = apol_vector_get_element(user_vector, i);
+ qpol_user_get_role_iter(apol_policy_get_qpol(policy), user, &role_iter);
+ if (!qpol_iterator_end(role_iter)) {
+ qpol_iterator_destroy(&role_iter);
+ continue;
+ }
+ qpol_iterator_destroy(&role_iter);
+
+ proof = sechk_proof_new(NULL);
+ if (!proof) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ proof->type = SECHK_ITEM_USER;
+ proof->text = "User has no roles.\n";
+ item = sechk_item_new(NULL);
+ if (!item) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ item->item = (void *)user;
+ if (!item->proof) {
+ if (!(item->proof = apol_vector_create(sechk_proof_free))) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ }
+ if (apol_vector_append(item->proof, (void *)proof) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ if (apol_vector_append(res->items, (void *)item) < 0) {
+ error = errno;
+ ERR(policy, "%s", strerror(ENOMEM));
+ goto users_wo_roles_run_fail;
+ }
+ }
+ apol_vector_destroy(&user_vector);
+
+ mod->result = res;
+
+ if (apol_vector_get_size(res->items))
+ return 1;
+ return 0;
+
+ users_wo_roles_run_fail:
+ sechk_proof_free(proof);
+ sechk_item_free(item);
+ sechk_result_destroy(&res);
+ errno = error;
+ return -1;
+}
+
+/* The print output function generates the text printed in the
+ * report and prints it to stdout. */
+int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused)))
+{
+ unsigned char outformat = 0x00;
+ sechk_item_t *item = NULL;
+ size_t i = 0, j = 0, num_items;
+ const qpol_user_t *user;
+ const char *user_name;
+
+ if (!mod || !policy) {
+ ERR(policy, "%s", "Invalid parameters");
+ errno = EINVAL;
+ return -1;
+ }
+ if (strcmp(mod_name, mod->name)) {
+ ERR(policy, "Wrong module (%s)", mod->name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ outformat = mod->outputformat;
+ num_items = apol_vector_get_size(mod->result->items);
+
+ if (!outformat || (outformat & SECHK_OUT_QUIET))
+ return 0; /* not an error - no output is requested */
+
+ if (!mod->result) {
+ ERR(policy, "%s", "Module has not been run");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* display the statistics of the results */
+ if (outformat & SECHK_OUT_STATS) {
+ printf("Found %zd users.\n", num_items);
+ }
+ if (outformat & SECHK_OUT_PROOF) {
+ printf("\nThe following users have no associated roles.\n");
+ }
+ /* The list report component is a display of all items
+ * found without any supporting proof. */
+ if (outformat & (SECHK_OUT_LIST | SECHK_OUT_PROOF)) {
+ printf("\n");
+ for (i = 0; i < num_items; i++) {
+ j++;
+ j %= 4;
+ item = apol_vector_get_element(mod->result->items, i);
+ user = (qpol_user_t *) item->item;
+ qpol_user_get_name(apol_policy_get_qpol(policy), user, &user_name);
+ printf("%s%s", user_name, (char *)((j && i != num_items - 1) ? ", " : "\n"));
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/sechecker/modules/users_wo_roles.h b/sechecker/modules/users_wo_roles.h
new file mode 100644
index 0000000..dd1ee42
--- /dev/null
+++ b/sechecker/modules/users_wo_roles.h
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * Defines the interface for the users without roles module.
+ *
+ * @author Kevin Carr kcarr@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2005-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef USERS_WO_ROLES
+#define USERS_WO_ROLES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "sechecker.h"
+#include <apol/policy.h>
+#include <apol/user-query.h>
+
+ int users_wo_roles_register(sechk_lib_t * lib);
+ int users_wo_roles_init(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int users_wo_roles_run(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+ int users_wo_roles_print(sechk_module_t * mod, apol_policy_t * policy, void *arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif