Implemented a in-memory peer identity whitelist plugin
authorMartin Willi <martin@revosec.ch>
Thu, 3 Feb 2011 12:38:13 +0000 (13:38 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 28 Feb 2011 14:00:46 +0000 (15:00 +0100)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/whitelist/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/whitelist/whitelist_listener.c [new file with mode: 0644]
src/libcharon/plugins/whitelist/whitelist_listener.h [new file with mode: 0644]
src/libcharon/plugins/whitelist/whitelist_plugin.c [new file with mode: 0644]
src/libcharon/plugins/whitelist/whitelist_plugin.h [new file with mode: 0644]

index ca7f78e..3948362 100644 (file)
@@ -166,6 +166,7 @@ ARG_ENABL_SET([android],        [enable Android specific plugin.])
 ARG_ENABL_SET([maemo],          [enable Maemo specific plugin.])
 ARG_ENABL_SET([nm],             [enable NetworkManager plugin.])
 ARG_ENABL_SET([ha],             [enable high availability cluster plugin.])
+ARG_ENABL_SET([whitelist],      [enable peer identity whitelisting plugin.])
 ARG_ENABL_SET([led],            [enable plugin to control LEDs on IKEv2 activity using the Linux kernel LED subsystem.])
 ARG_ENABL_SET([vstr],           [enforce using the Vstr string library to replace glibc-like printf hooks.])
 ARG_ENABL_SET([monolithic],     [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
@@ -774,6 +775,7 @@ ADD_PLUGIN([nm],                   [c libcharon])
 ADD_PLUGIN([dhcp],                 [c libcharon])
 ADD_PLUGIN([android],              [c libcharon])
 ADD_PLUGIN([ha],                   [c libcharon])
+ADD_PLUGIN([whitelist],            [c libcharon])
 ADD_PLUGIN([led],                  [c libcharon])
 ADD_PLUGIN([maemo],                [c libcharon])
 ADD_PLUGIN([uci],                  [c libcharon])
@@ -853,6 +855,7 @@ AM_CONDITIONAL(USE_DHCP, test x$dhcp = xtrue)
 AM_CONDITIONAL(USE_UNIT_TESTS, test x$unit_tests = xtrue)
 AM_CONDITIONAL(USE_LOAD_TESTER, test x$load_tester = xtrue)
 AM_CONDITIONAL(USE_HA, test x$ha = xtrue)
+AM_CONDITIONAL(USE_WHITELIST, test x$whitelist = xtrue)
 AM_CONDITIONAL(USE_LED, test x$led = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM, test x$eap_sim = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM_FILE, test x$eap_sim_file = xtrue)
@@ -1034,6 +1037,7 @@ AC_OUTPUT(
        src/libcharon/plugins/addrblock/Makefile
        src/libcharon/plugins/uci/Makefile
        src/libcharon/plugins/ha/Makefile
+       src/libcharon/plugins/whitelist/Makefile
        src/libcharon/plugins/led/Makefile
        src/libcharon/plugins/android/Makefile
        src/libcharon/plugins/maemo/Makefile
index 1e78c9d..7ae04f7 100644 (file)
@@ -403,6 +403,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_WHITELIST
+  SUBDIRS += plugins/whitelist
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/whitelist/libstrongswan-whitelist.la
+endif
+endif
+
 if USE_LED
   SUBDIRS += plugins/led
 if MONOLITHIC
diff --git a/src/libcharon/plugins/whitelist/Makefile.am b/src/libcharon/plugins/whitelist/Makefile.am
new file mode 100644 (file)
index 0000000..25350dc
--- /dev/null
@@ -0,0 +1,16 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-whitelist.la
+else
+plugin_LTLIBRARIES = libstrongswan-whitelist.la
+endif
+
+libstrongswan_whitelist_la_SOURCES = whitelist_plugin.h whitelist_plugin.c \
+       whitelist_listener.h whitelist_listener.c
+
+libstrongswan_whitelist_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.c b/src/libcharon/plugins/whitelist/whitelist_listener.c
new file mode 100644 (file)
index 0000000..66e9d80
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "whitelist_listener.h"
+
+#include <daemon.h>
+#include <utils/hashtable.h>
+#include <threading/rwlock.h>
+
+typedef struct private_whitelist_listener_t private_whitelist_listener_t;
+
+/**
+ * Private data of an whitelist_listener_t object.
+ */
+struct private_whitelist_listener_t {
+
+       /**
+        * Public whitelist_listener_t interface.
+        */
+       whitelist_listener_t public;
+
+       /**
+        * Lock for hashtable
+        */
+       rwlock_t *lock;
+
+       /**
+        * Hashtable with whitelisted identities
+        */
+       hashtable_t *ids;
+};
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(identification_t *key)
+{
+       return chunk_hash(key->get_encoding(key));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(identification_t *a, identification_t *b)
+{
+       return a->equals(a, b);
+}
+
+METHOD(listener_t, authorize, bool,
+       private_whitelist_listener_t *this, ike_sa_t *ike_sa,
+       bool final, bool *success)
+{
+       /* check each authentication round */
+       if (!final)
+       {
+               bool whitelisted = FALSE;
+               identification_t *id;
+               auth_cfg_t *auth;
+
+               auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
+               /* for authenticated with EAP, check EAP identity */
+               id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
+               if (!id)
+               {
+                       id = auth->get(auth, AUTH_RULE_IDENTITY);
+               }
+               if (id)
+               {
+                       this->lock->read_lock(this->lock);
+                       whitelisted = this->ids->get(this->ids, id) != NULL;
+                       this->lock->unlock(this->lock);
+               }
+               if (whitelisted)
+               {
+                       DBG2(DBG_CFG, "peer identity '%Y' whitelisted", id);
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "peer identity '%Y' not whitelisted", id);
+                       *success = FALSE;
+               }
+       }
+       return TRUE;
+}
+
+METHOD(whitelist_listener_t, add, void,
+       private_whitelist_listener_t *this, identification_t *id)
+{
+       id = id->clone(id);
+       this->lock->write_lock(this->lock);
+       id = this->ids->put(this->ids, id, id);
+       this->lock->unlock(this->lock);
+       DESTROY_IF(id);
+}
+
+METHOD(whitelist_listener_t, remove_, void,
+       private_whitelist_listener_t *this, identification_t *id)
+{
+       this->lock->write_lock(this->lock);
+       id = this->ids->remove(this->ids, id);
+       this->lock->unlock(this->lock);
+       DESTROY_IF(id);
+}
+
+/**
+ * Enumerator filter, from hashtable (key, value) to single identity
+ */
+static bool whitelist_filter(rwlock_t *lock, identification_t **key,
+                                                        identification_t **id, identification_t **value)
+{
+       *id = *value;
+       return TRUE;
+}
+
+METHOD(whitelist_listener_t, create_enumerator, enumerator_t*,
+       private_whitelist_listener_t *this)
+{
+       this->lock->read_lock(this->lock);
+       return enumerator_create_filter(this->ids->create_enumerator(this->ids),
+                                                                       (void*)whitelist_filter, this->lock,
+                                                                       (void*)this->lock->unlock);
+}
+
+METHOD(whitelist_listener_t, flush, void,
+       private_whitelist_listener_t *this, identification_t *id)
+{
+       enumerator_t *enumerator;
+       identification_t *key, *value;
+
+       this->lock->write_lock(this->lock);
+       enumerator = this->ids->create_enumerator(this->ids);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               if (value->matches(value, id))
+               {
+                       this->ids->remove_at(this->ids, enumerator);
+                       value->destroy(value);
+               }
+       }
+       enumerator->destroy(enumerator);
+       this->lock->unlock(this->lock);
+}
+
+METHOD(whitelist_listener_t, destroy, void,
+       private_whitelist_listener_t *this)
+{
+       identification_t *key, *value;
+       enumerator_t *enumerator;
+
+       enumerator = this->ids->create_enumerator(this->ids);
+       while (enumerator->enumerate(enumerator, &key, &value))
+       {
+               value->destroy(value);
+       }
+       enumerator->destroy(enumerator);
+       this->ids->destroy(this->ids);
+       this->lock->destroy(this->lock);
+       free(this);
+}
+
+/**
+ * See header
+ */
+whitelist_listener_t *whitelist_listener_create()
+{
+       private_whitelist_listener_t *this;
+
+       INIT(this,
+               .public = {
+                       .listener = {
+                               .authorize = _authorize,
+                       },
+                       .add = _add,
+                       .remove = _remove_,
+                       .create_enumerator = _create_enumerator,
+                       .flush = _flush,
+                       .destroy = _destroy,
+               },
+               .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+               .ids = hashtable_create((hashtable_hash_t)hash,
+                                                               (hashtable_equals_t)equals, 32),
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.h b/src/libcharon/plugins/whitelist/whitelist_listener.h
new file mode 100644 (file)
index 0000000..ed76d5f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup whitelist_listener whitelist_listener
+ * @{ @ingroup whitelist
+ */
+
+#ifndef WHITELIST_LISTENER_H_
+#define WHITELIST_LISTENER_H_
+
+#include <bus/listeners/listener.h>
+
+typedef struct whitelist_listener_t whitelist_listener_t;
+
+/**
+ * Listener checking connecting peer against a whitelist.
+ */
+struct whitelist_listener_t {
+
+       /**
+        * Implements listener_t interface.
+        */
+       listener_t listener;
+
+       /**
+        * Add a peer identity to the whitelist.
+        *
+        * @param id            identity to whitelist
+        */
+       void (*add)(whitelist_listener_t *this, identification_t *id);
+
+       /**
+        * Remove a peer identity from the whitelist.
+        *
+        * @param id            identity to remove from whitelist
+        */
+       void (*remove)(whitelist_listener_t *this, identification_t *id);
+
+       /**
+        * Create an enumerator over whitelisted peer identities.
+        *
+        * The enumerator read-locks the whitelist, do not call add/remove while
+        * it is alive.
+        *
+        * @return                      enumerator over identification_t*
+        */
+       enumerator_t* (*create_enumerator)(whitelist_listener_t *this);
+
+       /**
+        * Flush identities from whitelist matching id.
+        *
+        * @param id            id to match
+        */
+       void (*flush)(whitelist_listener_t *this, identification_t *id);
+
+       /**
+        * Destroy a whitelist_listener_t.
+        */
+       void (*destroy)(whitelist_listener_t *this);
+};
+
+/**
+ * Create a whitelist_listener instance.
+ */
+whitelist_listener_t *whitelist_listener_create();
+
+#endif /** WHITELIST_LISTENER_H_ @}*/
diff --git a/src/libcharon/plugins/whitelist/whitelist_plugin.c b/src/libcharon/plugins/whitelist/whitelist_plugin.c
new file mode 100644 (file)
index 0000000..f2ed7ba
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+#include "whitelist_plugin.h"
+
+#include "whitelist_listener.h"
+
+#include <daemon.h>
+
+typedef struct private_whitelist_plugin_t private_whitelist_plugin_t;
+
+/**
+ * private data of whitelist plugin
+ */
+struct private_whitelist_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       whitelist_plugin_t public;
+
+       /**
+        * Listener checking whitelist entries during authorization
+        */
+       whitelist_listener_t *listener;
+};
+
+METHOD(plugin_t, destroy, void,
+       private_whitelist_plugin_t *this)
+{
+       charon->bus->remove_listener(charon->bus, &this->listener->listener);
+       this->listener->destroy(this->listener);
+       free(this);
+}
+
+/**
+ * Plugin constructor
+ */
+plugin_t *whitelist_plugin_create()
+{
+       private_whitelist_plugin_t *this;
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .destroy = _destroy,
+                       },
+               },
+               .listener = whitelist_listener_create(),
+       );
+
+       charon->bus->add_listener(charon->bus, &this->listener->listener);
+
+       return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/whitelist/whitelist_plugin.h b/src/libcharon/plugins/whitelist/whitelist_plugin.h
new file mode 100644 (file)
index 0000000..2433133
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup whitelist whitelist
+ * @ingroup cplugins
+ *
+ * @defgroup whitelist_plugin whitelist_plugin
+ * @{ @ingroup whitelist
+ */
+
+#ifndef WHITELIST_PLUGIN_H_
+#define WHITELIST_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct whitelist_plugin_t whitelist_plugin_t;
+
+/**
+ * Peer identity whitelisting plugin.
+ */
+struct whitelist_plugin_t {
+
+       /**
+        * Implements plugin interface.
+        */
+       plugin_t plugin;
+};
+
+#endif /** WHITELIST_PLUGIN_H_ @}*/