summaryrefslogtreecommitdiffstats
path: root/libapol/src/netcon-query.c
diff options
context:
space:
mode:
Diffstat (limited to 'libapol/src/netcon-query.c')
-rw-r--r--libapol/src/netcon-query.c592
1 files changed, 592 insertions, 0 deletions
diff --git a/libapol/src/netcon-query.c b/libapol/src/netcon-query.c
new file mode 100644
index 0000000..7faf0de
--- /dev/null
+++ b/libapol/src/netcon-query.c
@@ -0,0 +1,592 @@
+/**
+ * @file
+ *
+ * Provides a way for setools to make queries about portcons,
+ * netifcons, and nodecons within a policy. The caller obtains a
+ * query object, fills in its parameters, and then runs the query; it
+ * obtains a vector of results. Searches are conjunctive -- all
+ * fields of the search query must match for a datum to be added to
+ * the results query.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policy-query-internal.h"
+#include <apol/render.h>
+
+#include <errno.h>
+#include <string.h>
+
+struct apol_portcon_query
+{
+ int proto;
+ int low, high;
+ apol_context_t *context;
+ unsigned int flags;
+};
+
+struct apol_netifcon_query
+{
+ char *dev;
+ apol_context_t *if_context, *msg_context;
+ unsigned int if_flags, msg_flags;
+};
+
+struct apol_nodecon_query
+{
+ char proto, addr_proto, mask_proto;
+ uint32_t addr[4], mask[4];
+ apol_context_t *context;
+ unsigned int flags;
+};
+
+/******************** portcon queries ********************/
+
+int apol_portcon_get_by_query(const apol_policy_t * p, const apol_portcon_query_t * po, apol_vector_t ** v)
+{
+ qpol_iterator_t *iter;
+ int retval = -1, retval2;
+ *v = NULL;
+ if (qpol_policy_get_portcon_iter(p->p, &iter) < 0) {
+ return -1;
+ }
+ if ((*v = apol_vector_create(NULL)) == NULL) {
+ ERR(p, "%s", strerror(errno));
+ goto cleanup;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ qpol_portcon_t *portcon;
+ if (qpol_iterator_get_item(iter, (void **)&portcon) < 0) {
+ goto cleanup;
+ }
+ if (po != NULL) {
+ uint16_t low, high;
+ uint8_t proto;
+ const qpol_context_t *context;
+ if (qpol_portcon_get_low_port(p->p,
+ portcon, &low) < 0 ||
+ qpol_portcon_get_high_port(p->p,
+ portcon, &high) < 0 ||
+ qpol_portcon_get_protocol(p->p,
+ portcon, &proto) < 0 || qpol_portcon_get_context(p->p, portcon, &context) < 0)
+ {
+ goto cleanup;
+ }
+ if ((po->low >= 0 && ((uint16_t) po->low) != low) ||
+ (po->high >= 0 && ((uint16_t) po->high) != high) || (po->proto >= 0 && ((uint8_t) po->proto) != proto))
+ {
+ continue;
+ }
+ retval2 = apol_compare_context(p, context, po->context, po->flags);
+ if (retval2 < 0) {
+ goto cleanup;
+ } else if (retval2 == 0) {
+ continue;
+ }
+ }
+ if (apol_vector_append(*v, portcon)) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ if (retval != 0) {
+ apol_vector_destroy(v);
+ }
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+apol_portcon_query_t *apol_portcon_query_create(void)
+{
+ apol_portcon_query_t *po = calloc(1, sizeof(*po));
+ if (po == NULL) {
+ return NULL;
+ }
+ po->proto = po->low = po->high = -1;
+ return po;
+}
+
+void apol_portcon_query_destroy(apol_portcon_query_t ** po)
+{
+ if (*po != NULL) {
+ apol_context_destroy(&((*po)->context));
+ free(*po);
+ *po = NULL;
+ }
+}
+
+int apol_portcon_query_set_protocol(const apol_policy_t * p __attribute__ ((unused)), apol_portcon_query_t * po, int proto)
+{
+ po->proto = proto;
+ return 0;
+}
+
+/**
+ * @deprecated Use apol_portcon_query_set_protocol() instead.
+ */
+int apol_portcon_query_set_proto(apol_policy_t * p, apol_portcon_query_t * po, int proto)
+{
+ return apol_portcon_query_set_protocol(p, po, proto);
+}
+int apol_portcon_query_set_proto(apol_policy_t * p, apol_portcon_query_t * po, int proto) __attribute__ ((deprecated));
+
+int apol_portcon_query_set_low(const apol_policy_t * p __attribute__ ((unused)), apol_portcon_query_t * po, int low)
+{
+ po->low = low;
+ return 0;
+}
+
+int apol_portcon_query_set_high(const apol_policy_t * p __attribute__ ((unused)), apol_portcon_query_t * po, int high)
+{
+ po->high = high;
+ return 0;
+}
+
+int apol_portcon_query_set_context(const apol_policy_t * p __attribute__ ((unused)),
+ apol_portcon_query_t * po, apol_context_t * context, unsigned int range_match)
+{
+ if (po->context != NULL) {
+ apol_context_destroy(&po->context);
+ }
+ po->context = context;
+ po->flags = (po->flags & ~APOL_QUERY_FLAGS) | range_match;
+ return 0;
+}
+
+char *apol_portcon_render(const apol_policy_t * p, const qpol_portcon_t * portcon)
+{
+ char *line = NULL, *retval = NULL;
+ char *buff = NULL;
+ const char *proto_str = NULL;
+ char *context_str = NULL;
+ const qpol_context_t *ctxt = NULL;
+ uint16_t low_port, high_port;
+ uint8_t proto;
+
+ const size_t bufflen = 50; /* arbitrary size big enough to hold port no. */
+ if (!portcon || !p)
+ goto cleanup;
+
+ buff = (char *)calloc(bufflen + 1, sizeof(char));
+ if (!buff) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+
+ if (qpol_portcon_get_protocol(p->p, portcon, &proto))
+ goto cleanup;
+
+ if ((proto_str = apol_protocol_to_str(proto)) == NULL) {
+ ERR(p, "%s", "Could not get protocol string.");
+ goto cleanup;
+ }
+ if (qpol_portcon_get_low_port(p->p, portcon, &low_port))
+ goto cleanup;
+ if (qpol_portcon_get_high_port(p->p, portcon, &high_port))
+ goto cleanup;
+ if (low_port == high_port)
+ snprintf(buff, bufflen, "%d", low_port);
+ else
+ snprintf(buff, bufflen, "%d-%d", low_port, high_port);
+
+ if (qpol_portcon_get_context(p->p, portcon, &ctxt))
+ goto cleanup;
+ context_str = apol_qpol_context_render(p, ctxt);
+ if (!context_str)
+ goto cleanup;
+
+ line = (char *)calloc(4 + strlen("portcon") + strlen(proto_str) + strlen(buff) + strlen(context_str), sizeof(char));
+ if (!line) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+
+ sprintf(line, "portcon %s %s %s", proto_str, buff, context_str);
+
+ retval = line;
+ cleanup:
+ free(buff);
+ free(context_str);
+ if (retval != line) {
+ free(line);
+ }
+ return retval;
+}
+
+/******************** netifcon queries ********************/
+
+int apol_netifcon_get_by_query(const apol_policy_t * p, const apol_netifcon_query_t * n, apol_vector_t ** v)
+{
+ qpol_iterator_t *iter;
+ int retval = -1, retval2;
+ *v = NULL;
+ if (qpol_policy_get_netifcon_iter(p->p, &iter) < 0) {
+ return -1;
+ }
+ if ((*v = apol_vector_create(NULL)) == NULL) {
+ ERR(p, "%s", strerror(errno));
+ goto cleanup;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ const qpol_netifcon_t *netifcon;
+ if (qpol_iterator_get_item(iter, (void **)&netifcon) < 0) {
+ goto cleanup;
+ }
+ if (n != NULL) {
+ const char *name;
+ const qpol_context_t *ifcon, *msgcon;
+ if (qpol_netifcon_get_name(p->p, netifcon, &name) < 0 ||
+ qpol_netifcon_get_if_con(p->p, netifcon, &ifcon) < 0 ||
+ qpol_netifcon_get_msg_con(p->p, netifcon, &msgcon) < 0) {
+ goto cleanup;
+ }
+ retval2 = apol_compare(p, name, n->dev, 0, NULL);
+ if (retval2 < 0) {
+ goto cleanup;
+ } else if (retval2 == 0) {
+ continue;
+ }
+ retval2 = apol_compare_context(p, ifcon, n->if_context, n->if_flags);
+ if (retval2 < 0) {
+ goto cleanup;
+ } else if (retval2 == 0) {
+ continue;
+ }
+ retval2 = apol_compare_context(p, msgcon, n->msg_context, n->msg_flags);
+ if (retval2 < 0) {
+ goto cleanup;
+ } else if (retval2 == 0) {
+ continue;
+ }
+ }
+ if (apol_vector_append(*v, (void *)netifcon)) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ if (retval != 0) {
+ apol_vector_destroy(v);
+ }
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+apol_netifcon_query_t *apol_netifcon_query_create(void)
+{
+ return calloc(1, sizeof(apol_netifcon_query_t));
+}
+
+void apol_netifcon_query_destroy(apol_netifcon_query_t ** n)
+{
+ if (*n != NULL) {
+ free((*n)->dev);
+ apol_context_destroy(&((*n)->if_context));
+ apol_context_destroy(&((*n)->msg_context));
+ free(*n);
+ *n = NULL;
+ }
+}
+
+int apol_netifcon_query_set_device(const apol_policy_t * p, apol_netifcon_query_t * n, const char *dev)
+{
+ return apol_query_set(p, &n->dev, NULL, dev);
+}
+
+int apol_netifcon_query_set_if_context(const apol_policy_t * p __attribute__ ((unused)),
+ apol_netifcon_query_t * n, apol_context_t * context, unsigned int range_match)
+{
+ if (n->if_context != NULL) {
+ apol_context_destroy(&n->if_context);
+ }
+ n->if_context = context;
+ n->if_flags = (n->if_flags & ~APOL_QUERY_FLAGS) | range_match;
+ return 0;
+}
+
+int apol_netifcon_query_set_msg_context(const apol_policy_t * p __attribute__ ((unused)),
+ apol_netifcon_query_t * n, apol_context_t * context, unsigned int range_match)
+{
+ if (n->msg_context != NULL) {
+ apol_context_destroy(&n->msg_context);
+ }
+ n->msg_context = context;
+ n->msg_flags = (n->msg_flags & ~APOL_QUERY_FLAGS) | range_match;
+ return 0;
+}
+
+char *apol_netifcon_render(const apol_policy_t * p, const qpol_netifcon_t * netifcon)
+{
+ char *line = NULL, *retval = NULL;
+ char *devcon_str = NULL;
+ char *pktcon_str = NULL;
+ const char *iface_str = NULL;
+ const qpol_context_t *ctxt = NULL;
+
+ if (!netifcon || !p)
+ goto cleanup;
+
+ if (qpol_netifcon_get_if_con(p->p, netifcon, &ctxt))
+ goto cleanup;
+ devcon_str = apol_qpol_context_render(p, ctxt);
+ if (!devcon_str)
+ goto cleanup;
+
+ if (qpol_netifcon_get_msg_con(p->p, netifcon, &ctxt))
+ goto cleanup;
+ pktcon_str = apol_qpol_context_render(p, ctxt);
+ if (!pktcon_str) {
+ goto cleanup;
+ }
+
+ if (qpol_netifcon_get_name(p->p, netifcon, &iface_str))
+ return NULL;
+ line = (char *)calloc(4 + strlen(iface_str) + strlen(devcon_str) + strlen(pktcon_str) + strlen("netifcon"), sizeof(char));
+ if (!line) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ sprintf(line, "netifcon %s %s %s", iface_str, devcon_str, pktcon_str);
+
+ retval = line;
+ cleanup:
+ free(devcon_str);
+ free(pktcon_str);
+ return retval;
+}
+
+/******************** nodecon queries ********************/
+
+int apol_nodecon_get_by_query(const apol_policy_t * p, const apol_nodecon_query_t * n, apol_vector_t ** v)
+{
+ qpol_iterator_t *iter;
+ int retval = -1, retval2;
+ qpol_nodecon_t *nodecon = NULL;
+ *v = NULL;
+ if (qpol_policy_get_nodecon_iter(p->p, &iter) < 0) {
+ return -1;
+ }
+ if ((*v = apol_vector_create(free)) == NULL) {
+ ERR(p, "%s", strerror(errno));
+ goto cleanup;
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&nodecon) < 0) {
+ goto cleanup;
+ }
+ if (n != NULL) {
+ unsigned char proto, proto_a, proto_m;
+ uint32_t *addr, *mask;
+ const qpol_context_t *con;
+ if (qpol_nodecon_get_protocol(p->p, nodecon, &proto) < 0 ||
+ qpol_nodecon_get_addr(p->p, nodecon, &addr, &proto_a) < 0 ||
+ qpol_nodecon_get_mask(p->p, nodecon, &mask, &proto_m) < 0 ||
+ qpol_nodecon_get_context(p->p, nodecon, &con) < 0) {
+ goto cleanup;
+ }
+ if (n->proto >= 0 && n->proto != proto) {
+ free(nodecon);
+ continue;
+ }
+ if (n->addr_proto >= 0 &&
+ (n->addr_proto != proto_a ||
+ (proto_a == QPOL_IPV4 && memcmp(n->addr, addr, 1 * sizeof(uint32_t)) != 0) ||
+ (proto_a == QPOL_IPV6 && memcmp(n->addr, addr, 4 * sizeof(uint32_t)) != 0))) {
+ free(nodecon);
+ continue;
+ }
+ if (n->mask_proto >= 0 &&
+ (n->mask_proto != proto_m ||
+ (proto_m == QPOL_IPV4 && memcmp(n->mask, mask, 1 * sizeof(uint32_t)) != 0) ||
+ (proto_m == QPOL_IPV6 && memcmp(n->mask, mask, 4 * sizeof(uint32_t)) != 0))) {
+ free(nodecon);
+ continue;
+ }
+ retval2 = apol_compare_context(p, con, n->context, n->flags);
+ if (retval2 < 0) {
+ goto cleanup;
+ } else if (retval2 == 0) {
+ free(nodecon);
+ continue;
+ }
+ }
+ if (apol_vector_append(*v, nodecon)) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ if (retval != 0) {
+ apol_vector_destroy(v);
+ free(nodecon);
+ }
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+apol_nodecon_query_t *apol_nodecon_query_create(void)
+{
+ apol_nodecon_query_t *n = calloc(1, sizeof(apol_nodecon_query_t));
+ if (n != NULL) {
+ n->proto = n->addr_proto = n->mask_proto = -1;
+ }
+ return n;
+}
+
+void apol_nodecon_query_destroy(apol_nodecon_query_t ** n)
+{
+ if (*n != NULL) {
+ apol_context_destroy(&((*n)->context));
+ free(*n);
+ *n = NULL;
+ }
+}
+
+int apol_nodecon_query_set_protocol(const apol_policy_t * p, apol_nodecon_query_t * n, int proto)
+{
+ if (proto == QPOL_IPV4 || proto == QPOL_IPV6) {
+ n->proto = (char)proto;
+ } else if (proto < 0) {
+ n->proto = -1;
+ } else {
+ ERR(p, "Invalid protocol value %d.", proto);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * @deprecated Use apol_nodecon_query_set_protocol() instead.
+ */
+int apol_nodecon_query_set_proto(apol_policy_t * p, apol_nodecon_query_t * n, int proto)
+{
+ return apol_nodecon_query_set_protocol(p, n, proto);
+}
+int apol_nodecon_query_set_proto(apol_policy_t * p, apol_nodecon_query_t * n, int proto) __attribute__ ((deprecated));
+
+int apol_nodecon_query_set_addr(const apol_policy_t * p, apol_nodecon_query_t * n, uint32_t * addr, int proto)
+{
+ if (addr == NULL) {
+ n->addr_proto = -1;
+ } else {
+ if (proto == QPOL_IPV4) {
+ memcpy(n->addr, addr, 1 * sizeof(uint32_t));
+ } else if (proto == QPOL_IPV6) {
+ memcpy(n->addr, addr, 4 * sizeof(uint32_t));
+ } else {
+ ERR(p, "Invalid protocol value %d.", proto);
+ return -1;
+ }
+ n->addr_proto = (char)proto;
+ }
+ return 0;
+}
+
+int apol_nodecon_query_set_mask(const apol_policy_t * p, apol_nodecon_query_t * n, uint32_t * mask, int proto)
+{
+ if (mask == NULL) {
+ n->mask_proto = -1;
+ } else {
+ if (proto == QPOL_IPV4) {
+ memcpy(n->mask, mask, 1 * sizeof(uint32_t));
+ } else if (proto == QPOL_IPV6) {
+ memcpy(n->mask, mask, 4 * sizeof(uint32_t));
+ } else {
+ ERR(p, "Invalid protocol value %d.", proto);
+ return -1;
+ }
+ n->mask_proto = (char)proto;
+ }
+ return 0;
+}
+
+int apol_nodecon_query_set_context(const apol_policy_t * p __attribute__ ((unused)),
+ apol_nodecon_query_t * n, apol_context_t * context, unsigned int range_match)
+{
+ if (n->context != NULL) {
+ apol_context_destroy(&n->context);
+ }
+ n->context = context;
+ n->flags = (n->flags & ~APOL_QUERY_FLAGS) | range_match;
+ return 0;
+}
+
+char *apol_nodecon_render(const apol_policy_t * p, const qpol_nodecon_t * nodecon)
+{
+ char *line = NULL, *retval = NULL;
+ char *context_str = NULL;
+ char *addr_str = NULL;
+ char *mask_str = NULL;
+ const qpol_context_t *ctxt = NULL;
+ unsigned char protocol, addr_proto, mask_proto;
+ uint32_t *addr = NULL, *mask = NULL;
+
+ if (!nodecon || !p)
+ goto cleanup;
+
+ if (qpol_nodecon_get_protocol(p->p, nodecon, &protocol))
+ goto cleanup;
+ if (qpol_nodecon_get_addr(p->p, nodecon, &addr, &addr_proto))
+ goto cleanup;
+ if (qpol_nodecon_get_mask(p->p, nodecon, &mask, &mask_proto))
+ goto cleanup;
+ switch (protocol) {
+ case QPOL_IPV4:
+ if ((addr_str = apol_ipv4_addr_render(p, addr)) == NULL || (mask_str = apol_ipv4_addr_render(p, mask)) == NULL) {
+ goto cleanup;
+ }
+ break;
+ case QPOL_IPV6:
+ if ((addr_str = apol_ipv6_addr_render(p, addr)) == NULL || (mask_str = apol_ipv6_addr_render(p, mask)) == NULL) {
+ goto cleanup;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (qpol_nodecon_get_context(p->p, nodecon, &ctxt))
+ goto cleanup;
+ context_str = apol_qpol_context_render(p, ctxt);
+ if (!context_str)
+ goto cleanup;
+
+ line = (char *)calloc(4 + strlen("nodecon") + strlen(addr_str) + strlen(mask_str) + strlen(context_str), sizeof(char));
+ if (!line) {
+ ERR(p, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+
+ sprintf(line, "nodecon %s %s %s", addr_str, mask_str, context_str);
+
+ retval = line;
+ cleanup:
+ free(addr_str);
+ free(mask_str);
+ free(context_str);
+ return retval;
+}