From 47be9ff57e72906660bb62a515222f482131e1fb Mon Sep 17 00:00:00 2001 From: Miroslav Grepl Date: Fri, 11 Apr 2014 09:37:53 +0200 Subject: Create setools-3.3.7 git repo --- sechecker/modules/inc_net_access.c | 1852 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1852 insertions(+) create mode 100644 sechecker/modules/inc_net_access.c (limited to 'sechecker/modules/inc_net_access.c') diff --git a/sechecker/modules/inc_net_access.c b/sechecker/modules/inc_net_access.c new file mode 100644 index 0000000..a8903ea --- /dev/null +++ b/sechecker/modules/inc_net_access.c @@ -0,0 +1,1852 @@ +/** + * @file + * Defines the interface for the incomplete network access module. + * + * @author Kevin Carr kcarr@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author David Windsor dwindsor@tresys.com + * + * Copyright (C) 2005-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "inc_net_access.h" + +#include +#include +#include + +static const char *const mod_name = "inc_net_access"; + +/* The register function registers all of a module's functions + * with the library. You should not need to edit this function + * unless you are adding additional functions you need other modules + * to call. See the note at the bottom of this function to do so. */ +int inc_net_access_register(sechk_lib_t * lib) +{ + sechk_module_t *mod = NULL; + sechk_fn_t *fn_struct = NULL; + + if (!lib) { + ERR(NULL, "%s", "No library"); + errno = EINVAL; + return -1; + } + + /* Modules are declared by the config file and their name and options + * are stored in the module array. The name is looked up to determine + * where to store the function structures */ + mod = sechk_lib_get_module(mod_name, lib); + if (!mod) { + ERR(NULL, "%s", "Module unknown"); + errno = EINVAL; + return -1; + } + mod->parent_lib = lib; + + /* assign the descriptions */ + mod->brief_description = "finds network domains with inadequate permissions"; + mod->detailed_description = + "--------------------------------------------------------------------------------\n" + "This module finds all network domains in a policy which do not have the \n" + "required permissions needed to facilitate network communication. For network\n" + "domains to communicate, the following conditions must be true:\n" + " 1) the domain must have read or receive permissions on a socket of the same\n" + " type\n" + " 2) the domain must have send or receive permissions on an IPsec association\n" + " (see find_assoc_types)\n" + " 3) the domain must have send or receive permissions on netif objects for a\n" + " netif type (see find_netif_types)\n" + " 4) the domain must have send or receive permissions on node objects for a\n" + " node type (see find_node_types)\n" + " 5) the domain must have send or receive permissions on port objects for a\n" + " port type (see find_port_types)\n"; + mod->opt_description = + " Module requirements:\n" + " none\n" " Module dependencies:\n" " find_net_domains\n" " Module options:\n" " none\n"; + mod->severity = SECHK_SEV_MED; + /* assign dependencies */ + if (apol_vector_append(mod->dependencies, sechk_name_value_new("module", "find_net_domains")) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + /* register functions */ + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_INIT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_init; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_RUN); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_run; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + mod->data_free = NULL; + + fn_struct = sechk_fn_new(); + if (!fn_struct) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->name = strdup(SECHK_MOD_FN_PRINT); + if (!fn_struct->name) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + fn_struct->fn = inc_net_access_print; + if (apol_vector_append(mod->functions, (void *)fn_struct) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + + return 0; +} + +/* The init function creates the module's private data storage object + * and initializes its values based on the options parsed in the config + * file. + * Add any option processing logic as indicated below. */ +int inc_net_access_init(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + if (!mod || !policy) { + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + mod->data = NULL; + + return 0; +} + +/* This set of defines represents individual permission bits for + * the permissions needed to have complete network access */ +/* allow domain self : sock_file {read write getattr}; */ +#define PERM_SELF_SOCK_FILE_READ 0x00000001 +#define PERM_SELF_SOCK_FILE_WRITE 0x00000002 +#define PERM_SELF_SOCK_FILE_GETATTR 0x00000004 +/* allow domain self : tcp_socket {create read write}; */ +#define PERM_SELF_TCP_SOC_READ 0x00000008 +#define PERM_SELF_TCP_SOC_WRITE 0x00000010 +#define PERM_SELF_TCP_SOC_CREATE 0x00000020 +/* allow domain self : udp_socket {create read write}; */ +#define PERM_SELF_UDP_SOC_READ 0x00000040 +#define PERM_SELF_UDP_SOC_WRITE 0x00000080 +#define PERM_SELF_UDP_SOC_CREATE 0x00000100 +/* allow domain if_type : netif {tcp_send udp_send tcp_recv tcp_send}; */ +#define PERM_NETIF_TCP_SEND 0x00000200 +#define PERM_NETIF_UDP_SEND 0x00000400 +#define PERM_NETIF_TCP_RECV 0x00000800 +#define PERM_NETIF_UDP_RECV 0x00001000 +/* allow domain node_type : node {tcp_send udp_send tcp_recv tcp_send}; */ +#define PERM_NODE_TCP_SEND 0x00002000 +#define PERM_NODE_UDP_SEND 0x00004000 +#define PERM_NODE_TCP_RECV 0x00008000 +#define PERM_NODE_UDP_RECV 0x00010000 +/* allow domain port_type : tcp_socket {send_msg recv_msg}; */ +#define PERM_PORT_TCP_SEND 0x00020000 +#define PERM_PORT_TCP_RECV 0x00040000 +/* allow domain port_type : udp_socket {send_msg recv_msg}; */ +#define PERM_PORT_UDP_SEND 0x00080000 +#define PERM_PORT_UDP_RECV 0x00100000 +/* allow domain assoc_type : association {sendto recvfrom}; */ +#define PERM_ASSOC_SEND 0x00200000 +#define PERM_ASSOC_RECV 0x00400000 + +/* this set of defines represents masks for individual rules */ +#define RULE_TCP_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_UDPs_SOCK_FILE (PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_UDPr_SOCK_FILE (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_GETATTR) +#define RULE_TCP_SELF_SOC (PERM_SELF_TCP_SOC_READ|PERM_SELF_TCP_SOC_WRITE|PERM_SELF_TCP_SOC_CREATE) +#define RULE_UDPs_SELF_SOC (PERM_SELF_UDP_SOC_WRITE|PERM_SELF_UDP_SOC_CREATE) +#define RULE_UDPr_SELF_SOC (PERM_SELF_UDP_SOC_READ|PERM_SELF_UDP_SOC_CREATE) +#define RULE_TCP_NETIF (PERM_NETIF_TCP_SEND|PERM_NETIF_TCP_RECV) +#define RULE_UDPs_NETIF (PERM_NETIF_UDP_SEND) +#define RULE_UDPr_NETIF (PERM_NETIF_UDP_RECV) +#define RULE_TCP_NODE (PERM_NODE_TCP_SEND|PERM_NODE_TCP_RECV) +#define RULE_UDPs_NODE (PERM_NODE_UDP_SEND) +#define RULE_UDPr_NODE (PERM_NODE_UDP_RECV) +#define RULE_TCP_PORT (PERM_PORT_TCP_SEND|PERM_PORT_TCP_RECV) +#define RULE_UDPs_PORT (PERM_PORT_UDP_SEND) +#define RULE_UDPr_PORT (PERM_PORT_UDP_RECV) +#define RULE_TCP_ASSOC (PERM_ASSOC_SEND|PERM_ASSOC_RECV) +#define RULE_UDPs_ASSOC (PERM_ASSOC_SEND) +#define RULE_UDPr_ASSOC (PERM_ASSOC_RECV) + +/* This set of defines represents mask sets to represent access types */ +#define UDP_RECV_PERM_SET (RULE_UDPr_SOCK_FILE|RULE_UDPr_SELF_SOC|RULE_UDPr_NETIF|RULE_UDPr_NODE|RULE_UDPr_PORT|RULE_UDPr_ASSOC) +#define UDP_SEND_PERM_SET (RULE_UDPs_SOCK_FILE|RULE_UDPs_SELF_SOC|RULE_UDPs_NETIF|RULE_UDPs_NODE|RULE_UDPs_PORT|RULE_UDPs_ASSOC) +#define TCP_FULL_PERM_SET (RULE_TCP_SOCK_FILE|RULE_TCP_SELF_SOC|RULE_TCP_NETIF|RULE_TCP_NODE|RULE_TCP_PORT|RULE_TCP_ASSOC) +#define COMMON_ACCESS_SET (PERM_SELF_SOCK_FILE_READ|PERM_SELF_SOCK_FILE_WRITE|PERM_SELF_SOCK_FILE_GETATTR|PERM_ASSOC_SEND|PERM_ASSOC_RECV) + +typedef struct net_state +{ + uint32_t perms; + apol_vector_t *netifs; + apol_vector_t *nodes; + apol_vector_t *tcpsocs; + apol_vector_t *udpsocs; + apol_vector_t *assocs; +} net_state_t; + +typedef struct name_perm +{ + const char *name; /* will be from policy do not free */ + uint32_t perms; +} name_perm_t; + +static void net_state_destroy(net_state_t ** n) +{ + if (!n || !(*n)) + return; + + apol_vector_destroy(&((*n)->netifs)); + apol_vector_destroy(&((*n)->nodes)); + apol_vector_destroy(&((*n)->tcpsocs)); + apol_vector_destroy(&((*n)->udpsocs)); + apol_vector_destroy(&((*n)->assocs)); + free(*n); + *n = NULL; +} + +static net_state_t *net_state_create(void) +{ + net_state_t *n = NULL; + + n = calloc(1, sizeof(*n)); + n->netifs = apol_vector_create(free); + n->nodes = apol_vector_create(free); + n->tcpsocs = apol_vector_create(free); + n->udpsocs = apol_vector_create(free); + n->assocs = apol_vector_create(free); + + return n; +} + +static int name_perm_comp(const void *a, const void *b, void *arg __attribute__ ((unused))) +{ + const name_perm_t *x = a; + const name_perm_t *y = b; + + return strcmp(x->name, y->name); +} + +static name_perm_t *name_perm_create(const char *name) +{ + name_perm_t *np = NULL; + + np = calloc(1, sizeof(*np)); + np->name = name; + + return np; +} + +static int name_perm_vector_has_incomplete_perms(apol_vector_t * v, uint32_t mask) +{ + uint32_t tmp; + name_perm_t *np = NULL; + size_t i = 0; + + if (!apol_vector_get_size(v)) + return 1; + for (i = 0; i < apol_vector_get_size(v); i++) { + np = apol_vector_get_element(v, i); + tmp = np->perms & mask; + if (tmp != mask) + return 1; + } + + return 0; +} + +static void name_perm_vector_add_perm(apol_vector_t * v, const char *name, uint32_t perm) +{ + name_perm_t *np = NULL; + size_t i = 0; + int retv; + + np = name_perm_create(name); + retv = apol_vector_get_index(v, np, name_perm_comp, NULL, &i); + if (retv) { + np->perms = perm; + apol_vector_append(v, (void *)np); + } else { + free(np); /* already exists free temp one */ + np = apol_vector_get_element(v, i); + np->perms |= perm; + } +} + +static char *generate_tcp_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == TCP_FULL_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has TCP access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete TCP access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SOCK_FILE; + missing = attempt ^ RULE_TCP_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SELF_SOC; + missing = attempt ^ RULE_TCP_SELF_SOC; + asprintf(&tmp, "allow %s self : tcp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_TCP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_TCP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_TCP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_TCP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_TCP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_TCP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_TCP_NETIF; + missing = attempt ^ RULE_TCP_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (attempt & PERM_NETIF_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (missing & PERM_NETIF_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : netif { tcp_send tcp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_TCP_NODE; + missing = attempt ^ RULE_TCP_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (attempt & PERM_NODE_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "tcp_send ")) + goto err; + } + if (missing & PERM_NODE_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "tcp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : node { tcp_send tcp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->tcpsocs); i++) { + np = apol_vector_get_element(state->tcpsocs, i); + attempt = state->perms & RULE_TCP_PORT; + missing = attempt ^ RULE_TCP_PORT; + asprintf(&tmp, "allow %s %s : tcp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (attempt & PERM_PORT_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_TCP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (missing & PERM_PORT_TCP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->tcpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : tcp_socket { send_msg recv_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_TCP_ASSOC; + missing = attempt ^ RULE_TCP_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (missing & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : association { sendto recvfrom };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_udp_send_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == UDP_SEND_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has UDP send access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP send access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_UDPs_SOCK_FILE; + missing = attempt ^ RULE_UDPs_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_UDPs_SELF_SOC; + missing = attempt ^ RULE_UDPs_SELF_SOC; + asprintf(&tmp, "allow %s self : udp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_UDP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_UDP_SOC_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (missing & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_UDPs_NETIF; + missing = attempt ^ RULE_UDPs_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : netif { udp_send };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_UDPs_NODE; + missing = attempt ^ RULE_UDPs_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "udp_send ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : node { udp_send };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) { + np = apol_vector_get_element(state->udpsocs, i); + attempt = state->perms & RULE_UDPs_PORT; + missing = attempt ^ RULE_UDPs_PORT; + asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_UDP_SEND) { + if (apol_str_append(&text, &text_sz, "send_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->udpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : udp_socket { send_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_UDPs_ASSOC; + missing = attempt ^ RULE_UDPs_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : association { sendto };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_udp_recv_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0, missing = 0; + name_perm_t *np = NULL; + + if (state->perms == UDP_RECV_PERM_SET) { + if (apol_str_append(&text, &text_sz, "Domain has UDP receive access, but some accesses are incomplete.")) + goto err; + } else { + if (apol_str_append(&text, &text_sz, "Domain has incomplete UDP receive access.")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_UDPr_SOCK_FILE; + missing = attempt ^ RULE_UDPr_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tsocket creation permissions:")) + goto err; + attempt = state->perms & RULE_UDPr_SELF_SOC; + missing = attempt ^ RULE_UDPr_SELF_SOC; + asprintf(&tmp, "allow %s self : udp_socket { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_UDP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_SELF_UDP_SOC_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (missing & PERM_SELF_UDP_SOC_CREATE) { + if (apol_str_append(&text, &text_sz, "create ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tnetif permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->netifs); i++) { + np = apol_vector_get_element(state->netifs, i); + attempt = state->perms & RULE_UDPr_NETIF; + missing = attempt ^ RULE_UDPr_NETIF; + asprintf(&tmp, "allow %s %s : netif { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NETIF_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NETIF_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->netifs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : netif { udp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tnode permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->nodes); i++) { + np = apol_vector_get_element(state->nodes, i); + attempt = state->perms & RULE_UDPr_NODE; + missing = attempt ^ RULE_UDPr_NODE; + asprintf(&tmp, "allow %s %s : node { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_NODE_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_NODE_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "udp_recv ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->nodes)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : node { udp_recv };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tport socket permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->udpsocs); i++) { + np = apol_vector_get_element(state->udpsocs, i); + attempt = state->perms & RULE_UDPr_PORT; + missing = attempt ^ RULE_UDPr_PORT; + asprintf(&tmp, "allow %s %s : udp_socket { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_PORT_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_PORT_UDP_RECV) { + if (apol_str_append(&text, &text_sz, "recv_msg ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->udpsocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : udp_socket { recv_msg };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_UDPr_ASSOC; + missing = attempt ^ RULE_UDPr_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + if (missing) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (missing & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + if (!apol_vector_get_size(state->assocs)) { + if (apol_str_append(&text, &text_sz, "\n\t\tMissing: allow ")) + goto err; + if (apol_str_append(&text, &text_sz, domain)) + goto err; + if (apol_str_append(&text, &text_sz, " : association { recvfrom };")) + goto err; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +static char *generate_common_only_proof_text(const char *domain, net_state_t * state) +{ + char *text = NULL, *tmp = NULL; + size_t text_sz = 0, i; + uint32_t attempt = 0; + name_perm_t *np = NULL; + + if (apol_str_append + (&text, &text_sz, + "Domain has incomplete network access.\n\tDomain has no protocol specific permissions only the following:")) + goto err; + + if (apol_str_append(&text, &text_sz, "\n\tsock_file permissions:")) + goto err; + attempt = state->perms & RULE_TCP_SOCK_FILE; + asprintf(&tmp, "allow %s self : sock_file { ", domain); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_SELF_SOCK_FILE_READ) { + if (apol_str_append(&text, &text_sz, "read ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_WRITE) { + if (apol_str_append(&text, &text_sz, "write ")) + goto err; + } + if (attempt & PERM_SELF_SOCK_FILE_GETATTR) { + if (apol_str_append(&text, &text_sz, "getattr ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + + if (apol_str_append(&text, &text_sz, "\n\tassociation permissions:")) + goto err; + for (i = 0; i < apol_vector_get_size(state->assocs); i++) { + np = apol_vector_get_element(state->assocs, i); + attempt = state->perms & RULE_TCP_ASSOC; + asprintf(&tmp, "allow %s %s : association { ", domain, np->name); + if (attempt) { + if (apol_str_append(&text, &text_sz, "\n\t\tHas: ")) + goto err; + if (apol_str_append(&text, &text_sz, tmp)) + goto err; + if (attempt & PERM_ASSOC_SEND) { + if (apol_str_append(&text, &text_sz, "sendto ")) + goto err; + } + if (attempt & PERM_ASSOC_RECV) { + if (apol_str_append(&text, &text_sz, "recvfrom ")) + goto err; + } + if (apol_str_append(&text, &text_sz, "};")) + goto err; + } + free(tmp); + tmp = NULL; + } + + if (apol_str_append(&text, &text_sz, "\n")) + goto err; + + return text; + + err: + free(text); + free(tmp); + return NULL; +} + +/* The run function performs the check. This function runs only once + * even if called multiple times. This function allocates the result + * structure and fills in all relavant item and proof data. + * Return Values: + * -1 System error + * 0 The module "succeeded" - no negative results found + * 1 The module "failed" - some negative results found */ +int inc_net_access_run(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + sechk_result_t *res = NULL; + sechk_item_t *item = NULL, *tmp_item = NULL; + sechk_proof_t *proof = NULL; + sechk_result_t *net_domain_res = NULL; + sechk_name_value_t *dep = NULL; + sechk_mod_fn_t run_fn = NULL; + size_t i = 0, j = 0; + int error = 0; + apol_avrule_query_t *avrule_query = NULL; + apol_vector_t *avrule_vector = NULL, *net_domain_vector = NULL; + const qpol_type_t *net_domain = NULL, *tmp_type = NULL; + const char *net_domain_name = NULL, *tgt_name = NULL; + char *perm_name = NULL; + const qpol_avrule_t *rule = NULL; + qpol_iterator_t *iter = NULL; + qpol_policy_t *q = apol_policy_get_qpol(policy); + net_state_t *state = NULL; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + /* if already run return */ + if (mod->result) + return 0; + + res = sechk_result_new(); + if (!res) { + ERR(policy, "%s", strerror(ENOMEM)); + errno = ENOMEM; + return -1; + } + res->test_name = strdup(mod_name); + if (!res->test_name) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_net_access_run_fail; + } + res->item_type = SECHK_ITEM_TYPE; + if (!(res->items = apol_vector_create(sechk_item_free))) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + goto inc_net_access_run_fail; + } + + /* run dependencies */ + for (i = 0; i < apol_vector_get_size(mod->dependencies); i++) { + dep = apol_vector_get_element(mod->dependencies, i); + run_fn = sechk_lib_get_module_function(dep->value, SECHK_MOD_FN_RUN, mod->parent_lib); + run_fn(sechk_lib_get_module(dep->value, mod->parent_lib), policy, NULL); + } + + net_domain_res = sechk_lib_get_module_result("find_net_domains", mod->parent_lib); + if (!net_domain_res) { + error = errno; + ERR(policy, "%s", "Unable to get results for module find_net_domains"); + goto inc_net_access_run_fail; + } + net_domain_vector = (apol_vector_t *) net_domain_res->items; + + avrule_query = apol_avrule_query_create(); + if (!avrule_query) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + apol_avrule_query_set_rules(policy, avrule_query, QPOL_RULE_ALLOW); + + for (i = 0; i < apol_vector_get_size(net_domain_vector); i++) { + tmp_item = apol_vector_get_element(net_domain_vector, i); + net_domain = tmp_item->item; + qpol_type_get_name(q, net_domain, &net_domain_name); + state = net_state_create(); + + /* find any self sock_file perms */ + apol_avrule_query_set_source(policy, avrule_query, net_domain_name, 1); + apol_avrule_query_set_target(policy, avrule_query, net_domain_name, 1); + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "sock_file"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_SOCK_FILE_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_SOCK_FILE_WRITE; + } else if (!strcmp(perm_name, "getattr")) { + state->perms |= PERM_SELF_SOCK_FILE_GETATTR; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any self tcp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "tcp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_TCP_SOC_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_TCP_SOC_WRITE; + } else if (!strcmp(perm_name, "create")) { + state->perms |= PERM_SELF_TCP_SOC_CREATE; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any self udp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "udp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "read")) { + state->perms |= PERM_SELF_UDP_SOC_READ; + } else if (!strcmp(perm_name, "write")) { + state->perms |= PERM_SELF_UDP_SOC_WRITE; + } else if (!strcmp(perm_name, "create")) { + state->perms |= PERM_SELF_UDP_SOC_CREATE; + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any if_t netif perms */ + apol_avrule_query_set_target(policy, avrule_query, NULL, 0); + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "netif"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "tcp_send")) { + state->perms |= PERM_NETIF_TCP_SEND; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_SEND); + } else if (!strcmp(perm_name, "tcp_recv")) { + state->perms |= PERM_NETIF_TCP_RECV; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_TCP_RECV); + } else if (!strcmp(perm_name, "udp_send")) { + state->perms |= PERM_NETIF_UDP_SEND; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_SEND); + } else if (!strcmp(perm_name, "udp_recv")) { + state->perms |= PERM_NETIF_UDP_RECV; + name_perm_vector_add_perm(state->netifs, tgt_name, PERM_NETIF_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any node_t node perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "node"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "tcp_send")) { + state->perms |= PERM_NODE_TCP_SEND; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_SEND); + } else if (!strcmp(perm_name, "tcp_recv")) { + state->perms |= PERM_NODE_TCP_RECV; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_TCP_RECV); + } else if (!strcmp(perm_name, "udp_send")) { + state->perms |= PERM_NODE_UDP_SEND; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_SEND); + } else if (!strcmp(perm_name, "udp_recv")) { + state->perms |= PERM_NODE_UDP_RECV; + name_perm_vector_add_perm(state->nodes, tgt_name, PERM_NODE_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any port_t tcp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "tcp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + /* skip self */ + if (!strcmp(net_domain_name, tgt_name)) + continue; + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "send_msg")) { + state->perms |= PERM_PORT_TCP_SEND; + name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_SEND); + } else if (!strcmp(perm_name, "recv_msg")) { + state->perms |= PERM_PORT_TCP_RECV; + name_perm_vector_add_perm(state->tcpsocs, tgt_name, PERM_PORT_TCP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any port_t udp_socket perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "udp_socket"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + /* skip self */ + if (!strcmp(net_domain_name, tgt_name)) + continue; + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "send_msg")) { + state->perms |= PERM_PORT_UDP_SEND; + name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_SEND); + } else if (!strcmp(perm_name, "recv_msg")) { + state->perms |= PERM_PORT_UDP_RECV; + name_perm_vector_add_perm(state->udpsocs, tgt_name, PERM_PORT_UDP_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* find any assoc_t association perms */ + apol_avrule_query_append_class(policy, avrule_query, NULL); + apol_avrule_query_append_class(policy, avrule_query, "association"); + apol_avrule_get_by_query(policy, avrule_query, &avrule_vector); + for (j = 0; j < apol_vector_get_size(avrule_vector); j++) { + rule = apol_vector_get_element(avrule_vector, j); + qpol_avrule_get_target_type(q, rule, &tmp_type); + qpol_type_get_name(q, tmp_type, &tgt_name); + qpol_avrule_get_perm_iter(q, rule, &iter); + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + qpol_iterator_get_item(iter, (void **)(&perm_name)); + if (!strcmp(perm_name, "sendto")) { + state->perms |= PERM_ASSOC_SEND; + name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_SEND); + } else if (!strcmp(perm_name, "recvfrom")) { + state->perms |= PERM_ASSOC_RECV; + name_perm_vector_add_perm(state->assocs, tgt_name, PERM_ASSOC_RECV); + } /* no general case else */ + free(perm_name); + perm_name = NULL; + } + qpol_iterator_destroy(&iter); + } + apol_vector_destroy(&avrule_vector); + + /* if has tcp perms check for missing ones */ + if ((state->perms & ((~(COMMON_ACCESS_SET)) & (TCP_FULL_PERM_SET))) && + ((state->perms & RULE_TCP_SOCK_FILE) != RULE_TCP_SOCK_FILE || + (state->perms & RULE_TCP_SELF_SOC) != RULE_TCP_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_TCP_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_TCP_NODE) || + name_perm_vector_has_incomplete_perms(state->tcpsocs, RULE_TCP_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_TCP_ASSOC))) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_tcp_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has udp send perms check for missing perms */ + if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_SEND_PERM_SET))) && + ((state->perms & RULE_UDPs_SOCK_FILE) != RULE_UDPs_SOCK_FILE || + (state->perms & RULE_UDPs_SELF_SOC) != RULE_UDPs_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPs_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPs_NODE) || + name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPs_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPs_ASSOC))) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_udp_send_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has udp reveive perms check for missing perms */ + if ((state->perms & ((~(COMMON_ACCESS_SET | PERM_SELF_UDP_SOC_CREATE)) & (UDP_RECV_PERM_SET))) && + ((state->perms & RULE_UDPr_SOCK_FILE) != RULE_UDPr_SOCK_FILE || + (state->perms & RULE_UDPr_SELF_SOC) != RULE_UDPr_SELF_SOC || + name_perm_vector_has_incomplete_perms(state->netifs, RULE_UDPr_NETIF) || + name_perm_vector_has_incomplete_perms(state->nodes, RULE_UDPr_NODE) || + name_perm_vector_has_incomplete_perms(state->udpsocs, RULE_UDPr_PORT) || + name_perm_vector_has_incomplete_perms(state->assocs, RULE_UDPr_ASSOC))) { + if (!item) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_udp_recv_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + /* if has only common access perms report that */ + if (!(state->perms & (~(COMMON_ACCESS_SET)))) { + item = sechk_item_new(NULL); + if (!item) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item->item = (void *)net_domain; + item->test_result = 1; + item->proof = apol_vector_create(sechk_proof_free); + if (!item->proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = sechk_proof_new(NULL); + if (!proof) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof->type = SECHK_ITEM_NONE; + proof->elem = NULL; + proof->text = generate_common_only_proof_text(net_domain_name, state); + //TODO check that it succeeded + if (apol_vector_append(item->proof, (void *)proof)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + proof = NULL; + } + + if (item) { + if (apol_vector_append(res->items, (void *)item)) { + error = errno; + ERR(policy, "%s", strerror(error)); + goto inc_net_access_run_fail; + } + item = NULL; + } + net_state_destroy(&state); + } + mod->result = res; + + if (apol_vector_get_size(res->items)) + return 1; + return 0; + + inc_net_access_run_fail: + apol_avrule_query_destroy(&avrule_query); + apol_vector_destroy(&avrule_vector); + qpol_iterator_destroy(&iter); + free(perm_name); + net_state_destroy(&state); + sechk_item_free(item); + sechk_proof_free(proof); + sechk_result_destroy(&res); + errno = error; + return -1; +} + +/* The print function generates the text and prints the + * results to stdout. */ +int inc_net_access_print(sechk_module_t * mod, apol_policy_t * policy, void *arg __attribute__ ((unused))) +{ + unsigned char outformat = 0x00; + sechk_item_t *item = NULL; + sechk_proof_t *proof = NULL; + size_t i = 0, j = 0, k = 0, l = 0, num_items; + const qpol_type_t *type; + qpol_policy_t *q = apol_policy_get_qpol(policy); + const char *type_name; + + if (!mod || !policy) { + ERR(policy, "%s", "Invalid parameters"); + errno = EINVAL; + return -1; + } + if (strcmp(mod_name, mod->name)) { + ERR(policy, "Wrong module (%s)", mod->name); + errno = EINVAL; + return -1; + } + + outformat = mod->outputformat; + num_items = apol_vector_get_size(mod->result->items); + + if (!mod->result) { + ERR(policy, "%s", "Module has not been run"); + errno = EINVAL; + return -1; + } + + if (!outformat || (outformat & SECHK_OUT_QUIET)) + return 0; /* not an error - no output is requested */ + + if (outformat & SECHK_OUT_STATS) { + printf("Found %i network domains with insufficient permissions.\n", num_items); + } + + /* Print current permissions then the permissions that are missing */ + if (outformat & SECHK_OUT_PROOF) { + printf("\n"); + for (k = 0; k < num_items; k++) { + item = apol_vector_get_element(mod->result->items, k); + if (item) { + type = item->item; + qpol_type_get_name(q, type, &type_name); + printf("%s\n", (char *)type_name); + for (l = 0; l < apol_vector_get_size(item->proof); l++) { + proof = apol_vector_get_element(item->proof, l); + if (proof) + printf("\t%s\n", proof->text); + } + } + } + printf("\n"); + } + + i = 0; + if (outformat & SECHK_OUT_LIST) { + printf("\n"); + for (i = 0; i < num_items; i++) { + j++; + item = apol_vector_get_element(mod->result->items, i); + type = item->item; + qpol_type_get_name(q, type, &type_name); + j %= 4; + printf("%s%s", type_name, (char *)((j && i != num_items - 1) ? ", " : "\n")); + } + printf("\n"); + } + + return 0; +} -- cgit