ADD_PLUGIN([kernel-pfkey], [c charon starter nm cmd])
ADD_PLUGIN([kernel-pfroute], [c charon starter nm cmd])
ADD_PLUGIN([kernel-netlink], [c charon starter nm cmd])
+ADD_PLUGIN([selinux], [c charon starter nm cmd])
ADD_PLUGIN([resolve], [c charon cmd])
ADD_PLUGIN([save-keys], [c])
ADD_PLUGIN([socket-default], [c charon nm cmd])
AM_CONDITIONAL(USE_ATTR, test x$attr = xtrue)
AM_CONDITIONAL(USE_ATTR_SQL, test x$attr_sql = xtrue)
AM_CONDITIONAL(USE_COUNTERS, test x$counters = xtrue)
+AM_CONDITIONAL(USE_SELINUX, test x$selinux = xtrue)
# other options
# ---------------
src/libcharon/plugins/resolve/Makefile
src/libcharon/plugins/attr/Makefile
src/libcharon/plugins/attr_sql/Makefile
+ src/libcharon/plugins/selinux/Makefile
src/libcharon/tests/Makefile
src/libtpmtss/Makefile
src/libtpmtss/plugins/tpm/Makefile
endif
endif
+if USE_SELINUX
+ SUBDIRS += plugins/selinux
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/selinux/libstrongswan-selinux.la
+endif
+endif
+
if USE_ATTR_SQL
SUBDIRS += plugins/attr_sql
if MONOLITHIC
--- /dev/null
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-selinux.la
+else
+plugin_LTLIBRARIES = libstrongswan-selinux.la
+endif
+
+libstrongswan_selinux_la_SOURCES = \
+ selinux_plugin.h selinux_plugin.c \
+ selinux_listener.h selinux_listener.c
+
+libstrongswan_selinux_la_LDFLAGS = -module -avoid-version
--- /dev/null
+/*
+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "selinux_listener.h"
+
+#include <daemon.h>
+#include <collections/array.h>
+#include <collections/hashtable.h>
+
+typedef struct private_selinux_listener_t private_selinux_listener_t;
+
+/**
+ * Private data.
+ */
+struct private_selinux_listener_t {
+
+ /**
+ * Public interface.
+ */
+ selinux_listener_t public;
+
+ /**
+ * IKE_SAs with attached trap policies, ike_sa_id_t => entry_t.
+ */
+ hashtable_t *sas;
+};
+
+/**
+ * Entry to keep track of trap policies.
+ */
+typedef struct {
+
+ /**
+ * IKE_SA ID.
+ */
+ ike_sa_id_t *id;
+
+ /**
+ * Installed trap policies.
+ */
+ array_t *traps;
+
+} entry_t;
+
+/**
+ * Destroy the given entry.
+ */
+static void destroy_entry(entry_t *entry)
+{
+ entry->id->destroy(entry->id);
+ array_destroy(entry->traps);
+ free(entry);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(const void *key)
+{
+ ike_sa_id_t *id = (ike_sa_id_t*)key;
+ uint64_t spi_i = id->get_initiator_spi(id),
+ spi_r = id->get_responder_spi(id);
+ return chunk_hash_inc(chunk_from_thing(spi_i),
+ chunk_hash(chunk_from_thing(spi_r)));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(const void *a_pub, const void *b)
+{
+ ike_sa_id_t *a = (ike_sa_id_t*)a_pub;
+ return a->equals(a, (ike_sa_id_t*)b);
+}
+
+/**
+ * Install a trap policy for the generic SELinux label.
+ */
+static bool install_generic_trap(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ linked_list_t *local, *remote;
+ sec_label_t *label;
+ bool success;
+
+ label = child_sa->get_label(child_sa);
+ DBG1(DBG_IKE, "installing trap %s{%d} with generic security label '%s'",
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
+ label->get_string(label));
+
+ local = ike_sa_get_dynamic_hosts(ike_sa, TRUE);
+ remote = ike_sa_get_dynamic_hosts(ike_sa, FALSE);
+ success = charon->traps->install_external(charon->traps,
+ ike_sa->get_peer_cfg(ike_sa),
+ child_sa, local, remote);
+ local->destroy(local);
+ remote->destroy(remote);
+ return success;
+}
+
+METHOD(listener_t, ike_updown, bool,
+ private_selinux_listener_t *this, ike_sa_t *ike_sa, bool up)
+{
+ enumerator_t *enumerator;
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
+ child_sa_t *child_sa;
+ entry_t *entry;
+
+ if (up)
+ {
+ child_sa_create_t child = {
+ .if_id_in_def = ike_sa->get_if_id(ike_sa, TRUE),
+ .if_id_out_def = ike_sa->get_if_id(ike_sa, FALSE),
+ };
+
+ INIT(entry,
+ .id = ike_sa->get_id(ike_sa),
+ );
+ entry->id = entry->id->clone(entry->id);
+
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+ while (enumerator->enumerate(enumerator, &child_cfg))
+ {
+ if (child_cfg->get_label(child_cfg) &&
+ child_cfg->get_label_mode(child_cfg) == SEC_LABEL_MODE_SELINUX)
+ {
+ child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
+ ike_sa->get_other_host(ike_sa),
+ child_cfg, &child);
+ if (install_generic_trap(ike_sa, child_sa))
+ {
+ array_insert_create(&entry->traps, ARRAY_TAIL, child_sa);
+ }
+ else
+ {
+ child_sa->destroy(child_sa);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (array_count(entry->traps))
+ {
+ this->sas->put(this->sas, entry->id, entry);
+ }
+ else
+ {
+ destroy_entry(entry);
+ }
+ }
+ else
+ {
+ entry = this->sas->remove(this->sas, ike_sa->get_id(ike_sa));
+ if (entry)
+ {
+ while (array_remove(entry->traps, ARRAY_TAIL, &child_sa))
+ {
+ sec_label_t *label = child_sa->get_label(child_sa);
+
+ DBG1(DBG_IKE, "uninstalling trap %s{%d} with generic security "
+ "label '%s'", child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa),
+ label->get_string(label));
+ charon->traps->remove_external(charon->traps, child_sa);
+ child_sa->destroy(child_sa);
+ }
+ destroy_entry(entry);
+ }
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_rekey, bool,
+ private_selinux_listener_t *this, ike_sa_t *old, ike_sa_t *new)
+{
+ entry_t *entry;
+
+ entry = this->sas->remove(this->sas, old->get_id(old));
+ if (entry)
+ {
+ entry->id->destroy(entry->id);
+ entry->id = new->get_id(new);
+ entry->id = entry->id->clone(entry->id);
+ this->sas->put(this->sas, entry->id, entry);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, ike_update, bool,
+ private_selinux_listener_t *this, ike_sa_t *ike_sa,
+ host_t *local, host_t *remote)
+{
+ entry_t *entry;
+ child_sa_t *child_sa;
+ linked_list_t *vips;
+ int i;
+
+ entry = this->sas->get(this->sas, ike_sa->get_id(ike_sa));
+ if (entry)
+ {
+ vips = linked_list_create_from_enumerator(
+ ike_sa->create_virtual_ip_enumerator(ike_sa, local));
+ for (i = 0; i < array_count(entry->traps); i++)
+ {
+ array_get(entry->traps, i, &child_sa);
+ child_sa->update(child_sa, local, remote, vips,
+ ike_sa->has_condition(ike_sa, COND_NAT_ANY));
+ }
+ vips->destroy(vips);
+ }
+ return TRUE;
+}
+
+METHOD(selinux_listener_t, destroy, void,
+ private_selinux_listener_t *this)
+{
+ this->sas->destroy(this->sas);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+selinux_listener_t *selinux_listener_create()
+{
+ private_selinux_listener_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_updown = _ike_updown,
+ .ike_rekey = _ike_rekey,
+ .ike_update = _ike_update,
+ },
+ .destroy = _destroy,
+ },
+ .sas = hashtable_create(hash, equals, 32),
+ );
+
+ return &this->public;
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup selinux_listener selinux_listener
+ * @{ @ingroup selinux
+ */
+
+#ifndef SELINUX_LISTENER_H_
+#define SELINUX_LISTENER_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct selinux_listener_t selinux_listener_t;
+
+/**
+ * Listener to manage trap policies for generic SELinux labels.
+ */
+struct selinux_listener_t {
+
+ /**
+ * Implements listener_t interface.
+ */
+ listener_t listener;
+
+ /**
+ * Destroy a selinux_listener_t.
+ */
+ void (*destroy)(selinux_listener_t *this);
+};
+
+/**
+ * Create a listener instance.
+ */
+selinux_listener_t *selinux_listener_create();
+
+#endif /** SELINUX_LISTENER_H_ @}*/
--- /dev/null
+/*
+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "selinux_plugin.h"
+#include "selinux_listener.h"
+
+#include <daemon.h>
+
+typedef struct private_selinux_plugin_t private_selinux_plugin_t;
+
+/**
+ * Private data
+ */
+struct private_selinux_plugin_t {
+
+ /**
+ * Public interface
+ */
+ selinux_plugin_t public;
+
+ /**
+ * Listener
+ */
+ selinux_listener_t *listener;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_selinux_plugin_t *this)
+{
+ return "selinux";
+}
+
+/**
+ * Register handler
+ */
+static bool plugin_cb(private_selinux_plugin_t *this,
+ plugin_feature_t *feature, bool reg, void *cb_data)
+{
+ if (reg)
+ {
+ charon->bus->add_listener(charon->bus, &this->listener->listener);
+ }
+ else
+ {
+ charon->bus->remove_listener(charon->bus, &this->listener->listener);
+ }
+ return TRUE;
+}
+
+METHOD(plugin_t, get_features, int,
+ private_selinux_plugin_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
+ PLUGIN_PROVIDE(CUSTOM, "selinux"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+ private_selinux_plugin_t *this)
+{
+ this->listener->destroy(this->listener);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+plugin_t *selinux_plugin_create()
+{
+ private_selinux_plugin_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ .listener = selinux_listener_create(),
+ );
+
+ return &this->public.plugin;
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup selinux selinux
+ * @ingroup cplugins
+ *
+ * @defgroup selinux_plugin selinux_plugin
+ * @{ @ingroup selinux
+ */
+
+#ifndef SELINUX_PLUGIN_H_
+#define SELINUX_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct selinux_plugin_t selinux_plugin_t;
+
+/**
+ * Plugin managing trap policies with generic SELinux labels.
+ */
+struct selinux_plugin_t {
+
+ /**
+ * Implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+#endif /** SELINUX_PLUGIN_H_ @}*/