summaryrefslogtreecommitdiff
path: root/src/charon/config/backend_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/config/backend_manager.c')
-rw-r--r--src/charon/config/backend_manager.c366
1 files changed, 230 insertions, 136 deletions
diff --git a/src/charon/config/backend_manager.c b/src/charon/config/backend_manager.c
index b2104acea..d77c05fd7 100644
--- a/src/charon/config/backend_manager.c
+++ b/src/charon/config/backend_manager.c
@@ -1,10 +1,3 @@
-/**
- * @file backend_manager.c
- *
- * @brief Implementation of backend_manager_t.
- *
- */
-
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
@@ -18,18 +11,18 @@
* 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.
+ *
+ * $Id: backend_manager.c 4044 2008-06-06 15:05:54Z martin $
*/
#include "backend_manager.h"
#include <sys/types.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <dlfcn.h>
+#include <pthread.h>
#include <daemon.h>
#include <utils/linked_list.h>
-#include <config/backends/writeable_backend.h>
+#include <utils/mutex.h>
typedef struct private_backend_manager_t private_backend_manager_t;
@@ -50,164 +43,268 @@ struct private_backend_manager_t {
linked_list_t *backends;
/**
- * Additional list of writable backends.
+ * locking mutex
*/
- linked_list_t *writeable;
-
- /**
- * List of dlopen() handles we used to open backends
- */
- linked_list_t *handles;
+ mutex_t *mutex;
};
/**
- * implements backend_manager_t.get_ike_cfg.
+ * data to pass nested IKE enumerator
*/
-static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this,
- host_t *my_host, host_t *other_host)
+typedef struct {
+ private_backend_manager_t *this;
+ host_t *me;
+ host_t *other;
+} ike_data_t;
+
+/**
+ * data to pass nested peer enumerator
+ */
+typedef struct {
+ private_backend_manager_t *this;
+ identification_t *me;
+ identification_t *other;
+} peer_data_t;
+
+/**
+ * destroy IKE enumerator data and unlock list
+ */
+static void ike_enum_destroy(ike_data_t *data)
{
- backend_t *backend;
- ike_cfg_t *config = NULL;
- iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE);
- while (config == NULL && iterator->iterate(iterator, (void**)&backend))
- {
- config = backend->get_ike_cfg(backend, my_host, other_host);
- }
- iterator->destroy(iterator);
- return config;
+ data->this->mutex->unlock(data->this->mutex);
+ free(data);
}
/**
- * implements backend_manager_t.get_peer_cfg.
- */
-static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this,
- identification_t *my_id, identification_t *other_id,
- ca_info_t *other_ca_info)
+ * destroy PEER enumerator data and unlock list
+ */
+static void peer_enum_destroy(peer_data_t *data)
{
- backend_t *backend;
- peer_cfg_t *config = NULL;
- iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE);
- while (config == NULL && iterator->iterate(iterator, (void**)&backend))
- {
- config = backend->get_peer_cfg(backend, my_id, other_id, other_ca_info);
- }
- iterator->destroy(iterator);
- return config;
+ data->this->mutex->unlock(data->this->mutex);
+ free(data);
}
/**
- * implements backend_manager_t.get_peer_cfg_by_name.
- */
-static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name)
+ * inner enumerator constructor for IKE cfgs
+ */
+static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
{
- backend_t *backend;
- peer_cfg_t *config = NULL;
- iterator_t *iterator = this->backends->create_iterator(this->backends, TRUE);
- while (config == NULL && iterator->iterate(iterator, (void**)&backend))
- {
- config = backend->get_peer_cfg_by_name(backend, name);
- }
- iterator->destroy(iterator);
- return config;
+ return backend->create_ike_cfg_enumerator(backend, data->me, data->other);
}
/**
- * implements backend_manager_t.add_peer_cfg.
- */
-static void add_peer_cfg(private_backend_manager_t *this, peer_cfg_t *config)
+ * inner enumerator constructor for Peer cfgs
+ */
+static enumerator_t *peer_enum_create(backend_t *backend, peer_data_t *data)
{
- writeable_backend_t *backend;
-
- if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS)
- {
- backend->add_cfg(backend, config);
- }
+ return backend->create_peer_cfg_enumerator(backend, data->me, data->other);
}
-
/**
- * implements backend_manager_t.create_iterator.
- */
-static iterator_t* create_iterator(private_backend_manager_t *this)
+ * inner enumerator constructor for all Peer cfgs
+ */
+static enumerator_t *peer_enum_create_all(backend_t *backend)
{
- writeable_backend_t *backend;
-
- if (this->writeable->get_first(this->writeable, (void**)&backend) == SUCCESS)
- {
- return backend->create_iterator(backend);
- }
- /* give out an empty iterator if we have no writable backend*/
- return this->writeable->create_iterator(this->writeable, TRUE);
+ return backend->create_peer_cfg_enumerator(backend, NULL, NULL);
}
/**
- * load the configuration backend modules
+ * implements backend_manager_t.get_ike_cfg.
*/
-static void load_backends(private_backend_manager_t *this)
+static ike_cfg_t *get_ike_cfg(private_backend_manager_t *this,
+ host_t *me, host_t *other)
{
- struct dirent* entry;
- DIR* dir;
-
- dir = opendir(IPSEC_BACKENDDIR);
- if (dir == NULL)
- {
- DBG1(DBG_CFG, "error opening backend modules directory "IPSEC_BACKENDDIR);
- return;
- }
+ ike_cfg_t *current, *found = NULL;
+ enumerator_t *enumerator;
+ host_t *my_candidate, *other_candidate;
+ ike_data_t *data;
+ enum {
+ MATCH_NONE = 0x00,
+ MATCH_ANY = 0x01,
+ MATCH_ME = 0x04,
+ MATCH_OTHER = 0x08,
+ } prio, best = MATCH_ANY;
- DBG1(DBG_CFG, "loading backend modules from '"IPSEC_BACKENDDIR"'");
-
- while ((entry = readdir(dir)) != NULL)
+ data = malloc_thing(ike_data_t);
+ data->this = this;
+ data->me = me;
+ data->other = other;
+
+ DBG2(DBG_CFG, "looking for a config for %H...%H", me, other);
+
+ this->mutex->lock(this->mutex);
+ enumerator = enumerator_create_nested(
+ this->backends->create_enumerator(this->backends),
+ (void*)ike_enum_create, data, (void*)ike_enum_destroy);
+ while (enumerator->enumerate(enumerator, (void**)&current))
{
- char file[256];
- backend_t *backend;
- backend_constructor_t constructor;
- void *handle;
- char *ending;
-
- snprintf(file, sizeof(file), IPSEC_BACKENDDIR"/%s", entry->d_name);
+ prio = MATCH_NONE;
- ending = entry->d_name + strlen(entry->d_name) - 3;
- if (ending <= entry->d_name || !streq(ending, ".so"))
+ my_candidate = host_create_from_dns(current->get_my_addr(current),
+ me->get_family(me), 0);
+ if (!my_candidate)
{
- /* skip anything which does not look like a library */
- DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
- entry->d_name);
continue;
}
- /* try to load the library */
- handle = dlopen(file, RTLD_LAZY);
- if (handle == NULL)
+ if (my_candidate->ip_equals(my_candidate, me))
{
- DBG1(DBG_CFG, " opening backend module %s failed: %s",
- entry->d_name, dlerror());
- continue;
+ prio += MATCH_ME;
}
- constructor = dlsym(handle, "backend_create");
- if (constructor == NULL)
+ else if (my_candidate->is_anyaddr(my_candidate))
{
- DBG1(DBG_CFG, " backend module %s has no backend_create() "
- "function, skipped", entry->d_name);
- dlclose(handle);
- continue;
+ prio += MATCH_ANY;
}
+ my_candidate->destroy(my_candidate);
- backend = constructor();
- if (backend == NULL)
+ other_candidate = host_create_from_dns(current->get_other_addr(current),
+ other->get_family(other), 0);
+ if (!other_candidate)
{
- DBG1(DBG_CFG, " unable to create instance of backend "
- "module %s, skipped", entry->d_name);
- dlclose(handle);
continue;
}
- DBG1(DBG_CFG, " loaded backend module successfully from %s", entry->d_name);
- this->backends->insert_last(this->backends, backend);
- if (backend->is_writeable(backend))
+ if (other_candidate->ip_equals(other_candidate, other))
+ {
+ prio += MATCH_OTHER;
+ }
+ else if (other_candidate->is_anyaddr(other_candidate))
+ {
+ prio += MATCH_ANY;
+ }
+ other_candidate->destroy(other_candidate);
+
+ DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
+ current->get_my_addr(current), current->get_other_addr(current),
+ prio);
+
+ /* we require at least two MATCH_ANY */
+ if (prio > best)
{
- this->writeable->insert_last(this->writeable, backend);
+ best = prio;
+ DESTROY_IF(found);
+ found = current;
+ found->get_ref(found);
}
- this->handles->insert_last(this->handles, handle);
}
- closedir(dir);
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+ return found;
+}
+
+
+static enumerator_t *create_peer_cfg_enumerator(private_backend_manager_t *this)
+{
+ this->mutex->lock(this->mutex);
+ return enumerator_create_nested(
+ this->backends->create_enumerator(this->backends),
+ (void*)peer_enum_create_all, this->mutex,
+ (void*)this->mutex->unlock);
+}
+
+/**
+ * implements backend_manager_t.get_peer_cfg.
+ */
+static peer_cfg_t *get_peer_cfg(private_backend_manager_t *this,
+ identification_t *me, identification_t *other,
+ auth_info_t *auth)
+{
+ peer_cfg_t *current, *found = NULL;
+ enumerator_t *enumerator;
+ identification_t *my_candidate, *other_candidate;
+ id_match_t best = ID_MATCH_NONE;
+ peer_data_t *data;
+
+ DBG2(DBG_CFG, "looking for a config for %D...%D", me, other);
+
+ data = malloc_thing(peer_data_t);
+ data->this = this;
+ data->me = me;
+ data->other = other;
+
+ this->mutex->lock(this->mutex);
+ enumerator = enumerator_create_nested(
+ this->backends->create_enumerator(this->backends),
+ (void*)peer_enum_create, data, (void*)peer_enum_destroy);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ id_match_t m1, m2, sum;
+
+ my_candidate = current->get_my_id(current);
+ other_candidate = current->get_other_id(current);
+
+ /* own ID may have wildcards in both, config and request (missing IDr) */
+ m1 = my_candidate->matches(my_candidate, me);
+ if (!m1)
+ {
+ m1 = me->matches(me, my_candidate);
+ }
+ m2 = other->matches(other, other_candidate);
+ sum = m1 + m2;
+
+ if (m1 && m2)
+ {
+ if (auth->complies(auth, current->get_auth(current)))
+ {
+ DBG2(DBG_CFG, " candidate '%s': %D...%D, prio %d",
+ current->get_name(current), my_candidate,
+ other_candidate, sum);
+ if (sum > best)
+ {
+ DESTROY_IF(found);
+ found = current;
+ found->get_ref(found);
+ best = sum;
+ }
+ }
+ }
+ }
+ if (found)
+ {
+ DBG1(DBG_CFG, "found matching config \"%s\": %D...%D, prio %d",
+ found->get_name(found), found->get_my_id(found),
+ found->get_other_id(found), best);
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+ return found;
+}
+
+/**
+ * implements backend_manager_t.get_peer_cfg_by_name.
+ */
+static peer_cfg_t *get_peer_cfg_by_name(private_backend_manager_t *this, char *name)
+{
+ backend_t *backend;
+ peer_cfg_t *config = NULL;
+ enumerator_t *enumerator;
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->backends->create_enumerator(this->backends);
+ while (config == NULL && enumerator->enumerate(enumerator, (void**)&backend))
+ {
+ config = backend->get_peer_cfg_by_name(backend, name);
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+ return config;
+}
+
+/**
+ * Implementation of backend_manager_t.remove_backend.
+ */
+static void remove_backend(private_backend_manager_t *this, backend_t *backend)
+{
+ this->mutex->lock(this->mutex);
+ this->backends->remove(this->backends, backend, NULL);
+ this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of backend_manager_t.add_backend.
+ */
+static void add_backend(private_backend_manager_t *this, backend_t *backend)
+{
+ this->mutex->lock(this->mutex);
+ this->backends->insert_last(this->backends, backend);
+ this->mutex->unlock(this->mutex);
}
/**
@@ -215,9 +312,8 @@ static void load_backends(private_backend_manager_t *this)
*/
static void destroy(private_backend_manager_t *this)
{
- this->backends->destroy_offset(this->backends, offsetof(backend_t, destroy));
- this->writeable->destroy(this->writeable);
- this->handles->destroy_function(this->handles, (void*)dlclose);
+ this->backends->destroy(this->backends);
+ this->mutex->destroy(this->mutex);
free(this);
}
@@ -229,17 +325,15 @@ backend_manager_t *backend_manager_create()
private_backend_manager_t *this = malloc_thing(private_backend_manager_t);
this->public.get_ike_cfg = (ike_cfg_t* (*)(backend_manager_t*, host_t*, host_t*))get_ike_cfg;
- this->public.get_peer_cfg = (peer_cfg_t* (*)(backend_manager_t*,identification_t*,identification_t*,ca_info_t*))get_peer_cfg;
+ this->public.get_peer_cfg = (peer_cfg_t* (*)(backend_manager_t*,identification_t*,identification_t*,auth_info_t*))get_peer_cfg;
this->public.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_manager_t*,char*))get_peer_cfg_by_name;
- this->public.add_peer_cfg = (void (*)(backend_manager_t*,peer_cfg_t*))add_peer_cfg;
- this->public.create_iterator = (iterator_t* (*)(backend_manager_t*))create_iterator;
+ this->public.create_peer_cfg_enumerator = (enumerator_t* (*)(backend_manager_t*))create_peer_cfg_enumerator;
+ this->public.add_backend = (void(*)(backend_manager_t*, backend_t *backend))add_backend;
+ this->public.remove_backend = (void(*)(backend_manager_t*, backend_t *backend))remove_backend;
this->public.destroy = (void (*)(backend_manager_t*))destroy;
this->backends = linked_list_create();
- this->writeable = linked_list_create();
- this->handles = linked_list_create();
-
- load_backends(this);
+ this->mutex = mutex_create(MUTEX_RECURSIVE);
return &this->public;
}