splitted stroke plugin to several files:
authorMartin Willi <martin@strongswan.org>
Wed, 26 Mar 2008 10:10:40 +0000 (10:10 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 26 Mar 2008 10:10:40 +0000 (10:10 -0000)
  socket: reads messages from socket, dispatching
  config: process add/del conn, serves configs through backend_t
  control: controlling of the daemon (up/down/route/...(
  cred: credential loading, serves creds through credential_set_t
  ca: ca sections from ipsec.conf, serves cdp's through credential_set_t
  list: log status information to stroke console (status/statusall/list*)
  shared_key: shared key implementation for keys read from ipsec.secrets
  plugin: registers stroke plugin and starts socket w/ thread

19 files changed:
src/charon/plugins/stroke/Makefile.am
src/charon/plugins/stroke/stroke.c [deleted file]
src/charon/plugins/stroke/stroke.h [deleted file]
src/charon/plugins/stroke/stroke_ca.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_ca.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_config.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_config.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_control.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_control.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_cred.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_cred.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_list.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_list.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_plugin.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_plugin.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_shared_key.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_shared_key.h [new file with mode: 0644]
src/charon/plugins/stroke/stroke_socket.c [new file with mode: 0644]
src/charon/plugins/stroke/stroke_socket.h [new file with mode: 0644]

index b2aeec1..4aa1f60 100644 (file)
@@ -5,6 +5,13 @@ AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\
 
 plugin_LTLIBRARIES = libcharon-stroke.la
 
-libcharon_stroke_la_SOURCES = stroke.h stroke.c
+libcharon_stroke_la_SOURCES = stroke_plugin.h stroke_plugin.c \
+  stroke_socket.h stroke_socket.c \
+  stroke_config.h stroke_config.c \
+  stroke_control.h stroke_control.c \
+  stroke_cred.h stroke_cred.c \
+  stroke_ca.h stroke_ca.c \
+  stroke_list.h stroke_list.c \
+  stroke_shared_key.h stroke_shared_key.c \
 libcharon_stroke_la_LDFLAGS = -module
 
diff --git a/src/charon/plugins/stroke/stroke.c b/src/charon/plugins/stroke/stroke.c
deleted file mode 100755 (executable)
index ae78176..0000000
+++ /dev/null
@@ -1,3276 +0,0 @@
-/*
- * Copyright (C) 2007 Tobias Brunner
- * Copyright (C) 2006-2007 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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.
- *
- * $Id$
- */
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/fcntl.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-
-#include "stroke.h"
-
-/* stroke message format definition */
-#include <stroke_msg.h>
-
-#include <library.h>
-#include <daemon.h>
-#include <credentials/certificates/x509.h>
-#include <credentials/certificates/crl.h>
-#include <credentials/certificates/ac.h>
-#include <credentials/certificates/ocsp_request.h>
-#include <credentials/certificates/ocsp_response.h>
-#include <control/controller.h>
-#include <utils/lexparser.h>
-#include <asn1/ttodata.h>
-#include <asn1/pem.h>
-#include <utils/mutex.h>
-#include <processing/jobs/callback_job.h>
-#include <credentials/credential_set.h>
-
-/* configuration directories and files */
-#define CONFIG_DIR IPSEC_CONFDIR
-#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
-#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
-#define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
-#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
-#define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
-#define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
-#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
-#define CRL_DIR IPSEC_D_DIR "/crls"
-#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
-
-/* warning intervals for list functions */
-#define CERT_WARNING_INTERVAL  30      /* days */
-#define CRL_WARNING_INTERVAL   7       /* days */
-
-typedef struct private_stroke_t private_stroke_t;
-typedef struct stroke_credentials_t stroke_credentials_t;
-typedef struct ca_creds_t ca_creds_t;
-typedef struct creds_t creds_t;
-typedef struct ca_section_t ca_section_t;
-typedef struct configs_t configs_t;
-
-/**
- * loaded ipsec.conf CA sections
- */
-struct ca_section_t {
-
-       /**
-        * name of the CA section
-        */
-       char *name;
-       
-       /**
-        * reference to cert in trusted_credential_t
-        */
-       certificate_t *cert;
-       
-       /**
-        * CRL URIs
-        */
-       linked_list_t *crl;
-       
-       /**
-        * OCSP URIs
-        */
-       linked_list_t *ocsp;
-};
-
-/**
- * private credentail_set_t implementation for CA sections
- */
-struct ca_creds_t {
-       /**
-        * implements credential set
-        */
-       credential_set_t set;
-
-       /**
-        * list of starters CA sections and its certificates (ca_section_t)
-        */
-       linked_list_t *sections;
-       
-       /**
-        * mutex to lock sections list
-        */
-       mutex_t *mutex;
-       
-};
-
-/**
- * private credential_set_t implementation for trusted certificates and keys
- */
-struct creds_t {
-       /**
-        * implements credential set
-        */
-       credential_set_t set;
-       
-       /**
-        * list of trusted peer/signer/CA certificates (certificate_t)
-        */
-       linked_list_t *certs;
-
-       /**
-        * list of shared secrets (private_shared_key_t)
-        */
-       linked_list_t *shared;
-
-       /**
-        * list of private keys (private_key_t)
-        */
-       linked_list_t *private;
-       
-       /**
-        * mutex to lock lists above
-        */
-       mutex_t *mutex;
-};
-
-
-typedef struct private_shared_key_t private_shared_key_t;
-/**
- * private data of shared_key
- */
-struct private_shared_key_t {
-
-       /**
-        * implements shared_key_t
-        */
-       shared_key_t public;
-       
-       /**
-        * type of this key
-        */
-       shared_key_type_t type;
-
-       /**
-        * data of the key
-        */
-       chunk_t key;
-
-       /**
-        * list of key owners, as identification_t
-        */
-       linked_list_t *owners;
-       
-       /**
-        * reference counter
-        */
-       refcount_t ref;
-};
-
-
-/**
- * configuration backend including peer_cfg list
- */
-struct configs_t {
-
-       /**
-        * implements backend_t interface
-        */
-       backend_t backend;
-       
-       /**
-        * list of peer_cfg_t
-        */
-       linked_list_t *list;
-       
-       /**
-        * mutex to lock config list
-        */
-       mutex_t *mutex;
-};
-
-/**
- * Private data of an stroke_t object.
- */
-struct private_stroke_t {
-
-       /**
-        * Public part of stroke_t object.
-        */
-       stroke_t public;
-               
-       /**
-        * Unix socket to listen for strokes
-        */
-       int socket;
-       
-       /**
-        * job accepting stroke messages
-        */
-       callback_job_t *job;
-       
-       /**
-        * CA credentials
-        */
-       ca_creds_t ca_creds;
-       
-       /**
-        * other credentials
-        */
-       creds_t creds;
-       
-       /**
-        * configuration backend
-        */
-       configs_t configs;
-};
-
-typedef struct stroke_log_info_t stroke_log_info_t;
-
-/**
- * helper struct to say what and where to log when using controller callback
- */
-struct stroke_log_info_t {
-
-       /**
-        * level to log up to
-        */
-       level_t level;
-       
-       /**
-        * where to write log
-        */
-       FILE* out;
-};
-
-/**
- * create a new CA section 
- */
-static ca_section_t *ca_section_create(char *name, certificate_t *cert)
-{
-       ca_section_t *ca = malloc_thing(ca_section_t);
-       
-       ca->name = strdup(name);
-       ca->crl = linked_list_create();
-       ca->ocsp = linked_list_create();
-       ca->cert = cert;
-       return ca;
-}
-
-/**
- * destroy a ca section entry
- */
-static void ca_section_destroy(ca_section_t *this)
-{
-       this->crl->destroy_function(this->crl, free);
-       this->ocsp->destroy_function(this->ocsp, free);
-       free(this->name);
-       free(this);
-}
-
-/**
- * data to pass to create_inner_cdp
- */
-typedef struct {
-       ca_creds_t *this;
-       certificate_type_t type;
-       identification_t *id;
-} cdp_data_t;
-
-/**
- * destroy cdp enumerator data and unlock list
- */
-static void cdp_data_destroy(cdp_data_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-/**
- * inner enumerator constructor for CDP URIs
- */
-static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
-{
-       public_key_t *public;
-       identification_t *keyid;
-       enumerator_t *enumerator = NULL;
-       linked_list_t *list;
-       
-       if (data->type == CERT_X509_OCSP_RESPONSE)
-       {
-               list = section->ocsp;
-       }
-       else
-       {
-               list = section->crl;
-       }
-
-       public = section->cert->get_public_key(section->cert);
-       if (public)
-       {
-               if (!data->id)
-               {
-                       enumerator = list->create_enumerator(list);
-               }
-               else
-               {
-                       keyid = public->get_id(public, data->id->get_type(data->id));
-                       if (keyid && keyid->matches(keyid, data->id))
-                       {
-                               enumerator = list->create_enumerator(list);             
-                       }
-               }
-               public->destroy(public);
-       }
-       return enumerator;
-}
-
-/**
- * Implementation of ca_creds_t.set.create_cdp_enumerator.
- */
-static enumerator_t *create_cdp_enumerator(ca_creds_t *this,
-                                                               certificate_type_t type, identification_t *id)
-{
-       cdp_data_t *data;
-
-       switch (type)
-       {       /* we serve CRLs and OCSP responders */
-               case CERT_X509_CRL:
-               case CERT_X509_OCSP_RESPONSE:
-               case CERT_ANY:
-                       break;
-               default:
-                       return NULL;
-       }
-       data = malloc_thing(cdp_data_t);
-       data->this = this;
-       data->type = type;
-       data->id = id;
-       
-       this->mutex->lock(this->mutex);
-       return enumerator_create_nested(this->sections->create_enumerator(this->sections),
-                                                                       (void*)create_inner_cdp, data,
-                                                                       (void*)cdp_data_destroy);
-}
-
-/**
- * data to pass to various filters
- */
-typedef struct {
-       creds_t *this;
-       identification_t *id;
-} id_data_t;
-
-/**
- * destroy id enumerator data and unlock list
- */
-static void id_data_destroy(id_data_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-
-/**
- * filter function for private key enumerator
- */
-static bool private_filter(id_data_t *data,
-                                                  private_key_t **in, private_key_t **out)
-{
-       identification_t *candidate;
-       
-       if (data->id == NULL)
-       {
-               *out = *in;
-               return TRUE;
-       }
-       candidate = (*in)->get_id(*in, data->id->get_type(data->id));
-       if (candidate && data->id->equals(data->id, candidate))
-       {
-               *out = *in;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * Implements creds_t.set.create_private_enumerator
- */
-static enumerator_t* create_private_enumerator(creds_t *this,
-                                                       key_type_t type, identification_t *id)
-{
-       id_data_t *data;
-
-       if (type != KEY_RSA && type != KEY_ANY)
-       {       /* we only have RSA keys */
-               return NULL;
-       }
-       data = malloc_thing(id_data_t);
-       data->this = this;
-       data->id = id;
-       
-       this->mutex->lock(this->mutex);
-       return enumerator_create_filter(this->private->create_enumerator(this->private),
-                                                                       (void*)private_filter, data,
-                                                                       (void*)id_data_destroy);
-}
-
-/**
- * filter function for certs enumerator
- */
-static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **out)
-{
-       public_key_t *public;
-       identification_t *candidate;
-       certificate_t *cert = *in;
-       
-       if (cert->get_type(cert) == CERT_X509_CRL)
-       {
-               return FALSE;
-       }
-
-       if (data->id == NULL || cert->has_subject(cert, data->id))
-       {
-               *out = *in;
-               return TRUE;
-       }
-       
-       public = (cert)->get_public_key(cert);
-       if (public)
-       {
-               candidate = public->get_id(public, data->id->get_type(data->id));
-               if (candidate && data->id->equals(data->id, candidate))
-               {
-                       public->destroy(public);
-                       *out = *in;
-                       return TRUE;
-               }
-               public->destroy(public);
-       }
-       return FALSE;
-}
-
-/**
- * filter function for crl enumerator
- */
-static bool crl_filter(id_data_t *data, certificate_t **in, certificate_t **out)
-{
-       certificate_t *cert = *in;
-       
-       if (cert->get_type(cert) != CERT_X509_CRL)
-       {
-               return FALSE;
-       }
-
-       if (data->id == NULL || cert->has_issuer(cert, data->id))
-       {
-               *out = *in;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * Implements creds_t.set.create_cert_enumerator
- */
-static enumerator_t* create_cert_enumerator(creds_t *this,
-                                                       certificate_type_t cert, key_type_t key,
-                                                       identification_t *id, bool trusted)
-{
-       id_data_t *data;
-       
-       if (cert == CERT_X509_CRL)
-       {
-               data = malloc_thing(id_data_t);
-               data->this = this;
-               data->id = id;
-               
-               this->mutex->lock(this->mutex);
-               return enumerator_create_filter(this->certs->create_enumerator(this->certs),
-                                                                               (void*)crl_filter, data,
-                                                                               (void*)id_data_destroy);
-       }
-       if (cert != CERT_X509 && cert != CERT_ANY)
-       {       /* we only have X509 certificates. TODO: ACs? */
-               return NULL;
-       }
-       if (key != KEY_RSA && key != KEY_ANY)
-       {       /* we only have RSA keys */
-               return NULL;
-       }
-       data = malloc_thing(id_data_t);
-       data->this = this;
-       data->id = id;
-       
-       this->mutex->lock(this->mutex);
-       return enumerator_create_filter(this->certs->create_enumerator(this->certs),
-                                                                       (void*)certs_filter, data,
-                                                                       (void*)id_data_destroy);
-}
-
-/**
- * Implementation of shared_key_t.get_type.
- */
-static shared_key_type_t get_type(private_shared_key_t *this)
-{
-       return this->type;
-}
-
-/**
- * Implementation of shared_key_t.get_ref.
- */
-static private_shared_key_t* get_ref(private_shared_key_t *this)
-{
-       ref_get(&this->ref);
-       return this;
-}
-
-/**
- * Implementation of shared_key_t.destroy
- */
-static void shared_key_destroy(private_shared_key_t *this)
-{
-       if (ref_put(&this->ref))
-       {
-               this->owners->destroy_offset(this->owners, offsetof(identification_t, destroy));
-               chunk_free(&this->key);
-               free(this);
-       }
-}
-
-/**
- * Implementation of shared_key_t.get_key.
- */
-static chunk_t get_key(private_shared_key_t *this)
-{
-       return this->key;
-}
-
-/**
- * create a shared key
- */
-static private_shared_key_t *private_shared_key_create(shared_key_type_t type, chunk_t key)
-{
-       private_shared_key_t *this = malloc_thing(private_shared_key_t);
-
-       this->public.get_type = (shared_key_type_t(*)(shared_key_t*))get_type;
-       this->public.get_key = (chunk_t(*)(shared_key_t*))get_key;
-       this->public.get_ref = (shared_key_t*(*)(shared_key_t*))get_ref;
-       this->public.destroy = (void(*)(shared_key_t*))shared_key_destroy;
-
-       this->owners = linked_list_create();
-       this->type = type;
-       this->key = key;
-       this->ref = 1;
-       return this;
-}
-
-/**
- * Check if a key has such an owner
- */
-static id_match_t has_owner(private_shared_key_t *this, identification_t *owner)
-{
-       enumerator_t *enumerator;
-       id_match_t match, best = ID_MATCH_NONE;
-       identification_t *current;
-       
-       enumerator = this->owners->create_enumerator(this->owners);
-       while (enumerator->enumerate(enumerator, &current))
-       {
-               match  = owner->matches(owner, current);
-               if (match > best)
-               {
-                       best = match;
-               }
-       }
-       enumerator->destroy(enumerator);
-       return best;
-}
-
-typedef struct {
-       creds_t *this;
-       identification_t *me;
-       identification_t *other;
-       shared_key_type_t type;
-} shared_data_t;
-
-/**
- * free shared key enumerator data and unlock list
- */
-static void shared_data_destroy(shared_data_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-/**
- * filter function for certs enumerator
- */
-static bool shared_filter(shared_data_t *data,
-                                                 private_shared_key_t **in, private_shared_key_t **out,
-                                                 void **unused1, id_match_t *me,
-                                                 void **unused2, id_match_t *other)
-{
-       id_match_t my_match, other_match;
-
-       if (data->type != SHARED_ANY && (*in)->type != data->type)
-       {
-               return FALSE;
-       }
-       my_match = has_owner(*in, data->me);
-       other_match = has_owner(*in, data->other);
-       if (!my_match && !other_match)
-       {
-               return FALSE;
-       }
-       *out = *in;
-       if (me)
-       {
-               *me = my_match;
-       }
-       if (other)
-       {
-               *other = other_match;
-       }
-       return TRUE;
-}
-
-/**
- * Implements creds_t.set.create_shared_enumerator
- */
-static enumerator_t* create_shared_enumerator(creds_t *this, 
-                                                       shared_key_type_t type, identification_t *me,
-                                                       identification_t *other)
-{
-       shared_data_t *data = malloc_thing(shared_data_t);
-       
-       data->this = this;
-       data->me = me;
-       data->other = other;
-       data->type = type;
-       this->mutex->lock(this->mutex);
-       return enumerator_create_filter(this->shared->create_enumerator(this->shared),
-                                                                       (void*)shared_filter, data,
-                                                                       (void*)shared_data_destroy);
-}
-
-/**
- * Helper function which corrects the string pointers
- * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
- * contains RELATIVE addresses (relative to the beginning of the
- * stroke_msg). They must be corrected if they reach our address
- * space...
- */
-static void pop_string(stroke_msg_t *msg, char **string)
-{
-       if (*string == NULL)
-       {
-               return;
-       }
-
-       /* check for sanity of string pointer and string */
-       if (string < (char**)msg ||
-               string > (char**)msg + sizeof(stroke_msg_t) ||
-               (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) ||
-               (unsigned long)*string > msg->length)
-       {
-               *string = "(invalid pointer in stroke msg)";
-       }
-       else
-       {
-               *string = (char*)msg + (unsigned long)*string;
-       }
-}
-
-/**
- * Add X.509 certificate to chain
- */
-static certificate_t* add_x509_cert(private_stroke_t *this, x509_t* x509)
-{
-       certificate_t *current, *cert = &x509->interface;
-       enumerator_t *enumerator;
-       bool new = TRUE;        
-
-       this->creds.mutex->lock(this->creds.mutex);
-       enumerator = this->creds.certs->create_enumerator(this->creds.certs);
-       while (enumerator->enumerate(enumerator, (void**)&current))
-       {
-               if (current->equals(current, cert))
-               {
-                       /* cert already in queue */
-                       cert->destroy(cert);
-                       cert = current;
-                       new = FALSE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (new)
-       {
-               this->creds.certs->insert_last(this->creds.certs, cert);
-       }
-       this->creds.mutex->unlock(this->creds.mutex);
-       return cert;
-}
-
-/**
- * Verify the signature of an X.509 CRL
- */
-static bool verify_crl(crl_t* crl)
-{
-       certificate_t *crl_cert = &crl->certificate;
-       identification_t *issuer = crl_cert->get_issuer(crl_cert);
-       identification_t *authKeyIdentifier = crl->get_authKeyIdentifier(crl);
-       certificate_t *issuer_cert;
-
-       DBG1(DBG_CFG, "  issuer: %D", issuer);
-       if (authKeyIdentifier)
-       {
-               DBG1(DBG_CFG, "  authkey: %D", authKeyIdentifier);
-       }
-
-       issuer_cert = charon->credentials->get_cert(charon->credentials, CERT_X509,
-                                                                                           KEY_ANY, issuer, TRUE);
-
-       if (issuer_cert)
-       {
-               
-               bool ok = crl_cert->issued_by(crl_cert, issuer_cert, TRUE);
-
-               DBG1(DBG_CFG, "  crl is %strusted: %s signature",
-                                                ok? "":"un", ok? "good":"bad");
-               return ok;
-       }
-       else
-       {
-               DBG1(DBG_CFG, "  crl is untrusted: issuer certificate not found");
-               return FALSE;
-       }
-}
-
-/**
- * Add X.509 CRL to chain
- */
-static void add_crl(private_stroke_t *this, crl_t* crl)
-{
-       certificate_t *current, *cert = &crl->certificate;
-       enumerator_t *enumerator;
-       bool new = TRUE, found = FALSE; 
-
-       this->creds.mutex->lock(this->creds.mutex);
-       enumerator = this->creds.certs->create_enumerator(this->creds.certs);
-       while (enumerator->enumerate(enumerator, (void**)&current))
-       {
-               if (current->get_type(current) == CERT_X509_CRL)
-               {
-                       crl_t *crl_c = (crl_t*)current;
-                       identification_t *authkey = crl->get_authKeyIdentifier(crl);
-                       identification_t *authkey_c = crl_c->get_authKeyIdentifier(crl_c);
-
-                       /* if compare authorityKeyIdentifiers if available */
-                       if (authkey != NULL && authkey_c != NULL &&
-                               authkey->equals(authkey, authkey_c))
-                       {
-                               found = TRUE;
-                       }
-                       else
-                       {
-                               identification_t *issuer = cert->get_issuer(cert);
-                               identification_t *issuer_c = current->get_issuer(current);
-
-                               /* otherwise compare issuer distinguished names */
-                               if (issuer->equals(issuer, issuer_c))
-                               {
-                                       found = TRUE;
-                               }
-                       }
-                       if (found)
-                       {
-                               new = cert->is_newer(cert, current);
-                               if (new)
-                               {
-                                       this->creds.certs->remove_at(this->creds.certs, enumerator);
-                               }
-                               else
-                               {
-                                       cert->destroy(cert);
-                               }
-                               break;
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (new)
-       {
-               this->creds.certs->insert_last(this->creds.certs, cert);
-       }
-       this->creds.mutex->unlock(this->creds.mutex);
-}
-
-/**
- * Load end entitity certificate
- */
-static void load_peer_cert(private_stroke_t *this,
-                                                  char *filename, identification_t **id)
-{
-       certificate_t *cert;
-       char path[PATH_MAX];
-       identification_t *peerid = *id;
-
-       if (*filename == '/')
-       {
-               snprintf(path, sizeof(path), "%s", filename);
-       }
-       else
-       {
-               snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
-       }
-       cert = lib->creds->create(lib->creds,
-                                                         CRED_CERTIFICATE, CERT_X509,
-                                                         BUILD_FROM_FILE, path,
-                                                         BUILD_X509_FLAG, 0,
-                                                         BUILD_END);
-       if (cert)
-       {
-               identification_t *subject = cert->get_subject(cert);
-
-               if (!cert->has_subject(cert, peerid))
-               {
-                       DBG1(DBG_CFG, "  peerid %D not confirmed by certificate, "
-                                       "defaulting to subject DN", peerid);
-                       peerid->destroy(peerid);
-                       *id = subject->clone(subject);
-               }
-               add_x509_cert(this, (x509_t*)cert);
-       }
-}
-
-/**
- * Load ca certificate
- */
-static certificate_t* load_ca_cert(private_stroke_t *this, char *filename)
-{
-       certificate_t *cert;
-       char path[PATH_MAX];
-
-       if (*filename == '/')
-       {
-               snprintf(path, sizeof(path), "%s", filename);
-       }
-       else
-       {
-               snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
-       }
-       cert = lib->creds->create(lib->creds,
-                                                         CRED_CERTIFICATE, CERT_X509,
-                                                         BUILD_FROM_FILE, path,
-                                                         BUILD_X509_FLAG, X509_CA,
-                                                         BUILD_END);
-       if (cert)
-       {
-               return add_x509_cert(this, (x509_t*)cert);
-       }
-       else
-       {
-               return NULL;
-       }
-}
-
-/**
- * load trusted certificates from a directory
- */
-static void load_certdir(private_stroke_t *this, char *path,
-                                                certificate_type_t type, x509_flag_t flag)
-{
-       struct stat st;
-       char *file;
-       
-       enumerator_t *enumerator = enumerator_create_directory(path);
-
-       if (!enumerator)
-       {
-               DBG1(DBG_CFG, "  reading directory failed");
-               return;
-       }
-
-       while (enumerator->enumerate(enumerator, NULL, &file, &st))
-       {
-               certificate_t *cert;
-
-               if (!S_ISREG(st.st_mode))
-               {
-                       /* skip special file */
-                       continue;
-               }
-               switch (type)
-               {
-                       case CERT_X509:
-                               cert = lib->creds->create(lib->creds,
-                                                                                 CRED_CERTIFICATE, CERT_X509,
-                                                                                 BUILD_FROM_FILE, file,
-                                                                                 BUILD_X509_FLAG, flag,
-                                                                                 BUILD_END);
-                               if (cert)
-                               {
-                                       add_x509_cert(this, (x509_t*)cert);
-                               }
-                               break;
-                       case CERT_X509_CRL:
-                               cert = lib->creds->create(lib->creds,
-                                                                                 CRED_CERTIFICATE, CERT_X509_CRL,
-                                                                                 BUILD_FROM_FILE, file,
-                                                                                 BUILD_END);
-                               if (cert)
-                               {
-                                       /* only trusted crls are added to the store */
-                                       if (verify_crl((crl_t*)cert))
-                                       {
-                                               add_crl(this, (crl_t*)cert);
-                                       }
-                                       else
-                                       {
-                                               DBG1(DBG_CFG, "  crl discarded");
-                                               cert->destroy(cert);
-                                       }
-                               }
-                               break;
-                       case CERT_X509_AC:
-                               cert = lib->creds->create(lib->creds,
-                                                                                 CRED_CERTIFICATE, CERT_X509_AC,
-                                                                                 BUILD_FROM_FILE, file,
-                                                                                 BUILD_END);
-                               if (cert)
-                               {
-                                               cert->destroy(cert);
-                               }
-                               break;
-                       default:
-                               break;  
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * Convert a string of characters into a binary secret
- * A string between single or double quotes is treated as ASCII characters
- * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
- */
-static err_t extract_secret(chunk_t *secret, chunk_t *line)
-{
-       chunk_t raw_secret;
-       char delimiter = ' ';
-       bool quotes = FALSE;
-
-       if (!eat_whitespace(line))
-       {
-               return "missing secret";
-       }
-
-       if (*line->ptr == '\'' || *line->ptr == '"')
-       {
-               quotes = TRUE;
-               delimiter = *line->ptr;
-               line->ptr++;  line->len--;
-       }
-
-       if (!extract_token(&raw_secret, delimiter, line))
-       {
-               if (delimiter == ' ')
-               {
-                       raw_secret = *line;
-               }
-               else
-               {
-                       return "missing second delimiter";
-               }
-       }
-
-       if (quotes)
-       {       
-               /* treat as an ASCII string */
-               *secret = chunk_clone(raw_secret);
-       }
-       else
-       {
-               size_t len;
-               err_t ugh;
-
-               /* secret converted to binary form doesn't use more space than the raw_secret */
-               *secret = chunk_alloc(raw_secret.len);
-
-               /* convert from HEX or Base64 to binary */
-               ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len);
-
-           if (ugh != NULL)
-               {
-                       chunk_free_randomized(secret);
-                       return ugh;
-               }
-               secret->len = len;
-       }
-       return NULL;
-}
-
-/**
- * reload ipsec.secrets
- */
-static void load_secrets(private_stroke_t *this)
-{
-       size_t bytes;
-       int line_nr = 0;
-       chunk_t chunk, src, line;
-       FILE *fd;
-       private_key_t *private;
-       shared_key_t *shared;
-
-       DBG1(DBG_CFG, "loading secrets from '%s'", SECRETS_FILE);
-
-       fd = fopen(SECRETS_FILE, "r");
-       if (fd == NULL)
-       {
-               DBG1(DBG_CFG, "opening secrets file '%s' failed");
-               return;
-       }
-
-       /* TODO: do error checks */
-       fseek(fd, 0, SEEK_END);
-       chunk.len = ftell(fd);
-       rewind(fd);
-       chunk.ptr = malloc(chunk.len);
-       bytes = fread(chunk.ptr, 1, chunk.len, fd);
-       fclose(fd);
-       src = chunk;
-
-       this->creds.mutex->lock(this->creds.mutex);
-       while (this->creds.shared->remove_last(this->creds.shared,
-                                                                                  (void**)&shared) == SUCCESS)
-       {
-               shared->destroy(shared);
-       }
-       while (this->creds.private->remove_last(this->creds.private,
-                                                                                   (void**)&private) == SUCCESS)
-       {
-               private->destroy(private);
-       }
-       
-       while (fetchline(&src, &line))
-       {
-               chunk_t ids, token;
-               shared_key_type_t type;
-
-               line_nr++;
-
-               if (!eat_whitespace(&line))
-               {
-                       continue;
-               }
-               if (!extract_token(&ids, ':', &line))
-               {
-                       DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
-                       goto error;
-               }
-               /* NULL terminate the ids string by replacing the : separator */
-               *(ids.ptr + ids.len) = '\0';
-
-               if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
-               {
-                       DBG1(DBG_CFG, "line %d: missing token", line_nr);
-                       goto error;
-               }
-               if (match("RSA", &token))
-               {
-                       char path[PATH_MAX];
-                       chunk_t filename;
-                       chunk_t secret = chunk_empty;
-                       private_key_t *key;
-                       bool pgp = FALSE;
-                       chunk_t chunk = chunk_empty;
-
-                       err_t ugh = extract_value(&filename, &line);
-
-                       if (ugh != NULL)
-                       {
-                               DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
-                               goto error;
-                       }
-                       if (filename.len == 0)
-                       {
-                               DBG1(DBG_CFG, "line %d: empty filename", line_nr);
-                               goto error;
-                       }
-                       if (*filename.ptr == '/')
-                       {
-                               /* absolute path name */
-                               snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
-                       }
-                       else
-                       {
-                               /* relative path name */
-                               snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, 
-                                                filename.len, filename.ptr);
-                       }
-
-                       /* check for optional passphrase */
-                       if (eat_whitespace(&line))
-                       {
-                               ugh = extract_secret(&secret, &line);
-                               if (ugh != NULL)
-                               {
-                                       DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
-                                       goto error;
-                               }
-                       }
-
-                       if (pem_asn1_load_file(path, &secret, &chunk, &pgp))
-                       {
-                               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
-                                                                                BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
-                               if (key)
-                               {
-                                       DBG1(DBG_CFG, "  loaded private key file '%s'", path);
-                                       this->creds.private->insert_last(this->creds.private, key);
-                               }
-                       }
-                       chunk_free_randomized(&secret);
-               }
-               else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
-                                (match("EAP", &token) && (type = SHARED_EAP)) ||
-                                (match("XAUTH", &token) && (type = SHARED_EAP)) ||
-                                (match("PIN", &token) && (type = SHARED_PIN)))
-               {
-                       private_shared_key_t *shared_key;
-                       chunk_t secret = chunk_empty;
-                       bool any = TRUE;
-
-                       err_t ugh = extract_secret(&secret, &line);
-                       if (ugh != NULL)
-                       {
-                               DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
-                               goto error;
-                       }
-                       shared_key = private_shared_key_create(type, secret);
-                       DBG1(DBG_CFG, "  loaded %N secret for %s", shared_key_type_names, type,
-                                ids.len > 0 ? (char*)ids.ptr : "%any");
-                       DBG4(DBG_CFG, "  secret:", secret);
-                       
-                       this->creds.shared->insert_last(this->creds.shared, shared_key);
-                       while (ids.len > 0)
-                       {
-                               chunk_t id;
-                               identification_t *peer_id;
-
-                               ugh = extract_value(&id, &ids);
-                               if (ugh != NULL)
-                               {
-                                       DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
-                                       goto error;
-                               }
-                               if (id.len == 0)
-                               {
-                                       continue;
-                               }
-
-                               /* NULL terminate the ID string */
-                               *(id.ptr + id.len) = '\0';
-
-                               peer_id = identification_create_from_string(id.ptr);
-                               if (peer_id == NULL)
-                               {
-                                       DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
-                                       goto error;
-                               }
-                               if (peer_id->get_type(peer_id) == ID_ANY)
-                               {
-                                       peer_id->destroy(peer_id);
-                                       continue;
-                               }
-                               
-                               shared_key->owners->insert_last(shared_key->owners, peer_id);
-                               any = FALSE;
-                       }
-                       if (any)
-                       {
-                               shared_key->owners->insert_last(shared_key->owners,
-                                       identification_create_from_encoding(ID_ANY, chunk_empty));
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_CFG, "line %d: token must be either "
-                                "RSA, PSK, EAP, or PIN", line_nr);
-                       goto error;
-               }
-       }
-error:
-       this->creds.mutex->unlock(this->creds.mutex);
-       chunk_free_randomized(&chunk);
-}
-
-/**
- * data to pass peer_filter
- */
-typedef struct {
-       configs_t *this;
-       identification_t *me;
-       identification_t *other;
-} peer_data_t;
-
-/**
- * destroy id enumerator data and unlock list
- */
-static void peer_data_destroy(peer_data_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-/**
- * filter function for peer configs
- */
-static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out)
-{
-       bool match_me = FALSE, match_other = FALSE;
-       identification_t *me, *other;
-       
-       me = (*in)->get_my_id(*in);
-       other = (*in)->get_other_id(*in);
-       
-       /* own ID may have wildcards in data (no IDr payload) or in config */
-       match_me = (!data->me || data->me->matches(data->me, me) ||
-                               me->matches(me, data->me));
-       /* others ID has wildcards in config only */
-       match_other = (!data->other || data->other->matches(data->other, other));
-       
-       if (match_me && match_other)
-       {
-               *out = *in;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * Implementation of backend_t.create_peer_cfg_enumerator.
- */
-static enumerator_t* create_peer_cfg_enumerator(configs_t *this,
-                                                                                               identification_t *me,
-                                                                                               identification_t *other)
-{
-       peer_data_t *data;
-       
-       data = malloc_thing(peer_data_t);
-       data->this = this;
-       data->me = me;
-       data->other = other;
-       
-       this->mutex->lock(this->mutex);
-       return enumerator_create_filter(this->list->create_enumerator(this->list),
-                                                                       (void*)peer_filter, data,
-                                                                       (void*)peer_data_destroy);
-}
-
-/**
- * data to pass ike_filter
- */
-typedef struct {
-       configs_t *this;
-       host_t *me;
-       host_t *other;
-} ike_data_t;
-
-/**
- * destroy id enumerator data and unlock list
- */
-static void ike_data_destroy(ike_data_t *data)
-{
-       data->this->mutex->unlock(data->this->mutex);
-       free(data);
-}
-
-/**
- * filter function for ike configs
- */
-static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out)
-{
-       ike_cfg_t *ike_cfg;
-       host_t *me, *other;
-       
-       ike_cfg = (*in)->get_ike_cfg(*in);
-       
-       me = ike_cfg->get_my_host(ike_cfg);
-       other = ike_cfg->get_other_host(ike_cfg);
-       if ((!data->me || me->is_anyaddr(me) || me->ip_equals(me, data->me)) &&
-               (!data->other || other->is_anyaddr(other) || other->ip_equals(other, data->other)))
-       {
-               *out = ike_cfg;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-/**
- * Implementation of backend_t.create_ike_cfg_enumerator.
- */
-static enumerator_t* create_ike_cfg_enumerator(configs_t *this,
-                                                                                          host_t *me, host_t *other)
-{
-       ike_data_t *data;
-       
-       data = malloc_thing(ike_data_t);
-       data->this = this;
-       data->me = me;
-       data->other = other;
-       
-       this->mutex->lock(this->mutex);
-       return enumerator_create_filter(this->list->create_enumerator(this->list),
-                                                                       (void*)ike_filter, data,
-                                                                       (void*)ike_data_destroy);
-}
-
-/**
- * implements backend_t.get_peer_cfg_by_name.
- */
-static peer_cfg_t *get_peer_cfg_by_name(configs_t *this, char *name)
-{
-       enumerator_t *e1, *e2;
-       peer_cfg_t *current, *found = NULL;
-       child_cfg_t *child;
-
-       this->mutex->lock(this->mutex);
-       e1 = this->list->create_enumerator(this->list);
-       while (e1->enumerate(e1, &current))
-       {
-        /* compare peer_cfgs name first */
-        if (streq(current->get_name(current), name))
-        {
-            found = current;
-            found->get_ref(found);
-            break;
-        }
-        /* compare all child_cfg names otherwise */
-        e2 = current->create_child_cfg_enumerator(current);
-        while (e2->enumerate(e2, &child))
-        {
-            if (streq(child->get_name(child), name))
-            {
-                found = current;
-                found->get_ref(found);
-                break;
-            }
-        }
-        e2->destroy(e2);
-        if (found)
-        {
-            break;
-        }
-       }
-       e1->destroy(e1);
-       this->mutex->unlock(this->mutex);
-       return found;
-}
-
-/**
- * Pop the strings of a stroke_end_t struct and log them for debugging purposes
- */
-static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
-{
-       pop_string(msg, &end->address);
-       pop_string(msg, &end->subnet);
-       pop_string(msg, &end->sourceip);
-       pop_string(msg, &end->id);
-       pop_string(msg, &end->cert);
-       pop_string(msg, &end->ca);
-       pop_string(msg, &end->groups);
-       pop_string(msg, &end->updown);
-       
-       DBG2(DBG_CFG, "  %s=%s", label, end->address);
-       DBG2(DBG_CFG, "  %ssubnet=%s", label, end->subnet);
-       DBG2(DBG_CFG, "  %ssourceip=%s", label, end->sourceip);
-       DBG2(DBG_CFG, "  %sid=%s", label, end->id);
-       DBG2(DBG_CFG, "  %scert=%s", label, end->cert);
-       DBG2(DBG_CFG, "  %sca=%s", label, end->ca);
-       DBG2(DBG_CFG, "  %sgroups=%s", label, end->groups);
-       DBG2(DBG_CFG, "  %supdown=%s", label, end->updown);
-}
-
-/**
- * Add a connection to the configuration list
- */
-static void stroke_add_conn(private_stroke_t *this,
-                                                       stroke_msg_t *msg, FILE *out)
-{
-       ike_cfg_t *ike_cfg;
-       peer_cfg_t *peer_cfg;
-       peer_cfg_t *mediated_by_cfg = NULL;
-       child_cfg_t *child_cfg;
-       auth_info_t *auth;
-       identification_t *my_id, *other_id;
-       identification_t *my_ca = NULL;
-       identification_t *other_ca = NULL;
-       identification_t *peer_id = NULL;
-       bool my_ca_same = FALSE;
-       bool other_ca_same =FALSE;
-       host_t *my_host = NULL, *other_host = NULL, *my_subnet, *other_subnet;
-       host_t *my_vip = NULL, *other_vip = NULL;
-       proposal_t *proposal;
-       traffic_selector_t *my_ts, *other_ts;
-       char *interface;
-       bool use_existing = FALSE;
-       enumerator_t *enumerator;
-       u_int32_t vendor;
-       
-       pop_string(msg, &msg->add_conn.name);
-       DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
-       DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
-       pop_end(msg, "left", &msg->add_conn.me);
-       pop_end(msg, "right", &msg->add_conn.other);
-       pop_string(msg, &msg->add_conn.algorithms.ike);
-       pop_string(msg, &msg->add_conn.algorithms.esp);
-       DBG2(DBG_CFG, "  ike=%s", msg->add_conn.algorithms.ike);
-       DBG2(DBG_CFG, "  esp=%s", msg->add_conn.algorithms.esp);
-       pop_string(msg, &msg->add_conn.p2p.mediated_by);
-       pop_string(msg, &msg->add_conn.p2p.peerid);
-       DBG2(DBG_CFG, "  p2p_mediation=%s", msg->add_conn.p2p.mediation ? "yes" : "no");
-       DBG2(DBG_CFG, "  p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by);
-       DBG2(DBG_CFG, "  p2p_peerid=%s", msg->add_conn.p2p.peerid);
-       
-       if (msg->add_conn.me.address)
-       {
-               my_host = host_create_from_string(msg->add_conn.me.address,
-                                                                                 IKEV2_UDP_PORT);
-       }
-       if (my_host == NULL)
-       {
-               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
-               return;
-       }
-       if (msg->add_conn.other.address)
-       {
-               other_host = host_create_from_string(msg->add_conn.other.address,
-                                                                                        IKEV2_UDP_PORT);
-       }
-       if (other_host == NULL)
-       {
-               DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
-               my_host->destroy(my_host);
-               return;
-       }
-       
-       interface = charon->kernel_interface->get_interface(charon->kernel_interface, 
-                                                                                                               other_host);
-       if (interface)
-       {
-               stroke_end_t tmp_end;
-               host_t *tmp_host;
-
-               DBG2(DBG_CFG, "left is other host, swapping ends\n");
-
-               tmp_host = my_host;
-               my_host = other_host;
-               other_host = tmp_host;
-
-               tmp_end = msg->add_conn.me;
-               msg->add_conn.me = msg->add_conn.other;
-               msg->add_conn.other = tmp_end;
-               free(interface);
-       }
-       else
-       {
-               interface = charon->kernel_interface->get_interface(
-                                                                                       charon->kernel_interface, my_host);
-               if (!interface)
-               {
-                       DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
-               }
-               else
-               {
-                       free(interface);
-               }
-       }
-
-       my_id = identification_create_from_string(msg->add_conn.me.id ?
-                                               msg->add_conn.me.id : msg->add_conn.me.address);
-       if (my_id == NULL)
-       {
-               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
-               goto destroy_hosts;
-       }
-
-       other_id = identification_create_from_string(msg->add_conn.other.id ?
-                                               msg->add_conn.other.id : msg->add_conn.other.address);
-       if (other_id == NULL)
-       {
-               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
-               my_id->destroy(my_id);
-               goto destroy_hosts;
-       }
-       
-#ifdef P2P
-       if (msg->add_conn.p2p.mediation && msg->add_conn.p2p.mediated_by)
-       {
-               DBG1(DBG_CFG, "a mediation connection cannot be a"
-                               " mediated connection at the same time, aborting");
-               goto destroy_ids;
-       }
-       
-       if (msg->add_conn.p2p.mediated_by)
-       {
-               mediated_by_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
-                                                                                               msg->add_conn.p2p.mediated_by);
-               if (!mediated_by_cfg)
-               {
-                       DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
-                                       msg->add_conn.p2p.mediated_by);
-                       goto destroy_ids;
-               }
-               
-               if (!mediated_by_cfg->is_mediation(mediated_by_cfg))
-               {
-                       DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
-                                       "no mediation connection, aborting", 
-                                       msg->add_conn.p2p.mediated_by, msg->add_conn.name);
-                       goto destroy_ids;
-               }
-       }
-       
-       if (msg->add_conn.p2p.peerid)
-       {
-               peer_id = identification_create_from_string(msg->add_conn.p2p.peerid);
-               if (!peer_id)
-               {
-                       DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.p2p.peerid);
-                       goto destroy_ids;
-               }
-       }
-       else
-       {
-               /* no peer ID supplied, assume right ID */
-               peer_id = other_id->clone(other_id);
-       }
-#endif /* P2P */
-       
-       my_subnet = host_create_from_string(
-                                                       msg->add_conn.me.subnet ? msg->add_conn.me.subnet
-                                                                                                       : msg->add_conn.me.address, 
-                                                       IKEV2_UDP_PORT);
-       if (my_subnet == NULL)
-       {
-               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
-               goto destroy_ids;
-       }
-       
-       other_subnet = host_create_from_string(
-                                               msg->add_conn.other.subnet ? msg->add_conn.other.subnet 
-                                                                                                  : msg->add_conn.other.address, 
-                                               IKEV2_UDP_PORT);
-       if (other_subnet == NULL)
-       {
-               DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
-               my_subnet->destroy(my_subnet);
-               goto destroy_ids;
-       }
-       
-       if (msg->add_conn.me.virtual_ip && msg->add_conn.me.sourceip)
-       {
-               my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
-       }
-       if (msg->add_conn.other.virtual_ip && msg->add_conn.other.sourceip)
-       {
-               other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
-       }
-       
-       if (msg->add_conn.me.tohost)
-       {
-               my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol,
-                                       my_host->get_family(my_host) == AF_INET ?
-                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
-                                       msg->add_conn.me.port ? msg->add_conn.me.port : 0,
-                                       msg->add_conn.me.port ? msg->add_conn.me.port : 65535);
-       }
-       else
-       {
-               my_ts = traffic_selector_create_from_subnet(my_subnet,
-                               msg->add_conn.me.subnet ?  msg->add_conn.me.subnet_mask : 0,
-                               msg->add_conn.me.protocol, msg->add_conn.me.port);
-       }
-       my_subnet->destroy(my_subnet);
-       
-       if (msg->add_conn.other.tohost)
-       {
-               other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol,
-                                       other_host->get_family(other_host) == AF_INET ?
-                                               TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
-                                       msg->add_conn.other.port ? msg->add_conn.other.port : 0,
-                                       msg->add_conn.other.port ? msg->add_conn.other.port : 65535);
-       }
-       else
-       {
-               other_ts = traffic_selector_create_from_subnet(other_subnet, 
-                               msg->add_conn.other.subnet ?  msg->add_conn.other.subnet_mask : 0,
-                               msg->add_conn.other.protocol, msg->add_conn.other.port);
-       }
-       other_subnet->destroy(other_subnet);
-
-       if (msg->add_conn.me.ca)
-       {
-               if (streq(msg->add_conn.me.ca, "%same"))
-               {
-                       my_ca_same = TRUE;
-               }
-               else
-               {
-                       my_ca = identification_create_from_string(msg->add_conn.me.ca);
-               }
-       }
-       if (msg->add_conn.other.ca)
-       {
-               if (streq(msg->add_conn.other.ca, "%same"))
-               {
-                       other_ca_same = TRUE;
-               }
-               else
-               {
-                       other_ca = identification_create_from_string(msg->add_conn.other.ca);
-               }
-       }
-       if (msg->add_conn.me.cert)
-       {
-               load_peer_cert(this, msg->add_conn.me.cert, &my_id);
-       }
-       if (msg->add_conn.other.cert)
-       {
-               load_peer_cert(this, msg->add_conn.other.cert, &other_id);
-       }
-       if (other_ca_same && my_ca)
-       {
-               other_ca = my_ca->clone(my_ca);
-       }
-       else if (my_ca_same && other_ca)
-       {
-               my_ca = other_ca->clone(other_ca);
-       }
-       
-       if (my_ca)
-       {
-               DBG2(DBG_CFG, "  my ca:    %D", my_ca);
-       }
-       if (other_ca)
-       {
-               DBG2(DBG_CFG, "  other ca: %D", other_ca);
-       }
-
-       if (msg->add_conn.other.groups)
-       {
-               /* TODO: AC groups */
-       }
-
-       /* TODO: update matching */
-       /* have a look for an (almost) identical peer config to reuse */
-       enumerator = create_peer_cfg_enumerator(&this->configs, NULL, NULL);
-       while (enumerator->enumerate(enumerator, &peer_cfg))
-       {
-               host_t *my_vip_conf, *other_vip_conf;
-               bool my_vip_equals = FALSE, other_vip_equals = FALSE;
-
-               my_vip_conf = peer_cfg->get_my_virtual_ip(peer_cfg);
-               if ((my_vip && my_vip_conf && my_vip->equals(my_vip, my_vip_conf)) ||
-                       (!my_vip_conf && !my_vip))
-               {
-                       my_vip_equals = TRUE;
-               }
-               DESTROY_IF(my_vip_conf);
-               other_vip_conf = peer_cfg->get_other_virtual_ip(peer_cfg, NULL);
-               if ((other_vip && other_vip_conf && other_vip->equals(other_vip, other_vip_conf)) ||
-                       (!other_vip_conf && !other_vip))
-               {
-                       other_vip_equals = TRUE;
-               }
-               DESTROY_IF(other_vip_conf);
-       
-               ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
-               if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg))
-               &&      other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg))
-               &&      my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg))
-               &&      other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg))
-               &&      peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1)
-               &&      peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method
-               &&      peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type
-               &&  vendor == msg->add_conn.eap_vendor
-               &&  my_vip_equals && other_vip_equals)
-               {
-                       DBG1(DBG_CFG, "reusing existing configuration '%s'",
-                                peer_cfg->get_name(peer_cfg));
-                       use_existing = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (use_existing)
-       {
-               DESTROY_IF(my_vip);
-               DESTROY_IF(other_vip);
-               my_host->destroy(my_host);
-               my_id->destroy(my_id);
-               DESTROY_IF(my_ca);
-               other_host->destroy(other_host);
-               other_id->destroy(other_id);
-               DESTROY_IF(other_ca);
-               DESTROY_IF(peer_id);
-               DESTROY_IF(mediated_by_cfg);
-       }
-       else
-       {
-               ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
-                                                                msg->add_conn.force_encap, my_host, other_host);
-
-               if (msg->add_conn.algorithms.ike)
-               {
-                       char *proposal_string;
-                       char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
-
-                       if (*strict == '!')
-                               *strict = '\0';
-                       else
-                               strict = NULL;
-
-                       while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
-                       {
-                               proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
-                               if (proposal == NULL)
-                               {
-                                       DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
-                                       my_id->destroy(my_id);
-                                       other_id->destroy(other_id);
-                                       my_ts->destroy(my_ts);
-                                       other_ts->destroy(other_ts);
-                                       DESTROY_IF(my_ca);
-                                       DESTROY_IF(other_ca);
-                                       ike_cfg->destroy(ike_cfg);
-                                       return;
-                               }
-                               ike_cfg->add_proposal(ike_cfg, proposal);
-                       }
-                       if (!strict)
-                       {
-                               proposal = proposal_create_default(PROTO_IKE);
-                               ike_cfg->add_proposal(ike_cfg, proposal);
-                       }
-               }
-               else
-               {
-                       proposal = proposal_create_default(PROTO_IKE);
-                       ike_cfg->add_proposal(ike_cfg, proposal);
-               }
-               
-               u_int32_t rekey = 0, reauth = 0, over, jitter;
-               cert_validation_t valid;
-               
-               jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
-               over = msg->add_conn.rekey.margin;
-               if (msg->add_conn.rekey.reauth)
-               {
-                       reauth = msg->add_conn.rekey.ike_lifetime - over;
-               }
-               else
-               {
-                       rekey = msg->add_conn.rekey.ike_lifetime - over;
-               }
-               
-               peer_cfg = peer_cfg_create(msg->add_conn.name,
-                                       msg->add_conn.ikev2 ? 2 : 1, ike_cfg, my_id, other_id,
-                                       msg->add_conn.me.sendcert, msg->add_conn.auth_method,
-                                       msg->add_conn.eap_type, msg->add_conn.eap_vendor,
-                                       msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
-                                       msg->add_conn.mobike,
-                                       msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip,
-                                       msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id);
-               auth = peer_cfg->get_auth(peer_cfg);
-               switch (msg->add_conn.crl_policy)
-               {
-                       case CRL_STRICT_YES:
-                               valid = VALIDATION_GOOD;
-                               auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
-                               break;
-                       case CRL_STRICT_IFURI:
-                               valid = VALIDATION_SKIPPED;
-                               auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
-                               break;
-                       default:
-                               break;
-               }
-                                       
-               if (other_ca)
-               {
-                       DBG1(DBG_CFG, "  required other CA: %D", other_ca);
-                       certificate_t *cert = charon->credentials->get_cert(charon->credentials, 
-                                                                               CERT_X509, KEY_ANY, other_ca, TRUE);
-                       if (!cert)
-                       {
-                               DBG1(DBG_CFG, "deleted connection '%s': "
-                                                         "no trusted certificate found for required other CA",
-                                                          msg->add_conn.name);
-                               peer_cfg->destroy(peer_cfg);
-                               other_ca->destroy(other_ca);
-                               my_ts->destroy(my_ts);
-                               other_ts->destroy(other_ts);
-                               return;
-                       }
-                       /* require peer to authenticate against this cert */
-                       auth->add_item(auth, AUTHZ_CA_CERT, cert);
-                       cert->destroy(cert);
-                       other_ca->destroy(other_ca);
-               }
-               if (my_ca)
-               {
-                       certificate_t *cert = charon->credentials->get_cert(charon->credentials, 
-                                                                               CERT_X509, KEY_ANY, my_ca, TRUE);
-                       if (!cert)
-                       {
-                               DBG1(DBG_CFG, "deleted connection '%s': "
-                                                         "no trusted certificate found for my CA",
-                                                          msg->add_conn.name);
-                               peer_cfg->destroy(peer_cfg);
-                               my_ca->destroy(my_ca);
-                               my_ts->destroy(my_ts);
-                               other_ts->destroy(other_ts);
-                               return;
-                       }
-                       /* we authenticate against this cert */
-                       auth->add_item(auth, AUTHN_CA_CERT, cert);
-                       cert->destroy(cert);
-               }
-       }
-       child_cfg = child_cfg_create(
-                               msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
-                               msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
-                               msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
-                               msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
-                               msg->add_conn.mode);
-       
-       peer_cfg->add_child_cfg(peer_cfg, child_cfg);
-       
-       child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts);
-       child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts);
-       
-       if (msg->add_conn.algorithms.esp)
-       {
-               char *proposal_string;
-               char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
-
-               if (*strict == '!')
-                       *strict = '\0';
-               else
-                       strict = NULL;
-               
-               while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
-               {
-                       proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
-                       if (proposal == NULL)
-                       {
-                               DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
-                               peer_cfg->destroy(peer_cfg);
-                               return;
-                       }
-                       child_cfg->add_proposal(child_cfg, proposal);
-               }
-               if (!strict)
-               {
-                       proposal = proposal_create_default(PROTO_ESP);
-                       child_cfg->add_proposal(child_cfg, proposal);
-               }
-       }
-       else
-       {
-               proposal = proposal_create_default(PROTO_ESP);
-               child_cfg->add_proposal(child_cfg, proposal);
-       }
-       
-       if (!use_existing)
-       {
-               /* add config to backend */
-               this->configs.mutex->lock(this->configs.mutex);
-               this->configs.list->insert_last(this->configs.list, peer_cfg);
-               this->configs.mutex->unlock(this->configs.mutex);
-               DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]",
-                        msg->add_conn.name, my_host, my_id, other_host, other_id);
-       }
-       return;
-
-       /* mopping up after parsing errors */
-
-destroy_ids:
-       my_id->destroy(my_id);
-       other_id->destroy(other_id);
-       DESTROY_IF(mediated_by_cfg);
-       DESTROY_IF(peer_id);
-
-destroy_hosts:
-       my_host->destroy(my_host);
-       other_host->destroy(other_host);
-}
-
-/**
- * Delete a connection from the list
- */
-static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       enumerator_t *enumerator, *children;
-       peer_cfg_t *peer;
-       child_cfg_t *child;
-       
-       pop_string(msg, &(msg->del_conn.name));
-       DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
-       
-       this->configs.mutex->lock(this->configs.mutex);
-       enumerator = this->configs.list->create_enumerator(this->configs.list);
-       while (enumerator->enumerate(enumerator, (void**)&peer))
-       {
-               /* remove peer config with such a name */
-               if (streq(peer->get_name(peer), msg->del_conn.name))
-               {
-                       this->configs.list->remove_at(this->configs.list, enumerator);
-                       peer->destroy(peer);
-                       continue;
-               }
-               /* remove any child with such a name */
-               children = peer->create_child_cfg_enumerator(peer);
-               while (children->enumerate(children, &child))
-               {
-                       if (streq(child->get_name(child), msg->del_conn.name))
-                       {
-                               peer->remove_child_cfg(peer, enumerator);
-                               child->destroy(child);
-                       }
-               }
-               children->destroy(children);
-       }
-       enumerator->destroy(enumerator);
-       this->configs.mutex->unlock(this->configs.mutex);
-       
-       fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
-}
-
-/**
- * get the child_cfg with the same name as the peer cfg
- */
-static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
-{
-       child_cfg_t *current, *found = NULL;
-       enumerator_t *enumerator;
-       
-       enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
-       while (enumerator->enumerate(enumerator, &current))
-       {
-               if (streq(current->get_name(current), name))
-               {
-                       found = current;
-                       found->get_ref(found);
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-       return found;
-}
-
-/**
- * logging to the stroke interface
- */
-static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level,
-                                          ike_sa_t *ike_sa, char *format, va_list args)
-{
-       if (level <= info->level)
-       {
-               if (vfprintf(info->out, format, args) < 0 ||
-                       fprintf(info->out, "\n") < 0 ||
-                       fflush(info->out) != 0)
-               {
-                       return FALSE;
-               }
-       }
-       return TRUE;
-}
-
-/**
- * initiate a connection by name
- */
-static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       peer_cfg_t *peer_cfg;
-       child_cfg_t *child_cfg;
-       stroke_log_info_t info;
-       
-       pop_string(msg, &(msg->initiate.name));
-       DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
-       
-       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
-                                                                                                         msg->initiate.name);
-       if (peer_cfg == NULL)
-       {
-               fprintf(out, "no config named '%s'\n", msg->initiate.name);
-               return;
-       }
-       if (peer_cfg->get_ike_version(peer_cfg) != 2)
-       {
-               DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
-                        peer_cfg->get_ike_version(peer_cfg));
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
-       if (child_cfg == NULL)
-       {
-               fprintf(out, "no child config named '%s'\n", msg->initiate.name);
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       if (msg->output_verbosity < 0)
-       {
-               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        NULL, NULL);
-       }
-       else
-       {
-               info.out = out;
-               info.level = msg->output_verbosity;
-               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        (controller_cb_t)stroke_log, &info);
-       }
-}
-
-/**
- * route a policy (install SPD entries)
- */
-static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       peer_cfg_t *peer_cfg;
-       child_cfg_t *child_cfg;
-       stroke_log_info_t info;
-       
-       pop_string(msg, &(msg->route.name));
-       DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);
-       
-       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
-                                                                                                         msg->route.name);
-       if (peer_cfg == NULL)
-       {
-               fprintf(out, "no config named '%s'\n", msg->route.name);
-               return;
-       }
-       if (peer_cfg->get_ike_version(peer_cfg) != 2)
-       {
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
-       if (child_cfg == NULL)
-       {
-               fprintf(out, "no child config named '%s'\n", msg->route.name);
-               peer_cfg->destroy(peer_cfg);
-               return;
-       }
-       
-       info.out = out;
-       info.level = msg->output_verbosity;
-       charon->controller->route(charon->controller, peer_cfg, child_cfg,
-                                                         (controller_cb_t)stroke_log, &info);
-       peer_cfg->destroy(peer_cfg);
-       child_cfg->destroy(child_cfg);
-}
-
-/**
- * unroute a policy
- */
-static void stroke_unroute(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       char *name;
-       ike_sa_t *ike_sa;
-       iterator_t *iterator;
-       stroke_log_info_t info;
-       
-       pop_string(msg, &(msg->terminate.name));
-       name = msg->terminate.name;
-       
-       info.out = out;
-       info.level = msg->output_verbosity;
-       
-       iterator = charon->controller->create_ike_sa_iterator(charon->controller);
-       while (iterator->iterate(iterator, (void**)&ike_sa))
-       {
-               child_sa_t *child_sa;
-               iterator_t *children;
-               u_int32_t id;
-
-               children = ike_sa->create_child_sa_iterator(ike_sa);
-               while (children->iterate(children, (void**)&child_sa))
-               {
-                       if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
-                               streq(name, child_sa->get_name(child_sa)))
-                       {
-                               id = child_sa->get_reqid(child_sa);
-                               children->destroy(children);
-                               iterator->destroy(iterator);
-                               charon->controller->unroute(charon->controller, id,
-                                                               (controller_cb_t)stroke_log, &info);
-                               return;
-                       }
-               }
-               children->destroy(children);
-       }
-       iterator->destroy(iterator);
-       DBG1(DBG_CFG, "no such SA found");
-}
-
-/**
- * terminate a connection by name
- */
-static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       char *string, *pos = NULL, *name = NULL;
-       u_int32_t id = 0;
-       bool child;
-       int len;
-       ike_sa_t *ike_sa;
-       iterator_t *iterator;
-       stroke_log_info_t info;
-       
-       pop_string(msg, &(msg->terminate.name));
-       string = msg->terminate.name;
-       DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
-       
-       len = strlen(string);
-       if (len < 1)
-       {
-               DBG1(DBG_CFG, "error parsing string");
-               return;
-       }
-       switch (string[len-1])
-       {
-               case '}':
-                       child = TRUE;
-                       pos = strchr(string, '{');
-                       break;
-               case ']':
-                       child = FALSE;
-                       pos = strchr(string, '[');
-                       break;
-               default:
-                       name = string;
-                       child = FALSE;
-                       break;
-       }
-       
-       if (name)
-       {
-               /* is a single name */
-       }
-       else if (pos == string + len - 2)
-       {       /* is name[] or name{} */
-               string[len-2] = '\0';
-               name = string;
-       }
-       else
-       {       /* is name[123] or name{23} */
-               string[len-1] = '\0';
-               id = atoi(pos + 1);
-               if (id == 0)
-               {
-                       DBG1(DBG_CFG, "error parsing string");
-                       return;
-               }
-       }
-       
-       info.out = out;
-       info.level = msg->output_verbosity;
-       
-       iterator = charon->controller->create_ike_sa_iterator(charon->controller);
-       while (iterator->iterate(iterator, (void**)&ike_sa))
-       {
-               child_sa_t *child_sa;
-               iterator_t *children;
-               
-               if (child)
-               {
-                       children = ike_sa->create_child_sa_iterator(ike_sa);
-                       while (children->iterate(children, (void**)&child_sa))
-                       {
-                               if ((name && streq(name, child_sa->get_name(child_sa))) ||
-                                       (id && id == child_sa->get_reqid(child_sa)))
-                               {
-                                       id = child_sa->get_reqid(child_sa);
-                                       children->destroy(children);
-                                       iterator->destroy(iterator);
-                                       
-                                       charon->controller->terminate_child(charon->controller, id,
-                                                                       (controller_cb_t)stroke_log, &info);
-                                       return;
-                               }
-                       }
-                       children->destroy(children);
-               }
-               else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
-                                (id && id == ike_sa->get_unique_id(ike_sa)))
-               {
-                       id = ike_sa->get_unique_id(ike_sa);
-                       /* unlock manager first */
-                       iterator->destroy(iterator);
-                       
-                       charon->controller->terminate_ike(charon->controller, id,
-                                                                       (controller_cb_t)stroke_log, &info);
-                       return;
-               }
-               
-       }
-       iterator->destroy(iterator);
-       DBG1(DBG_CFG, "no such SA found");
-}
-
-/**
- * Add a ca information record to the cainfo list
- */
-static void stroke_add_ca(private_stroke_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       certificate_t *cert;
-       ca_section_t *ca;
-       
-       pop_string(msg, &msg->add_ca.name);
-       pop_string(msg, &msg->add_ca.cacert);
-       pop_string(msg, &msg->add_ca.crluri);
-       pop_string(msg, &msg->add_ca.crluri2);
-       pop_string(msg, &msg->add_ca.ocspuri);
-       pop_string(msg, &msg->add_ca.ocspuri2);
-       
-       DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
-       
-       DBG2(DBG_CFG, "ca %s",        msg->add_ca.name);
-       DBG2(DBG_CFG, "  cacert=%s",  msg->add_ca.cacert);
-       DBG2(DBG_CFG, "  crluri=%s",  msg->add_ca.crluri);
-       DBG2(DBG_CFG, "  crluri2=%s", msg->add_ca.crluri2);
-       DBG2(DBG_CFG, "  ocspuri=%s", msg->add_ca.ocspuri);
-       DBG2(DBG_CFG, "  ocspuri2=%s", msg->add_ca.ocspuri2);
-
-       if (msg->add_ca.cacert == NULL)
-       {
-               DBG1(DBG_CFG, "missing cacert parameter");
-               return;
-       }
-
-       cert = load_ca_cert(this, msg->add_ca.cacert);
-       if (cert)
-       {
-               ca = ca_section_create(msg->add_ca.name, cert);
-               if (msg->add_ca.crluri)
-               {
-                       ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
-               }
-               if (msg->add_ca.crluri2)
-               {
-                       ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2));
-               }
-               if (msg->add_ca.ocspuri)
-               {
-                       ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri));
-               }
-               if (msg->add_ca.ocspuri2)
-               {
-                       ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
-               }
-               this->ca_creds.mutex->lock(this->ca_creds.mutex);
-               this->ca_creds.sections->insert_last(this->ca_creds.sections, ca);
-               this->ca_creds.mutex->unlock(this->ca_creds.mutex);
-               DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
-       }
-}
-
-/**
- * Delete a ca information record from the cainfo list
- */
-static void stroke_del_ca(private_stroke_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       enumerator_t *enumerator;
-       ca_section_t *ca = NULL;
-       
-       pop_string(msg, &(msg->del_ca.name));
-       DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
-       
-       this->ca_creds.mutex->lock(this->ca_creds.mutex);
-       enumerator = this->ca_creds.sections->create_enumerator(this->ca_creds.sections);
-       while (enumerator->enumerate(enumerator, &ca))
-       {
-               if (streq(ca->name, msg->del_ca.name))
-               {
-                       this->ca_creds.sections->remove_at(this->ca_creds.sections, enumerator);
-                       break;
-               }
-               ca = NULL;
-       }
-       enumerator->destroy(enumerator);
-       this->ca_creds.mutex->unlock(this->ca_creds.mutex);
-       if (ca == NULL)
-       {
-               fprintf(out, "no ca named '%s' found\n", msg->del_ca.name);
-               return;
-       }
-       ca_section_destroy(ca);
-       /* TODO: flush cached certs */
-}
-
-/**
- * log an IKE_SA to out
- */
-static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
-{
-       ike_sa_id_t *id = ike_sa->get_id(ike_sa);
-       u_int32_t rekey, reauth;
-
-       fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
-                       ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                       ike_sa_state_names, ike_sa->get_state(ike_sa),
-                       ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
-                       ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
-       
-       if (all)
-       {
-               fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
-                               ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                               id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
-                               id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
-       
-               rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME);
-               reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME);
-               if (rekey)
-               {
-                       fprintf(out, ", rekeying in %V", &rekey);
-               }
-               if (reauth)
-               {
-                       fprintf(out, ", reauthentication in %V", &reauth);
-               }
-               if (!rekey && !reauth)
-               {
-                       fprintf(out, ", rekeying disabled");
-               }
-               fprintf(out, "\n");
-       }
-}
-
-/**
- * log an CHILD_SA to out
- */
-static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
-{
-       u_int32_t rekey, now = time(NULL);
-       u_int32_t use_in, use_out, use_fwd;
-       encryption_algorithm_t encr_alg;
-       integrity_algorithm_t int_alg;
-       size_t encr_len, int_len;
-       mode_t mode;
-       
-       child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
-                                               &int_alg, &int_len, &rekey, &use_in, &use_out,
-                                               &use_fwd);
-       
-       fprintf(out, "%12s{%d}:  %N, %N", 
-                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa_state_names, child_sa->get_state(child_sa),
-                       mode_names, mode);
-       
-       if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
-       {
-               fprintf(out, ", %N SPIs: %.8x_i %.8x_o",
-                               protocol_id_names, child_sa->get_protocol(child_sa),
-                               htonl(child_sa->get_spi(child_sa, TRUE)),
-                               htonl(child_sa->get_spi(child_sa, FALSE)));
-               
-               if (all)
-               {
-                       fprintf(out, "\n%12s{%d}:  ", child_sa->get_name(child_sa), 
-                                       child_sa->get_reqid(child_sa));
-                       
-                       
-                       if (child_sa->get_protocol(child_sa) == PROTO_ESP)
-                       {
-                               fprintf(out, "%N", encryption_algorithm_names, encr_alg);
-                               
-                               if (encr_len)
-                               {
-                                       fprintf(out, "-%d", encr_len);
-                               }
-                               fprintf(out, "/");
-                       }
-                       
-                       fprintf(out, "%N", integrity_algorithm_names, int_alg);
-                       if (int_len)
-                       {
-                               fprintf(out, "-%d", int_len);
-                       }
-                       fprintf(out, ", rekeying ");
-                       
-                       if (rekey)
-                       {
-                               fprintf(out, "in %#V", &now, &rekey);
-                       }
-                       else
-                       {
-                               fprintf(out, "disabled");
-                       }
-                       
-                       fprintf(out, ", last use: ");
-                       use_in = max(use_in, use_fwd);
-                       if (use_in)
-                       {
-                               fprintf(out, "%ds_i ", now - use_in);
-                       }
-                       else
-                       {
-                               fprintf(out, "no_i ");
-                       }
-                       if (use_out)
-                       {
-                               fprintf(out, "%ds_o ", now - use_out);
-                       }
-                       else
-                       {
-                               fprintf(out, "no_o ");
-                       }
-               }
-       }
-       
-       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
-                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa->get_traffic_selectors(child_sa, TRUE),
-                       child_sa->get_traffic_selectors(child_sa, FALSE));
-}
-
-/**
- * show status of daemon
- */
-static void stroke_status(private_stroke_t *this, stroke_msg_t *msg, FILE *out,
-                                                 bool all)
-{
-       enumerator_t *enumerator, *children;
-       iterator_t *iterator;
-       host_t *host;
-       peer_cfg_t *peer_cfg;
-       ike_cfg_t *ike_cfg;
-       child_cfg_t *child_cfg;
-       ike_sa_t *ike_sa;
-       char *name = NULL;
-       
-       if (msg->status.name)
-       {
-               pop_string(msg, &(msg->status.name));
-               name = msg->status.name;
-       }
-       
-       if (all)
-       {
-               fprintf(out, "Performance:\n");
-               fprintf(out, "  worker threads: %d idle of %d,",
-                               charon->processor->get_idle_threads(charon->processor),
-                               charon->processor->get_total_threads(charon->processor));
-               fprintf(out, " job queue load: %d,",
-                               charon->processor->get_job_load(charon->processor));
-               fprintf(out, " scheduled events: %d\n",
-                               charon->scheduler->get_job_load(charon->scheduler));
-               iterator = charon->kernel_interface->create_address_iterator(
-                                                                                                       charon->kernel_interface);
-               fprintf(out, "Listening IP addresses:\n");
-               while (iterator->iterate(iterator, (void**)&host))
-               {
-                       fprintf(out, "  %H\n", host);
-               }
-               iterator->destroy(iterator);
-       
-               fprintf(out, "Connections:\n");
-               enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
-               while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
-               {
-                       if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
-                               (name && !streq(name, peer_cfg->get_name(peer_cfg))))
-                       {
-                               continue;
-                       }
-                       
-                       ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
-                       fprintf(out, "%12s:  %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
-                                       ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
-                                       ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
-                       /* TODO: list CAs and groups */
-                       children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
-                       while (children->enumerate(children, &child_cfg))
-                       {
-                               linked_list_t *my_ts, *other_ts;
-                               my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
-                               other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
-                               fprintf(out, "%12s:    %#R=== %#R\n", child_cfg->get_name(child_cfg),
-                                               my_ts, other_ts);
-                               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
-                               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
-                       }
-                       children->destroy(children);
-               }
-               enumerator->destroy(enumerator);
-       }
-       
-       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
-       if (all && iterator->get_count(iterator) > 0)
-       {
-               fprintf(out, "Security Associations:\n");
-       }
-       while (iterator->iterate(iterator, (void**)&ike_sa))
-       {
-               bool ike_printed = FALSE;
-               child_sa_t *child_sa;
-               iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
-
-               if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
-               {
-                       log_ike_sa(out, ike_sa, all);
-                       ike_printed = TRUE;
-               }
-
-               while (children->iterate(children, (void**)&child_sa))
-               {
-                       if (name == NULL || streq(name, child_sa->get_name(child_sa)))
-                       {
-                               if (!ike_printed)
-                               {
-                                       log_ike_sa(out, ike_sa, all);
-                                       ike_printed = TRUE;
-                               }
-                               log_child_sa(out, child_sa, all);
-                       }       
-               }
-               children->destroy(children);
-       }
-       iterator->destroy(iterator);
-}
-
-/**
- * list all X.509 certificates matching the flags
- */
-static void stroke_list_certs(char *label, x509_flag_t flags, bool utc, FILE *out)
-{
-       bool first = TRUE;
-       time_t now = time(NULL);
-       certificate_t *cert;
-       enumerator_t *enumerator;
-       
-       enumerator = charon->credentials->create_cert_enumerator(
-                                               charon->credentials, CERT_X509, KEY_ANY, NULL, FALSE);
-       while (enumerator->enumerate(enumerator, (void**)&cert))
-       {
-               x509_t *x509 = (x509_t*)cert;
-               x509_flag_t x509_flags = x509->get_flags(x509);
-
-               /* list only if flag is set, or flags == 0 (ignoring self-signed) */
-               if ((x509_flags & flags) || (flags == (x509_flags & ~X509_SELF_SIGNED)))
-               {
-                       enumerator_t *enumerator;
-                       identification_t *altName;
-                       bool first_altName = TRUE;
-                       chunk_t serial = x509->get_serial(x509);
-                       identification_t *authkey = x509->get_authKeyIdentifier(x509);
-                       time_t notBefore, notAfter;
-                       public_key_t *public = cert->get_public_key(cert);
-
-                       if (first)
-                       {
-                               fprintf(out, "\n");
-                               fprintf(out, "List of %s:\n", label);
-                               first = FALSE;
-                       }
-                       fprintf(out, "\n");
-
-                       /* list subjectAltNames */
-                       enumerator = x509->create_subjectAltName_enumerator(x509);
-                       while (enumerator->enumerate(enumerator, (void**)&altName))
-                       {
-                               if (first_altName)
-                               {
-                                       fprintf(out, "  altNames:  ");
-                                       first_altName = FALSE;
-                               }
-                               else
-                               {
-                                       fprintf(out, ", ");
-                               }
-                               fprintf(out, "%D", altName);
-                       }
-                       if (!first_altName)
-                       {
-                               fprintf(out, "\n");
-                       }
-                       enumerator->destroy(enumerator);
-
-                       fprintf(out, "  subject:  %D\n", cert->get_subject(cert));
-                       fprintf(out, "  issuer:   %D\n", cert->get_issuer(cert));
-                       fprintf(out, "  serial:    %#B\n", &serial);
-
-                       /* list validity */
-                       cert->get_validity(cert, &now, &notBefore, &notAfter);
-                       fprintf(out, "  validity:  not before %#T, ", &notBefore, utc);
-                       if (now < notBefore)
-                       {
-                               fprintf(out, "not valid yet (valid in %#V)\n", &now, &notBefore);
-                       }
-                       else
-                       {
-                               fprintf(out, "ok\n");
-                       }
-                       fprintf(out, "             not after  %#T, ", &notAfter, utc);
-                       if (now > notAfter)
-                       {
-                               fprintf(out, "expired (%#V ago)\n", &now, &notAfter);
-                       }
-                       else
-                       {
-                               fprintf(out, "ok");
-                               if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
-                               {
-                                       fprintf(out, " (expires in %#V)", &now, &notAfter);
-                               }
-                               fprintf(out, " \n");
-                       }
-       
-                       /* list public key information */
-                       if (public)
-                       {
-                               private_key_t *private = NULL;
-                               identification_t *id, *keyid;
-                       
-                               id    = public->get_id(public, ID_PUBKEY_SHA1);
-                               keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
-
-                               private = charon->credentials->get_private(
-                                                                       charon->credentials, 
-                                                                       public->get_type(public), keyid, NULL);
-                               fprintf(out, "  pubkey:    %N %d bits%s\n",
-                                               key_type_names, public->get_type(public),
-                                               public->get_keysize(public) * 8,
-                                               private ? ", has private key" : "");
-                               fprintf(out, "  keyid:     %D\n", keyid);
-                               fprintf(out, "  subjkey:   %D\n", id);
-                               DESTROY_IF(private);
-                               public->destroy(public);
-                       }
-       
-                       /* list optional authorityKeyIdentifier */
-                       if (authkey)
-                       {
-                               fprintf(out, "  authkey:   %D\n", authkey);
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * list all X.509 CRLs
- */
-static void stroke_list_crls(bool utc, FILE *out)
-{
-       bool first = TRUE;
-       time_t thisUpdate, nextUpdate, now = time(NULL);
-       certificate_t *cert;
-       enumerator_t *enumerator;
-       
-       enumerator = charon->credentials->create_cert_enumerator(
-                                               charon->credentials, CERT_X509_CRL, KEY_ANY, NULL, FALSE);
-       while (enumerator->enumerate(enumerator, (void**)&cert))
-       {
-               crl_t *crl = (crl_t*)cert;
-               chunk_t serial  = crl->get_serial(crl);
-               identification_t *authkey = crl->get_authKeyIdentifier(crl);
-
-               if (first)
-               {
-                       fprintf(out, "\n");
-                       fprintf(out, "List of X.509 CRLs:\n");
-                       first = FALSE;
-               }
-               fprintf(out, "\n");
-
-               fprintf(out, "  issuer:   %D\n", cert->get_issuer(cert));
-
-               /* list optional crlNumber */
-               if (serial.ptr)
-               {
-                       fprintf(out, "  serial:    %#B\n", &serial);
-               }
-
-               /* count the number of revoked certificates */
-               {
-                       int count = 0;
-                       enumerator_t *enumerator = crl->create_enumerator(crl);
-
-                       while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
-                       {
-                               count++;
-                       }
-                       fprintf(out, "  revoked:   %d certificate%s\n", count,
-                                                       (count == 1)? "" : "s");
-                       enumerator->destroy(enumerator);
-               }
-
-               /* list validity */
-               cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
-               fprintf(out, "  updates:   this %#T\n",  &thisUpdate, utc);
-               fprintf(out, "             next %#T, ", &nextUpdate, utc);
-               if (now > nextUpdate)
-               {
-                       fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
-               }
-               else
-               {
-                       fprintf(out, "ok");
-                       if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
-                       {
-                               fprintf(out, " (expires in %#V)", &now, &nextUpdate);
-                       }
-                       fprintf(out, " \n");
-               }
-
-               /* list optional authorityKeyIdentifier */
-               if (authkey)
-               {
-                       fprintf(out, "  authkey:   %D\n", authkey);
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * list all CA information sections
- */
-static void stroke_list_cainfos(private_stroke_t *this, FILE *out)
-{
-       bool first = TRUE;
-       ca_section_t *section;
-       enumerator_t *enumerator;
-       
-       this->ca_creds.mutex->lock(this->ca_creds.mutex);
-       enumerator = this->ca_creds.sections->create_enumerator(this->ca_creds.sections);
-       while (enumerator->enumerate(enumerator, (void**)&section))
-       {
-               certificate_t *cert = section->cert;
-               public_key_t *public = cert->get_public_key(cert);
-
-               if (first)
-               {
-                       fprintf(out, "\n");
-                       fprintf(out, "List of CA Information Sections:\n");
-                       first = FALSE;
-               }
-               fprintf(out, "\n");
-               fprintf(out, "  authname: %D\n", cert->get_subject(cert));
-
-               /* list authkey and keyid */
-               if (public)
-               {
-                       fprintf(out, "  authkey:   %D\n",
-                                       public->get_id(public, ID_PUBKEY_SHA1));
-                       fprintf(out, "  keyid:     %D\n",
-                                       public->get_id(public, ID_PUBKEY_INFO_SHA1));
-                       public->destroy(public);
-               }
-               
-               /* list CRL URIs */
-               {
-                       bool first = TRUE;
-                       char *crluri;
-                       enumerator_t *enumerator;
-
-                       enumerator = section->crl->create_enumerator(section->crl);
-                       while (enumerator->enumerate(enumerator, (void**)&crluri))
-                       {
-                               if (first)
-                               {
-                                       fprintf(out, "  crluris:  ");
-                                       first = FALSE;
-                               }
-                               else
-                               {
-                                       fprintf(out, "            ");
-                               }
-                               fprintf(out, "'%s'\n", crluri);
-                       }
-                       enumerator->destroy(enumerator);
-               }
-
-               /* list OCSP URIs */
-               {
-                       bool first = TRUE;
-                       char *ocspuri;
-                       enumerator_t *enumerator;
-
-                       enumerator = section->ocsp->create_enumerator(section->ocsp);
-                       while (enumerator->enumerate(enumerator, (void**)&ocspuri))
-                       {
-                               if (first)
-                               {
-                                       fprintf(out, "  ocspuris: ");
-                                       first = FALSE;
-                               }
-                               else
-                               {
-                                       fprintf(out, "            ");
-                               }
-                               fprintf(out, "'%s'\n", ocspuri);
-                       }
-                       enumerator->destroy(enumerator);
-               }
-       }
-       enumerator->destroy(enumerator);
-       this->ca_creds.mutex->unlock(this->ca_creds.mutex);
-}
-
-/**
- * list various information
- */
-static void stroke_list(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       if (msg->list.flags & LIST_CERTS)
-       {
-               stroke_list_certs("X.509 End Entity Certificates",
-                                                 0, msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_CACERTS)
-       {
-               stroke_list_certs("X.509 CA Certificates",
-                                                 X509_CA, msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_OCSPCERTS)
-       {
-               stroke_list_certs("X.509 OCSP Signer Certificates",
-                                                 X509_OCSP_SIGNER, msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_AACERTS)
-       {
-               stroke_list_certs("X.509 AA Certificates",
-                                                 X509_AA, msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_ACERTS)
-       {
-
-       }
-       if (msg->list.flags & LIST_CAINFOS)
-       {
-               stroke_list_cainfos(this, out);
-       }
-       if (msg->list.flags & LIST_CRLS)
-       {
-               stroke_list_crls(msg->list.utc, out);
-       }
-       if (msg->list.flags & LIST_OCSP)
-       {
-
-       }
-}
-
-/**
- * reread various information
- */
-static void stroke_reread(private_stroke_t *this,
-                                                 stroke_msg_t *msg, FILE *out)
-{
-       if (msg->reread.flags & REREAD_SECRETS)
-       {
-               DBG1(DBG_CFG, "rereading secrets");
-               load_secrets(this);
-       }
-       if (msg->reread.flags & REREAD_CACERTS)
-       {
-               DBG1(DBG_CFG, "rereading ca certificates from '%s'",
-                        CA_CERTIFICATE_DIR);
-               load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
-       }
-       if (msg->reread.flags & REREAD_OCSPCERTS)
-       {
-               DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
-                        OCSP_CERTIFICATE_DIR);
-               load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
-                        X509_OCSP_SIGNER);
-       }
-       if (msg->reread.flags & REREAD_AACERTS)
-       {
-               DBG1(DBG_CFG, "rereading aa certificates from '%s'",
-                        AA_CERTIFICATE_DIR);
-               load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
-       }
-       if (msg->reread.flags & REREAD_ACERTS)
-       {
-               DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
-                        ATTR_CERTIFICATE_DIR);
-               load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
-       }
-       if (msg->reread.flags & REREAD_CRLS)
-       {
-               DBG1(DBG_CFG, "rereading crls from '%s'",
-                        CRL_DIR);
-               load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
-       }
-}
-
-/**
- * purge various information
- */
-static void stroke_purge(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       /* TODO: flush cache */
-}
-
-signal_t get_signal_from_logtype(char *type)
-{
-       if      (strcasecmp(type, "any") == 0) return SIG_ANY;
-       else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
-       else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
-       else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
-       else if (strcasecmp(type, "job") == 0) return DBG_JOB;
-       else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
-       else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
-       else if (strcasecmp(type, "net") == 0) return DBG_NET;
-       else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
-       else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
-       else return -1;
-}
-
-/**
- * set the verbosity debug output
- */
-static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg, FILE *out)
-{
-       signal_t signal;
-       
-       pop_string(msg, &(msg->loglevel.type));
-       DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
-                msg->loglevel.level, msg->loglevel.type);
-       
-       signal = get_signal_from_logtype(msg->loglevel.type);
-       if (signal < 0)
-       {
-               fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
-               return;
-       }
-       
-       charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
-       charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
-}
-
-typedef struct stroke_job_context_t stroke_job_context_t;
-
-/** job context to pass to processing thread */
-struct stroke_job_context_t {
-
-       /** file descriptor to read from */
-       int fd;
-       
-       /** global stroke interface */
-       private_stroke_t *this;
-};
-
-/**
- * destroy a job context
- */
-static void stroke_job_context_destroy(stroke_job_context_t *this)
-{
-       close(this->fd);
-       free(this);
-}
-
-/**
- * process a stroke request from the socket pointed by "fd"
- */
-static job_requeue_t stroke_process(stroke_job_context_t *ctx)
-{
-       stroke_msg_t *msg;
-       u_int16_t msg_length;
-       ssize_t bytes_read;
-       FILE *out;
-       private_stroke_t *this = ctx->this;
-       int strokefd = ctx->fd;
-       
-       /* peek the length */
-       bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
-       if (bytes_read != sizeof(msg_length))
-       {
-               DBG1(DBG_CFG, "reading length of stroke message failed: %s",
-                        strerror(errno));
-               close(strokefd);
-               return JOB_REQUEUE_NONE;
-       }
-       
-       /* read message */
-       msg = malloc(msg_length);
-       bytes_read = recv(strokefd, msg, msg_length, 0);
-       if (bytes_read != msg_length)
-       {
-               DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
-               close(strokefd);
-               return JOB_REQUEUE_NONE;
-       }
-       
-       out = fdopen(strokefd, "w");
-       if (out == NULL)
-       {
-               DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
-               close(strokefd);
-               free(msg);
-               return JOB_REQUEUE_NONE;
-       }
-       
-       DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
-       
-       /* the stroke_* functions are blocking, as they listen on the bus. Add
-        * cancellation handlers. */
-       pthread_cleanup_push((void*)fclose, out);
-       pthread_cleanup_push(free, msg);
-       
-       switch (msg->type)
-       {
-               case STR_INITIATE:
-                       stroke_initiate(this, msg, out);
-                       break;
-               case STR_ROUTE:
-                       stroke_route(this, msg, out);
-                       break;
-               case STR_UNROUTE:
-                       stroke_unroute(this, msg, out);
-                       break;
-               case STR_TERMINATE:
-                       stroke_terminate(this, msg, out);
-                       break;
-               case STR_STATUS:
-                       stroke_status(this, msg, out, FALSE);
-                       break;
-               case STR_STATUS_ALL:
-                       stroke_status(this, msg, out, TRUE);
-                       break;
-               case STR_ADD_CONN:
-                       stroke_add_conn(this, msg, out);
-                       break;
-               case STR_DEL_CONN:
-                       stroke_del_conn(this, msg, out);
-                       break;
-               case STR_ADD_CA:
-                       stroke_add_ca(this, msg, out);
-                       break;
-               case STR_DEL_CA:
-                       stroke_del_ca(this, msg, out);
-                       break;
-               case STR_LOGLEVEL:
-                       stroke_loglevel(this, msg, out);
-                       break;
-               case STR_LIST:
-                       stroke_list(this, msg, out);
-                       break;
-               case STR_REREAD:
-                       stroke_reread(this, msg, out);
-                       break;
-               case STR_PURGE:
-                       stroke_purge(this, msg, out);
-                       break;
-               default:
-                       DBG1(DBG_CFG, "received unknown stroke");
-       }
-       /* remove and execute cancellation handlers */
-       pthread_cleanup_pop(1);
-       pthread_cleanup_pop(1);
-       
-       return JOB_REQUEUE_NONE;
-}
-
-/**
- * Implementation of private_stroke_t.stroke_receive.
- */
-static job_requeue_t stroke_receive(private_stroke_t *this)
-{
-       struct sockaddr_un strokeaddr;
-       int strokeaddrlen = sizeof(strokeaddr);
-       int strokefd;
-       int oldstate;
-       callback_job_t *job;
-       stroke_job_context_t *ctx;
-       
-       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-       strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
-       pthread_setcancelstate(oldstate, NULL);
-       
-       if (strokefd < 0)
-       {
-               DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
-               return JOB_REQUEUE_FAIR;
-       }
-       
-       ctx = malloc_thing(stroke_job_context_t);
-       ctx->fd = strokefd;
-       ctx->this = this;
-       job = callback_job_create((callback_job_cb_t)stroke_process,
-                                                         ctx, (void*)stroke_job_context_destroy, this->job);
-       charon->processor->queue_job(charon->processor, (job_t*)job);
-       
-       return JOB_REQUEUE_FAIR;
-}
-
-/**
- * Implementation of interface_t.destroy.
- */
-static void destroy(private_stroke_t *this)
-{
-       this->job->cancel(this->job);
-       charon->credentials->remove_set(charon->credentials, &this->ca_creds.set);
-       charon->credentials->remove_set(charon->credentials, &this->creds.set);
-       charon->backends->remove_backend(charon->backends, &this->configs.backend);
-       this->ca_creds.sections->destroy_function(this->ca_creds.sections, (void*)ca_section_destroy);
-       this->ca_creds.mutex->destroy(this->ca_creds.mutex);
-       this->creds.certs->destroy_offset(this->creds.certs, offsetof(certificate_t, destroy));
-       this->creds.shared->destroy_offset(this->creds.shared, offsetof(shared_key_t, destroy));
-       this->creds.private->destroy_offset(this->creds.private, offsetof(private_key_t, destroy));
-       this->creds.mutex->destroy(this->creds.mutex);
-       this->configs.list->destroy_offset(this->configs.list, offsetof(peer_cfg_t, destroy));
-       this->configs.mutex->destroy(this->configs.mutex);
-       free(this);
-}
-
-/**
- * initialize and open stroke socket
- */
-static bool open_socket(private_stroke_t *this)
-{
-       struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
-       mode_t old;
-       
-       /* set up unix socket */
-       this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (this->socket == -1)
-       {
-               DBG1(DBG_CFG, "could not create stroke socket");
-               return FALSE;
-       }
-       
-       unlink(socket_addr.sun_path);
-       old = umask(~(S_IRWXU | S_IRWXG));
-       if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
-       {
-               DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
-               close(this->socket);
-               return FALSE;
-       }
-       umask(old);
-       if (chown(socket_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0)
-       {
-               DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
-                        strerror(errno));
-       }
-       
-       if (listen(this->socket, 0) < 0)
-       {
-               DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
-               close(this->socket);
-               unlink(socket_addr.sun_path);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-/**
- * load all certificates from ipsec.d
- */
-static void load_certs(private_stroke_t *this)
-{
-       DBG1(DBG_CFG, "loading ca certificates from '%s'",
-                CA_CERTIFICATE_DIR);
-       load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
-
-       DBG1(DBG_CFG, "loading aa certificates from '%s'",
-                AA_CERTIFICATE_DIR);
-       load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
-
-       DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
-                OCSP_CERTIFICATE_DIR);
-       load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER);
-
-       DBG1(DBG_CFG, "loading attribute certificates from '%s'",
-                ATTR_CERTIFICATE_DIR);
-       load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
-
-       DBG1(DBG_CFG, "loading crls from '%s'",
-                CRL_DIR);
-       load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
-}
-
-/*
- * Described in header-file
- */
-plugin_t *plugin_create()
-{
-       private_stroke_t *this = malloc_thing(private_stroke_t);
-
-       /* public functions */
-       this->public.plugin.destroy = (void (*)(plugin_t*))destroy;
-       
-       if (!open_socket(this))
-       {
-               free(this);
-               return NULL;
-       }
-       
-       this->ca_creds.sections = linked_list_create();
-       this->ca_creds.mutex = mutex_create(MUTEX_RECURSIVE);
-       this->creds.certs = linked_list_create();
-       this->creds.shared = linked_list_create();
-       this->creds.private = linked_list_create();
-       this->creds.mutex = mutex_create(MUTEX_RECURSIVE);
-       this->configs.list = linked_list_create();
-       this->configs.mutex = mutex_create(MUTEX_RECURSIVE);
-       
-       this->ca_creds.set.create_private_enumerator = (void*)return_null;
-       this->ca_creds.set.create_cert_enumerator = (void*)return_null;
-       this->ca_creds.set.create_shared_enumerator = (void*)return_null;
-       this->ca_creds.set.create_cdp_enumerator = (void*)create_cdp_enumerator;
-       charon->credentials->add_set(charon->credentials, &this->ca_creds.set);
-       
-       this->creds.set.create_private_enumerator = (void*)create_private_enumerator;
-       this->creds.set.create_cert_enumerator = (void*)create_cert_enumerator;
-       this->creds.set.create_shared_enumerator = (void*)create_shared_enumerator;
-       this->creds.set.create_cdp_enumerator = (void*)return_null;
-       charon->credentials->add_set(charon->credentials, &this->creds.set);
-
-       load_certs(this);
-       load_secrets(this);
-       
-       this->configs.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
-       this->configs.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
-       this->configs.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
-       charon->backends->add_backend(charon->backends, &this->configs.backend);
-       
-       this->job = callback_job_create((callback_job_cb_t)stroke_receive,
-                                                                       this, NULL, NULL);
-       charon->processor->queue_job(charon->processor, (job_t*)this->job);
-       
-       return &this->public.plugin;
-}
-
diff --git a/src/charon/plugins/stroke/stroke.h b/src/charon/plugins/stroke/stroke.h
deleted file mode 100644 (file)
index b61f410..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * 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.
- *
- * $Id$
- */
-
-/**
- * @defgroup stroke stroke
- * @ingroup cplugins
- *
- * @defgroup stroke_i stroke
- * @{ @ingroup stroke
- */
-#ifndef STROKE_H_
-#define STROKE_H_
-
-#include <plugins/plugin.h>
-
-typedef struct stroke_t stroke_t;
-
-/**
- * strongSwan 2.x style configuration and control interface.
- *
- * Stroke is a home-brewed communication interface inspired by whack. It
- * uses a unix socket (/var/run/charon.ctl).
- */
-struct stroke_t {
-
-       /**
-        * implements plugin interface
-        */
-       plugin_t plugin;
-};
-
-/**
- * Instanciate stroke plugin.
- */
-plugin_t *plugin_create();
-
-#endif /* STROKE_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_ca.c b/src/charon/plugins/stroke/stroke_ca.c
new file mode 100644 (file)
index 0000000..e39dfe3
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_ca.h"
+#include "stroke_cred.h"
+
+#include <utils/mutex.h>
+#include <utils/linked_list.h>
+
+#include <daemon.h>
+
+typedef struct private_stroke_ca_t private_stroke_ca_t;
+
+/**
+ * private data of stroke_ca
+ */
+struct private_stroke_ca_t {
+
+       /**
+        * public functions
+        */
+       stroke_ca_t public;
+       
+       /**
+        * mutex to lock access to list
+        */
+       mutex_t *mutex;
+       
+       /**
+        * list of starters CA sections and its certificates (ca_section_t)
+        */
+       linked_list_t *sections;
+       
+       /**
+        * stroke credentials, stores our CA certificates
+        */
+       stroke_cred_t *cred;
+};
+
+typedef struct ca_section_t ca_section_t;
+
+/**
+ * loaded ipsec.conf CA sections
+ */
+struct ca_section_t {
+
+       /**
+        * name of the CA section
+        */
+       char *name;
+       
+       /**
+        * reference to cert in trusted_credential_t
+        */
+       certificate_t *cert;
+       
+       /**
+        * CRL URIs
+        */
+       linked_list_t *crl;
+       
+       /**
+        * OCSP URIs
+        */
+       linked_list_t *ocsp;
+};
+
+/**
+ * create a new CA section 
+ */
+static ca_section_t *ca_section_create(char *name, certificate_t *cert)
+{
+       ca_section_t *ca = malloc_thing(ca_section_t);
+       
+       ca->name = strdup(name);
+       ca->crl = linked_list_create();
+       ca->ocsp = linked_list_create();
+       ca->cert = cert;
+       return ca;
+}
+
+/**
+ * destroy a ca section entry
+ */
+static void ca_section_destroy(ca_section_t *this)
+{
+       this->crl->destroy_function(this->crl, free);
+       this->ocsp->destroy_function(this->ocsp, free);
+       free(this->name);
+       free(this);
+}
+
+/**
+ * data to pass to create_inner_cdp
+ */
+typedef struct {
+       private_stroke_ca_t *this;
+       certificate_type_t type;
+       identification_t *id;
+} cdp_data_t;
+
+/**
+ * destroy cdp enumerator data and unlock list
+ */
+static void cdp_data_destroy(cdp_data_t *data)
+{
+       data->this->mutex->unlock(data->this->mutex);
+       free(data);
+}
+
+/**
+ * inner enumerator constructor for CDP URIs
+ */
+static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data)
+{
+       public_key_t *public;
+       identification_t *keyid;
+       enumerator_t *enumerator = NULL;
+       linked_list_t *list;
+       
+       if (data->type == CERT_X509_OCSP_RESPONSE)
+       {
+               list = section->ocsp;
+       }
+       else
+       {
+               list = section->crl;
+       }
+
+       public = section->cert->get_public_key(section->cert);
+       if (public)
+       {
+               if (!data->id)
+               {
+                       enumerator = list->create_enumerator(list);
+               }
+               else
+               {
+                       keyid = public->get_id(public, data->id->get_type(data->id));
+                       if (keyid && keyid->matches(keyid, data->id))
+                       {
+                               enumerator = list->create_enumerator(list);             
+                       }
+               }
+               public->destroy(public);
+       }
+       return enumerator;
+}
+
+/**
+ * Implementation of credential_set_t.create_cdp_enumerator.
+ */
+static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
+                                                               certificate_type_t type, identification_t *id)
+{
+       cdp_data_t *data;
+
+       switch (type)
+       {       /* we serve CRLs and OCSP responders */
+               case CERT_X509_CRL:
+               case CERT_X509_OCSP_RESPONSE:
+               case CERT_ANY:
+                       break;
+               default:
+                       return NULL;
+       }
+       data = malloc_thing(cdp_data_t);
+       data->this = this;
+       data->type = type;
+       data->id = id;
+       
+       this->mutex->lock(this->mutex);
+       return enumerator_create_nested(this->sections->create_enumerator(this->sections),
+                                                                       (void*)create_inner_cdp, data,
+                                                                       (void*)cdp_data_destroy);
+}
+/**
+ * Implementation of stroke_ca_t.add.
+ */
+static void add(private_stroke_ca_t *this, stroke_msg_t *msg)
+{
+       certificate_t *cert;
+       ca_section_t *ca;
+       
+       if (msg->add_ca.cacert == NULL)
+       {
+               DBG1(DBG_CFG, "missing cacert parameter");
+               return;
+       }       
+       cert = this->cred->load_ca(this->cred, msg->add_ca.cacert);
+       if (cert)
+       {
+               ca = ca_section_create(msg->add_ca.name, cert);
+               if (msg->add_ca.crluri)
+               {
+                       ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri));
+               }
+               if (msg->add_ca.crluri2)
+               {
+                       ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2));
+               }
+               if (msg->add_ca.ocspuri)
+               {
+                       ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri));
+               }
+               if (msg->add_ca.ocspuri2)
+               {
+                       ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2));
+               }
+               this->mutex->lock(this->mutex);
+               this->sections->insert_last(this->sections, ca);
+               this->mutex->unlock(this->mutex);
+               DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
+       }
+}
+
+/**
+ * Implementation of stroke_ca_t.del.
+ */
+static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
+{
+       enumerator_t *enumerator;
+       ca_section_t *ca = NULL;
+       
+       this->mutex->lock(this->mutex);
+       enumerator = this->sections->create_enumerator(this->sections);
+       while (enumerator->enumerate(enumerator, &ca))
+       {
+               if (streq(ca->name, msg->del_ca.name))
+               {
+                       this->sections->remove_at(this->sections, enumerator);
+                       break;
+               }
+               ca = NULL;
+       }
+       enumerator->destroy(enumerator);
+       this->mutex->unlock(this->mutex);
+       if (ca == NULL)
+       {
+               DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
+               return;
+       }
+       ca_section_destroy(ca);
+       /* TODO: flush cached certs */
+}
+
+/**
+ * list crl or ocsp URIs
+ */
+static void list_uris(linked_list_t *list, char *label, FILE *out)
+{
+       bool first = TRUE;
+       char *uri;
+       enumerator_t *enumerator;
+
+       enumerator = list->create_enumerator(list);
+       while (enumerator->enumerate(enumerator, (void**)&uri))
+       {
+               if (first)
+               {
+                       fprintf(out, label);
+                       first = FALSE;
+               }
+               else
+               {
+                       fprintf(out, "            ");
+               }
+               fprintf(out, "'%s'\n", uri);
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Implementation of stroke_ca_t.list.
+ */
+static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
+{
+       bool first = TRUE;
+       ca_section_t *section;
+       enumerator_t *enumerator;
+       
+       this->mutex->lock(this->mutex);
+       enumerator = this->sections->create_enumerator(this->sections);
+       while (enumerator->enumerate(enumerator, (void**)&section))
+       {
+               certificate_t *cert = section->cert;
+               public_key_t *public = cert->get_public_key(cert);
+
+               if (first)
+               {
+                       fprintf(out, "\n");
+                       fprintf(out, "List of CA Information Sections:\n");
+                       first = FALSE;
+               }
+               fprintf(out, "\n");
+               fprintf(out, "  authname: %D\n", cert->get_subject(cert));
+
+               /* list authkey and keyid */
+               if (public)
+               {
+                       fprintf(out, "  authkey:   %D\n",
+                                       public->get_id(public, ID_PUBKEY_SHA1));
+                       fprintf(out, "  keyid:     %D\n",
+                                       public->get_id(public, ID_PUBKEY_INFO_SHA1));
+                       public->destroy(public);
+               }
+               list_uris(section->crl, "  crluris:  ", out);
+               list_uris(section->ocsp, "  ocspuris: ", out);
+       }
+       enumerator->destroy(enumerator);
+       this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of stroke_ca_t.destroy
+ */
+static void destroy(private_stroke_ca_t *this)
+{
+       this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
+{
+       private_stroke_ca_t *this = malloc_thing(private_stroke_ca_t);
+       
+       this->public.set.create_private_enumerator = (void*)return_null;
+       this->public.set.create_cert_enumerator = (void*)return_null;
+       this->public.set.create_shared_enumerator = (void*)return_null;
+       this->public.set.create_cdp_enumerator = (void*)create_cdp_enumerator;
+       this->public.add = (void(*)(stroke_ca_t*, stroke_msg_t *msg))add;
+       this->public.del = (void(*)(stroke_ca_t*, stroke_msg_t *msg))del;
+       this->public.list = (void(*)(stroke_ca_t*, stroke_msg_t *msg, FILE *out))list;
+       this->public.destroy = (void(*)(stroke_ca_t*))destroy;
+       
+       this->sections = linked_list_create();
+       this->mutex = mutex_create(MUTEX_RECURSIVE);
+       this->cred = cred;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_ca.h b/src/charon/plugins/stroke/stroke_ca.h
new file mode 100644 (file)
index 0000000..5633196
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_ca stroke_ca
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_CA_H_
+#define STROKE_CA_H_
+
+#include <stroke_msg.h>
+
+#include "stroke_cred.h"
+
+typedef struct stroke_ca_t stroke_ca_t;
+
+/**
+ * ipsec.conf ca section handling.
+ */
+struct stroke_ca_t {
+
+       /**
+        * Implements credential_set_t
+        */
+       credential_set_t set;
+       
+       /**
+        * Add a CA to the set using a stroke_msg_t.
+        *
+        * @param msg           stroke message containing CA info
+        */
+       void (*add)(stroke_ca_t *this, stroke_msg_t *msg);
+       
+       /**
+        * Remove a CA from the set using a stroke_msg_t.
+        *
+        * @param msg           stroke message containing CA info
+        */
+       void (*del)(stroke_ca_t *this, stroke_msg_t *msg);
+       
+       /**
+        * List CA sections to stroke console.
+        *
+        * @param msg           stroke message
+        */
+       void (*list)(stroke_ca_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+     * Destroy a stroke_ca instance.
+     */
+    void (*destroy)(stroke_ca_t *this);
+};
+
+/**
+ * Create a stroke_ca instance.
+ */
+stroke_ca_t *stroke_ca_create(stroke_cred_t *cred);
+
+#endif /* STROKE_CA_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c
new file mode 100644 (file)
index 0000000..c8ab12c
--- /dev/null
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_config.h"
+
+#include <daemon.h>
+#include <utils/mutex.h>
+
+typedef struct private_stroke_config_t private_stroke_config_t;
+
+/**
+ * private data of stroke_config
+ */
+struct private_stroke_config_t {
+
+       /**
+        * public functions
+        */
+       stroke_config_t public;
+       
+       /**
+        * list of peer_cfg_t
+        */
+       linked_list_t *list;
+       
+       /**
+        * mutex to lock config list
+        */
+       mutex_t *mutex;
+       
+       /**
+        * credentials
+        */
+       stroke_cred_t *cred;
+};
+
+/**
+ * data to pass peer_filter
+ */
+typedef struct {
+       private_stroke_config_t *this;
+       identification_t *me;
+       identification_t *other;
+} peer_data_t;
+
+/**
+ * destroy id enumerator data and unlock list
+ */
+static void peer_data_destroy(peer_data_t *data)
+{
+       data->this->mutex->unlock(data->this->mutex);
+       free(data);
+}
+
+/**
+ * filter function for peer configs
+ */
+static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out)
+{
+       bool match_me = FALSE, match_other = FALSE;
+       identification_t *me, *other;
+       
+       me = (*in)->get_my_id(*in);
+       other = (*in)->get_other_id(*in);
+       
+       /* own ID may have wildcards in data (no IDr payload) or in config */
+       match_me = (!data->me || data->me->matches(data->me, me) ||
+                               me->matches(me, data->me));
+       /* others ID has wildcards in config only */
+       match_other = (!data->other || data->other->matches(data->other, other));
+       
+       if (match_me && match_other)
+       {
+               *out = *in;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Implementation of backend_t.create_peer_cfg_enumerator.
+ */
+static enumerator_t* create_peer_cfg_enumerator(private_stroke_config_t *this,
+                                                                                               identification_t *me,
+                                                                                               identification_t *other)
+{
+       peer_data_t *data;
+       
+       data = malloc_thing(peer_data_t);
+       data->this = this;
+       data->me = me;
+       data->other = other;
+       
+       this->mutex->lock(this->mutex);
+       return enumerator_create_filter(this->list->create_enumerator(this->list),
+                                                                       (void*)peer_filter, data,
+                                                                       (void*)peer_data_destroy);
+}
+
+/**
+ * data to pass ike_filter
+ */
+typedef struct {
+       private_stroke_config_t *this;
+       host_t *me;
+       host_t *other;
+} ike_data_t;
+
+/**
+ * destroy id enumerator data and unlock list
+ */
+static void ike_data_destroy(ike_data_t *data)
+{
+       data->this->mutex->unlock(data->this->mutex);
+       free(data);
+}
+
+/**
+ * filter function for ike configs
+ */
+static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out)
+{
+       ike_cfg_t *ike_cfg;
+       host_t *me, *other;
+       
+       ike_cfg = (*in)->get_ike_cfg(*in);
+       
+       me = ike_cfg->get_my_host(ike_cfg);
+       other = ike_cfg->get_other_host(ike_cfg);
+       if ((!data->me || me->is_anyaddr(me) || me->ip_equals(me, data->me)) &&
+               (!data->other || other->is_anyaddr(other) || other->ip_equals(other, data->other)))
+       {
+               *out = ike_cfg;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Implementation of backend_t.create_ike_cfg_enumerator.
+ */
+static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this,
+                                                                                          host_t *me, host_t *other)
+{
+       ike_data_t *data;
+       
+       data = malloc_thing(ike_data_t);
+       data->this = this;
+       data->me = me;
+       data->other = other;
+       
+       this->mutex->lock(this->mutex);
+       return enumerator_create_filter(this->list->create_enumerator(this->list),
+                                                                       (void*)ike_filter, data,
+                                                                       (void*)ike_data_destroy);
+}
+
+/**
+ * implements backend_t.get_peer_cfg_by_name.
+ */
+static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *name)
+{
+       enumerator_t *e1, *e2;
+       peer_cfg_t *current, *found = NULL;
+       child_cfg_t *child;
+
+       this->mutex->lock(this->mutex);
+       e1 = this->list->create_enumerator(this->list);
+       while (e1->enumerate(e1, &current))
+       {
+        /* compare peer_cfgs name first */
+        if (streq(current->get_name(current), name))
+        {
+            found = current;
+            found->get_ref(found);
+            break;
+        }
+        /* compare all child_cfg names otherwise */
+        e2 = current->create_child_cfg_enumerator(current);
+        while (e2->enumerate(e2, &child))
+        {
+            if (streq(child->get_name(child), name))
+            {
+                found = current;
+                found->get_ref(found);
+                break;
+            }
+        }
+        e2->destroy(e2);
+        if (found)
+        {
+            break;
+        }
+       }
+       e1->destroy(e1);
+       this->mutex->unlock(this->mutex);
+       return found;
+}
+
+/**
+ * check if a certificate has an ID
+ */
+static identification_t *update_peerid(certificate_t *cert, identification_t *id)
+{
+       if (!cert->has_subject(cert, id))
+       {
+               DBG1(DBG_CFG, "  peerid %D not confirmed by certificate, "
+                        "defaulting to subject DN", id);
+               id->destroy(id);
+               id = cert->get_subject(cert);
+               return id->clone(id);
+       }
+       return id;
+}
+
+/**
+ * parse a proposal string, either into ike_cfg or child_cfg
+ */
+static void add_proposals(private_stroke_config_t *this, char *string,
+                                                 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
+{
+       if (string)
+       {
+               char *single;
+               char *strict;
+               proposal_t *proposal;
+               protocol_id_t proto = PROTO_ESP;
+               
+               if (ike_cfg)
+               {
+                       proto = PROTO_IKE;
+               }
+               strict = string + strlen(string) - 1;
+               if (*strict == '!')
+               {
+                       *strict = '\0';
+               }
+               else
+               {
+                       strict = NULL;
+               }
+               while ((single = strsep(&string, ",")))
+               {
+                       proposal = proposal_create_from_string(proto, single);
+                       if (proposal)
+                       {
+                               if (ike_cfg)
+                               {
+                                       ike_cfg->add_proposal(ike_cfg, proposal);
+                               }
+                               else
+                               {
+                                       child_cfg->add_proposal(child_cfg, proposal);
+                               }
+                               continue;
+                       }
+                       DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
+               }
+               if (strict)
+               {
+                       return;
+               }
+               /* add default porposal to the end if not strict */
+       }
+       if (ike_cfg)
+       {
+               ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+       }
+       else
+       {
+               child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+       }
+}
+
+/**
+ * Build an IKE config from a stroke message
+ */
+static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
+{
+       host_t *me = NULL, *other = NULL, *tmp;
+       stroke_end_t tmp_end;
+       ike_cfg_t *ike_cfg;
+       char *interface;
+
+       if (msg->add_conn.me.address)
+       {
+               me = host_create_from_string(msg->add_conn.me.address, IKEV2_UDP_PORT);
+       }
+       if (!me)
+       {
+               DBG1(DBG_CFG, "invalid left host: %s", msg->add_conn.me.address);
+               return NULL;
+       }
+       if (msg->add_conn.other.address)
+       {
+               other = host_create_from_string(msg->add_conn.other.address, IKEV2_UDP_PORT);
+       }
+       if (!other)
+       {
+               DBG1(DBG_CFG, "invalid right host: %s", msg->add_conn.other.address);
+               me->destroy(me);
+               return NULL;
+       }
+       interface = charon->kernel_interface->get_interface(
+                                                                                       charon->kernel_interface, other);
+       if (interface)
+       {
+               DBG2(DBG_CFG, "left is other host, swapping ends");
+               tmp = me;
+               me = other;
+               other = tmp;
+               tmp_end = msg->add_conn.me;
+               msg->add_conn.me = msg->add_conn.other;
+               msg->add_conn.other = tmp_end;
+               free(interface);
+       }
+       else
+       {
+               interface = charon->kernel_interface->get_interface(
+                                                                                               charon->kernel_interface, me);
+               if (!interface)
+               {
+                       DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
+               }
+               else
+               {
+                       free(interface);
+               }
+       }
+       ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
+                                                        msg->add_conn.force_encap, me, other);
+       add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
+       return ike_cfg;                                  
+}
+/**
+ * build a peer_cfg from a stroke msg
+ */
+static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
+                                                                 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
+{
+       identification_t *me, *other, *peer_id = NULL;
+       peer_cfg_t *mediated_by = NULL;
+       host_t *my_vip = NULL, *other_vip = NULL;
+       certificate_t *cert;
+       u_int32_t rekey = 0, reauth = 0, over, jitter;
+       
+       me = identification_create_from_string(msg->add_conn.me.id ?
+                                               msg->add_conn.me.id : msg->add_conn.me.address);
+       if (!me)
+       {
+               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
+               return NULL;
+       }
+       other = identification_create_from_string(msg->add_conn.other.id ?
+                                               msg->add_conn.other.id : msg->add_conn.other.address);
+       if (!other)
+       {
+               DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
+               me->destroy(me);
+               return NULL;
+       }
+       
+       
+#ifdef P2P
+       if (msg->add_conn.p2p.mediation && msg->add_conn.p2p.mediated_by)
+       {
+               DBG1(DBG_CFG, "a mediation connection cannot be a"
+                               " mediated connection at the same time, aborting");
+               me->destroy(me);
+               other->destroy(other);
+               return NULL;
+       }
+       
+       if (msg->add_conn.p2p.mediated_by)
+       {
+               mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
+                                                                                               msg->add_conn.p2p.mediated_by);
+               if (!mediated_by)
+               {
+                       DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
+                                msg->add_conn.p2p.mediated_by);
+                       me->destroy(me);
+                       other->destroy(other);
+                       return NULL;
+               }
+               
+               if (!mediated_by->is_mediation(mediated_by))
+               {
+                       DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
+                                "no mediation connection, aborting", 
+                               msg->add_conn.p2p.mediated_by, msg->add_conn.name);
+                       mediated_by->destroy(mediated_by);
+                       me->destroy(me);
+                       other->destroy(other);
+                       return NULL;
+               }
+       }
+       
+       if (msg->add_conn.p2p.peerid)
+       {
+               peer_id = identification_create_from_string(msg->add_conn.p2p.peerid);
+               if (!peer_id)
+               {
+                       DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.p2p.peerid);
+                       mediated_by->destroy(mediated_by);
+                       me->destroy(me);
+                       other->destroy(other);
+                       return NULL;
+               }
+       }
+       else
+       {
+               /* no peer ID supplied, assume right ID */
+               peer_id = other_id->clone(other_id);
+       }
+#endif /* P2P */
+       
+       if (msg->add_conn.me.cert)
+       {
+               cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
+               if (cert)
+               {
+                       me = update_peerid(cert, me);
+                       cert->destroy(cert);
+               }
+       }
+       if (msg->add_conn.other.cert)
+       {
+               cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
+               if (cert)
+               {
+                       other = update_peerid(cert, other);
+                       cert->destroy(cert);
+               }
+       }
+       jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
+       over = msg->add_conn.rekey.margin;
+       if (msg->add_conn.rekey.reauth)
+       {
+               reauth = msg->add_conn.rekey.ike_lifetime - over;
+       }
+       else
+       {
+               rekey = msg->add_conn.rekey.ike_lifetime - over;
+       }       
+       if (msg->add_conn.me.virtual_ip && msg->add_conn.me.sourceip)
+       {
+               my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
+       }
+       if (msg->add_conn.other.virtual_ip && msg->add_conn.other.sourceip)
+       {
+               other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
+       }
+       return peer_cfg_create(msg->add_conn.name,
+               msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
+               msg->add_conn.me.sendcert, msg->add_conn.auth_method,
+               msg->add_conn.eap_type, msg->add_conn.eap_vendor,
+               msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
+               msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action,
+               my_vip, other_vip, msg->add_conn.p2p.mediation, mediated_by, peer_id);
+}
+
+/**
+ * fill in auth_info from stroke message
+ */
+static void build_auth_info(private_stroke_config_t *this,
+                                                       stroke_msg_t *msg, auth_info_t *auth)
+{
+       identification_t *my_ca = NULL, *other_ca = NULL;
+       bool my_ca_same = FALSE;
+       bool other_ca_same = FALSE;
+       cert_validation_t valid;
+
+       if (msg->add_conn.other.groups)
+       {
+               /* TODO: AC groups */
+       }
+       
+       switch (msg->add_conn.crl_policy)
+       {
+               case CRL_STRICT_YES:
+                       valid = VALIDATION_GOOD;
+                       auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
+                       break;
+               case CRL_STRICT_IFURI:
+                       valid = VALIDATION_SKIPPED;
+                       auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
+                       break;
+               default:
+                       break;
+       }
+       
+       if (msg->add_conn.me.ca)
+       {
+               if (streq(msg->add_conn.me.ca, "%same"))
+               {
+                       my_ca_same = TRUE;
+               }
+               else
+               {
+                       my_ca = identification_create_from_string(msg->add_conn.me.ca);
+               }
+       }
+       if (msg->add_conn.other.ca)
+       {
+               if (streq(msg->add_conn.other.ca, "%same"))
+               {
+                       other_ca_same = TRUE;
+               }
+               else
+               {
+                       other_ca = identification_create_from_string(msg->add_conn.other.ca);
+               }
+       }
+       if (other_ca_same && my_ca)
+       {
+               other_ca = my_ca->clone(my_ca);
+       }
+       else if (my_ca_same && other_ca)
+       {
+               my_ca = other_ca->clone(other_ca);
+       }
+       
+       if (other_ca)
+       {
+               DBG2(DBG_CFG, "  other ca: %D", other_ca);
+               certificate_t *cert = charon->credentials->get_cert(charon->credentials, 
+                                                                       CERT_X509, KEY_ANY, other_ca, TRUE);
+               if (cert)
+               {
+                       auth->add_item(auth, AUTHZ_CA_CERT, cert);
+                       cert->destroy(cert);
+               }
+               else
+               {
+                       auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
+               }
+               other_ca->destroy(other_ca);
+       }
+       if (my_ca)
+       {
+               DBG2(DBG_CFG, "  my ca:    %D", my_ca);
+               certificate_t *cert = charon->credentials->get_cert(charon->credentials, 
+                                                                       CERT_X509, KEY_ANY, my_ca, TRUE);
+               if (cert)
+               {
+                       auth->add_item(auth, AUTHN_CA_CERT, cert);
+                       cert->destroy(cert);
+               }
+               else
+               {
+                       auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
+               }
+               my_ca->destroy(my_ca);
+       }
+}
+
+/**
+ * build a traffic selector from a stroke_end
+ */
+static traffic_selector_t *build_ts(private_stroke_config_t *this,
+                                                                       stroke_end_t *end)
+{
+       if (end->tohost)
+       {
+               return traffic_selector_create_dynamic(end->protocol,
+                                       end->port ? end->port : 0, end->port ? end->port : 65535);
+       }
+       else
+       {
+               host_t *net;
+               
+               net = host_create_from_string(end->subnet ? end->subnet : end->address,
+                                                                         IKEV2_UDP_PORT);
+               if (!net)
+               {
+                       DBG1(DBG_CFG, "invalid subnet: %s", end->subnet);
+                       return NULL;
+               }
+               return traffic_selector_create_from_subnet(net,
+                               end->subnet ? end->subnet_mask : 0, end->protocol, end->port);
+       }
+}
+
+/**
+ * build a child config from the stroke message
+ */
+static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
+                                                                       stroke_msg_t *msg)
+{
+       child_cfg_t *child_cfg;
+       traffic_selector_t *ts;
+       
+       child_cfg = child_cfg_create(
+                               msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
+                               msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
+                               msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, 
+                               msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
+                               msg->add_conn.mode);
+       
+       ts = build_ts(this, &msg->add_conn.me);
+       if (!ts)
+       {
+               child_cfg->destroy(child_cfg);
+               return NULL;
+       }
+       child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
+       
+       ts = build_ts(this, &msg->add_conn.other);
+       if (!ts)
+       {
+               child_cfg->destroy(child_cfg);
+               return NULL;
+       }
+       child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+       
+       add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
+       
+       return child_cfg;
+}
+
+/**
+ * Implementation of stroke_config_t.add.
+ */
+static void add(private_stroke_config_t *this, stroke_msg_t *msg)
+{
+       ike_cfg_t *ike_cfg, *existing_ike;
+       peer_cfg_t *peer_cfg, *existing;
+       child_cfg_t *child_cfg;
+       enumerator_t *enumerator;
+       bool use_existing = FALSE;
+
+       ike_cfg = build_ike_cfg(this, msg);
+       if (!ike_cfg)
+       {
+               return;
+       }
+       peer_cfg = build_peer_cfg(this, msg, ike_cfg);
+       if (!peer_cfg)
+       {
+               ike_cfg->destroy(ike_cfg);
+               return;
+       }
+       
+       build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg));
+       enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
+       while (enumerator->enumerate(enumerator, &existing))
+       {
+               existing_ike = existing->get_ike_cfg(existing);
+               if (existing->equals(existing, peer_cfg) &&
+                       existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
+               {
+                       use_existing = TRUE;
+                       peer_cfg->destroy(peer_cfg);
+                       peer_cfg = existing;
+                       peer_cfg->get_ref(peer_cfg);
+                       DBG1(DBG_CFG, "added child to existing configuration '%s'",
+                                peer_cfg->get_name(peer_cfg));
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       
+       child_cfg = build_child_cfg(this, msg);
+       if (!child_cfg)
+       {
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       peer_cfg->add_child_cfg(peer_cfg, child_cfg);
+       
+       if (use_existing)
+       {
+               peer_cfg->destroy(peer_cfg);
+       }
+       else
+       {
+               /* add config to backend */
+               DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]", msg->add_conn.name,
+                        ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
+                        ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
+               this->mutex->lock(this->mutex);
+               this->list->insert_last(this->list, peer_cfg);
+               this->mutex->unlock(this->mutex);
+       }
+}
+
+/**
+ * Implementation of stroke_config_t.del.
+ */
+static void del(private_stroke_config_t *this, stroke_msg_t *msg)
+{
+       enumerator_t *enumerator, *children;
+       peer_cfg_t *peer;
+       child_cfg_t *child;
+       
+       this->mutex->lock(this->mutex);
+       enumerator = this->list->create_enumerator(this->list);
+       while (enumerator->enumerate(enumerator, (void**)&peer))
+       {
+               /* remove peer config with such a name */
+               if (streq(peer->get_name(peer), msg->del_conn.name))
+               {
+                       this->list->remove_at(this->list, enumerator);
+                       peer->destroy(peer);
+                       continue;
+               }
+               /* remove any child with such a name */
+               children = peer->create_child_cfg_enumerator(peer);
+               while (children->enumerate(children, &child))
+               {
+                       if (streq(child->get_name(child), msg->del_conn.name))
+                       {
+                               peer->remove_child_cfg(peer, enumerator);
+                               child->destroy(child);
+                       }
+               }
+               children->destroy(children);
+       }
+       enumerator->destroy(enumerator);
+       this->mutex->unlock(this->mutex);
+       
+       DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
+}
+
+/**
+ * Implementation of stroke_config_t.destroy
+ */
+static void destroy(private_stroke_config_t *this)
+{
+       this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_config_t *stroke_config_create(stroke_cred_t *cred)
+{
+       private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
+       
+       this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
+       this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
+       this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
+       this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add;
+       this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del;
+       this->public.destroy = (void(*)(stroke_config_t*))destroy;
+       
+       this->list = linked_list_create();
+       this->mutex = mutex_create(MUTEX_RECURSIVE);
+       this->cred = cred;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_config.h b/src/charon/plugins/stroke/stroke_config.h
new file mode 100644 (file)
index 0000000..478fa38
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_config stroke_config
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_CONFIG_H_
+#define STROKE_CONFIG_H_
+
+#include <config/backend.h>
+#include <stroke_msg.h>
+#include "stroke_cred.h"
+
+typedef struct stroke_config_t stroke_config_t;
+
+/**
+ * Stroke in-memory configuration backend
+ */
+struct stroke_config_t {
+
+       /**
+        * Implements the backend_t interface
+        */
+       backend_t backend;
+       
+       /**
+        * Add a configuration to the backend.
+        *
+        * @param msg           received stroke message containing config
+        */
+       void (*add)(stroke_config_t *this, stroke_msg_t *msg);
+       
+       /**
+        * Remove a configuration from the backend.
+        *
+        * @param msg           received stroke message containing config name
+        */
+       void (*del)(stroke_config_t *this, stroke_msg_t *msg);
+       
+       /**
+     * Destroy a stroke_config instance.
+     */
+    void (*destroy)(stroke_config_t *this);
+};
+
+/**
+ * Create a stroke_config instance.
+ */
+stroke_config_t *stroke_config_create(stroke_cred_t *cred);
+
+#endif /* STROKE_CONFIG_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_control.c b/src/charon/plugins/stroke/stroke_control.c
new file mode 100644 (file)
index 0000000..f6707b3
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_control.h"
+
+#include <daemon.h>
+
+typedef struct private_stroke_control_t private_stroke_control_t;
+
+/**
+ * private data of stroke_control
+ */
+struct private_stroke_control_t {
+
+       /**
+        * public functions
+        */
+       stroke_control_t public;
+};
+
+
+typedef struct stroke_log_info_t stroke_log_info_t;
+
+/**
+ * helper struct to say what and where to log when using controller callback
+ */
+struct stroke_log_info_t {
+
+       /**
+        * level to log up to
+        */
+       level_t level;
+       
+       /**
+        * where to write log
+        */
+       FILE* out;
+};
+
+/**
+ * logging to the stroke interface
+ */
+static bool stroke_log(stroke_log_info_t *info, signal_t signal, level_t level,
+                                          ike_sa_t *ike_sa, char *format, va_list args)
+{
+       if (level <= info->level)
+       {
+               if (vfprintf(info->out, format, args) < 0 ||
+                       fprintf(info->out, "\n") < 0 ||
+                       fflush(info->out) != 0)
+               {
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+/**
+ * get the child_cfg with the same name as the peer cfg
+ */
+static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
+{
+       child_cfg_t *current, *found = NULL;
+       enumerator_t *enumerator;
+       
+       enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (streq(current->get_name(current), name))
+               {
+                       found = current;
+                       found->get_ref(found);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
+/**
+ * Implementation of stroke_control_t.initiate.
+ */
+static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg;
+       stroke_log_info_t info;
+       
+       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
+                                                                                                         msg->initiate.name);
+       if (peer_cfg == NULL)
+       {
+               DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name);
+               return;
+       }
+       if (peer_cfg->get_ike_version(peer_cfg) != 2)
+       {
+               DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
+                        peer_cfg->get_ike_version(peer_cfg));
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
+       if (child_cfg == NULL)
+       {
+               DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name);
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       if (msg->output_verbosity < 0)
+       {
+               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+                                                                        NULL, NULL);
+       }
+       else
+       {
+               info.out = out;
+               info.level = msg->output_verbosity;
+               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
+                                                                        (controller_cb_t)stroke_log, &info);
+       }
+}
+
+/**
+ * Implementation of stroke_control_t.terminate.
+ */
+static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       char *string, *pos = NULL, *name = NULL;
+       u_int32_t id = 0;
+       bool child;
+       int len;
+       ike_sa_t *ike_sa;
+       iterator_t *iterator;
+       stroke_log_info_t info;
+       
+       string = msg->terminate.name;
+       
+       len = strlen(string);
+       if (len < 1)
+       {
+               DBG1(DBG_CFG, "error parsing string");
+               return;
+       }
+       switch (string[len-1])
+       {
+               case '}':
+                       child = TRUE;
+                       pos = strchr(string, '{');
+                       break;
+               case ']':
+                       child = FALSE;
+                       pos = strchr(string, '[');
+                       break;
+               default:
+                       name = string;
+                       child = FALSE;
+                       break;
+       }
+       
+       if (name)
+       {
+               /* is a single name */
+       }
+       else if (pos == string + len - 2)
+       {       /* is name[] or name{} */
+               string[len-2] = '\0';
+               name = string;
+       }
+       else
+       {       /* is name[123] or name{23} */
+               string[len-1] = '\0';
+               id = atoi(pos + 1);
+               if (id == 0)
+               {
+                       DBG1(DBG_CFG, "error parsing string");
+                       return;
+               }
+       }
+       
+       info.out = out;
+       info.level = msg->output_verbosity;
+       
+       iterator = charon->controller->create_ike_sa_iterator(charon->controller);
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               child_sa_t *child_sa;
+               iterator_t *children;
+               
+               if (child)
+               {
+                       children = ike_sa->create_child_sa_iterator(ike_sa);
+                       while (children->iterate(children, (void**)&child_sa))
+                       {
+                               if ((name && streq(name, child_sa->get_name(child_sa))) ||
+                                       (id && id == child_sa->get_reqid(child_sa)))
+                               {
+                                       id = child_sa->get_reqid(child_sa);
+                                       children->destroy(children);
+                                       iterator->destroy(iterator);
+                                       
+                                       charon->controller->terminate_child(charon->controller, id,
+                                                                       (controller_cb_t)stroke_log, &info);
+                                       return;
+                               }
+                       }
+                       children->destroy(children);
+               }
+               else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
+                                (id && id == ike_sa->get_unique_id(ike_sa)))
+               {
+                       id = ike_sa->get_unique_id(ike_sa);
+                       /* unlock manager first */
+                       iterator->destroy(iterator);
+                       
+                       charon->controller->terminate_ike(charon->controller, id,
+                                                                       (controller_cb_t)stroke_log, &info);
+                       return;
+               }
+               
+       }
+       iterator->destroy(iterator);
+       DBG1(DBG_CFG, "no such SA found");
+
+}
+
+/**
+ * Implementation of stroke_control_t.route.
+ */
+static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       peer_cfg_t *peer_cfg;
+       child_cfg_t *child_cfg;
+       stroke_log_info_t info;
+       
+       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
+                                                                                                         msg->route.name);
+       if (peer_cfg == NULL)
+       {
+               fprintf(out, "no config named '%s'\n", msg->route.name);
+               return;
+       }
+       if (peer_cfg->get_ike_version(peer_cfg) != 2)
+       {
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
+       if (child_cfg == NULL)
+       {
+               fprintf(out, "no child config named '%s'\n", msg->route.name);
+               peer_cfg->destroy(peer_cfg);
+               return;
+       }
+       
+       info.out = out;
+       info.level = msg->output_verbosity;
+       charon->controller->route(charon->controller, peer_cfg, child_cfg,
+                                                         (controller_cb_t)stroke_log, &info);
+       peer_cfg->destroy(peer_cfg);
+       child_cfg->destroy(child_cfg);
+}
+
+/**
+ * Implementation of stroke_control_t.unroute.
+ */
+static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
+{
+       char *name;
+       ike_sa_t *ike_sa;
+       iterator_t *iterator;
+       stroke_log_info_t info;
+       
+       name = msg->terminate.name;
+       
+       info.out = out;
+       info.level = msg->output_verbosity;
+       
+       iterator = charon->controller->create_ike_sa_iterator(charon->controller);
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               child_sa_t *child_sa;
+               iterator_t *children;
+               u_int32_t id;
+
+               children = ike_sa->create_child_sa_iterator(ike_sa);
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
+                               streq(name, child_sa->get_name(child_sa)))
+                       {
+                               id = child_sa->get_reqid(child_sa);
+                               children->destroy(children);
+                               iterator->destroy(iterator);
+                               charon->controller->unroute(charon->controller, id,
+                                                               (controller_cb_t)stroke_log, &info);
+                               return;
+                       }
+               }
+               children->destroy(children);
+       }
+       iterator->destroy(iterator);
+       DBG1(DBG_CFG, "no such SA found");
+}
+
+/**
+ * Implementation of stroke_control_t.destroy
+ */
+static void destroy(private_stroke_control_t *this)
+{
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_control_t *stroke_control_create()
+{
+       private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
+       
+       this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
+       this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
+       this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
+       this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
+       this->public.destroy = (void(*)(stroke_control_t*))destroy;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_control.h b/src/charon/plugins/stroke/stroke_control.h
new file mode 100644 (file)
index 0000000..9176792
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_control stroke_control
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_CONTROL_H_
+#define STROKE_CONTROL_H_
+
+#include <stroke_msg.h>
+#include <library.h>
+#include <stdio.h>
+
+typedef struct stroke_control_t stroke_control_t;
+
+/**
+ * Process stroke control messages
+ */
+struct stroke_control_t {
+
+       /**
+        * Initiate a connection.
+        *
+        * @param msg           stroke message
+        */
+       void (*initiate)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+        * Terminate a connection.
+        *
+        * @param msg           stroke message
+        */
+       void (*terminate)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+        * Route a connection.
+        *
+        * @param msg           stroke message
+        */
+       void (*route)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+        * Unroute a connection.
+        *
+        * @param msg           stroke message
+        */
+       void (*unroute)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+     * Destroy a stroke_control instance.
+     */
+    void (*destroy)(stroke_control_t *this);
+};
+
+/**
+ * Create a stroke_control instance.
+ */
+stroke_control_t *stroke_control_create();
+
+#endif /* STROKE_CONTROL_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_cred.c b/src/charon/plugins/stroke/stroke_cred.c
new file mode 100644 (file)
index 0000000..94c7984
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_cred.h"
+#include "stroke_shared_key.h"
+
+#include <sys/stat.h>
+
+#include <credentials/certificates/x509.h>
+#include <credentials/certificates/crl.h>
+#include <credentials/certificates/ac.h>
+#include <utils/linked_list.h>
+#include <utils/mutex.h>
+#include <utils/lexparser.h>
+#include <asn1/ttodata.h>
+#include <asn1/pem.h>
+#include <daemon.h>
+
+/* configuration directories and files */
+#define CONFIG_DIR IPSEC_CONFDIR
+#define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
+#define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
+#define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
+#define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
+#define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
+#define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
+#define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
+#define CRL_DIR IPSEC_D_DIR "/crls"
+#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
+
+typedef struct private_stroke_cred_t private_stroke_cred_t;
+
+/**
+ * private data of stroke_cred
+ */
+struct private_stroke_cred_t {
+
+       /**
+        * public functions
+        */
+       stroke_cred_t public;
+       
+       /**
+        * list of trusted peer/signer/CA certificates (certificate_t)
+        */
+       linked_list_t *certs;
+
+       /**
+        * list of shared secrets (private_shared_key_t)
+        */
+       linked_list_t *shared;
+
+       /**
+        * list of private keys (private_key_t)
+        */
+       linked_list_t *private;
+       
+       /**
+        * mutex to lock lists above
+        */
+       mutex_t *mutex;
+};
+
+/**
+ * data to pass to various filters
+ */
+typedef struct {
+       private_stroke_cred_t *this;
+       identification_t *id;
+} id_data_t;
+
+/**
+ * destroy id enumerator data and unlock list
+ */
+static void id_data_destroy(id_data_t *data)
+{
+       data->this->mutex->unlock(data->this->mutex);
+       free(data);
+}
+
+/**
+ * filter function for private key enumerator
+ */
+static bool private_filter(id_data_t *data,
+                                                  private_key_t **in, private_key_t **out)
+{
+       identification_t *candidate;
+       
+       if (data->id == NULL)
+       {
+               *out = *in;
+               return TRUE;
+       }
+       candidate = (*in)->get_id(*in, data->id->get_type(data->id));
+       if (candidate && data->id->equals(data->id, candidate))
+       {
+               *out = *in;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Implements credential_set_t.create_private_enumerator
+ */
+static enumerator_t* create_private_enumerator(private_stroke_cred_t *this,
+                                                       key_type_t type, identification_t *id)
+{
+       id_data_t *data;
+
+       if (type != KEY_RSA && type != KEY_ANY)
+       {       /* we only have RSA keys */
+               return NULL;
+       }
+       data = malloc_thing(id_data_t);
+       data->this = this;
+       data->id = id;
+       
+       this->mutex->lock(this->mutex);
+       return enumerator_create_filter(this->private->create_enumerator(this->private),
+                                                                       (void*)private_filter, data,
+                                                                       (void*)id_data_destroy);
+}
+
+/**
+ * filter function for certs enumerator
+ */
+static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **out)
+{
+       public_key_t *public;
+       identification_t *candidate;
+       certificate_t *cert = *in;
+       
+       if (cert->get_type(cert) == CERT_X509_CRL)
+       {
+               return FALSE;
+       }
+
+       if (data->id == NULL || cert->has_subject(cert, data->id))
+       {
+               *out = *in;
+               return TRUE;
+       }
+       
+       public = (cert)->get_public_key(cert);
+       if (public)
+       {
+               candidate = public->get_id(public, data->id->get_type(data->id));
+               if (candidate && data->id->equals(data->id, candidate))
+               {
+                       public->destroy(public);
+                       *out = *in;
+                       return TRUE;
+               }
+               public->destroy(public);
+       }
+       return FALSE;
+}
+
+/**
+ * filter function for crl enumerator
+ */
+static bool crl_filter(id_data_t *data, certificate_t **in, certificate_t **out)
+{
+       certificate_t *cert = *in;
+       
+       if (cert->get_type(cert) != CERT_X509_CRL)
+       {
+               return FALSE;
+       }
+
+       if (data->id == NULL || cert->has_issuer(cert, data->id))
+       {
+               *out = *in;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/**
+ * Implements credential_set_t.create_cert_enumerator
+ */
+static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this,
+                                                       certificate_type_t cert, key_type_t key,
+                                                       identification_t *id, bool trusted)
+{
+       id_data_t *data;
+       
+       if (cert == CERT_X509_CRL)
+       {
+               if (trusted)
+               {
+                       return FALSE;
+               }
+               
+               data = malloc_thing(id_data_t);
+               data->this = this;
+               data->id = id;
+               
+               this->mutex->lock(this->mutex);
+               return enumerator_create_filter(this->certs->create_enumerator(this->certs),
+                                                                               (void*)crl_filter, data,
+                                                                               (void*)id_data_destroy);
+       }
+       if (cert != CERT_X509 && cert != CERT_ANY)
+       {       /* we only have X509 certificates. TODO: ACs? */
+               return NULL;
+       }
+       if (key != KEY_RSA && key != KEY_ANY)
+       {       /* we only have RSA keys */
+               return NULL;
+       }
+       data = malloc_thing(id_data_t);
+       data->this = this;
+       data->id = id;
+       
+       this->mutex->lock(this->mutex);
+       return enumerator_create_filter(this->certs->create_enumerator(this->certs),
+                                                                       (void*)certs_filter, data,
+                                                                       (void*)id_data_destroy);
+}
+
+typedef struct {
+       private_stroke_cred_t *this;
+       identification_t *me;
+       identification_t *other;
+       shared_key_type_t type;
+} shared_data_t;
+
+/**
+ * free shared key enumerator data and unlock list
+ */
+static void shared_data_destroy(shared_data_t *data)
+{
+       data->this->mutex->unlock(data->this->mutex);
+       free(data);
+}
+
+/**
+ * filter function for certs enumerator
+ */
+static bool shared_filter(shared_data_t *data,
+                                                 stroke_shared_key_t **in, shared_key_t **out,
+                                                 void **unused1, id_match_t *me,
+                                                 void **unused2, id_match_t *other)
+{
+       id_match_t my_match, other_match;
+       stroke_shared_key_t *stroke = *in;
+       shared_key_t *shared = &stroke->shared;
+
+       if (data->type != SHARED_ANY && shared->get_type(shared) != data->type)
+       {
+               return FALSE;
+       }
+       
+       my_match = stroke->has_owner(stroke, data->me);
+       other_match = stroke->has_owner(stroke, data->other);
+       if (!my_match && !other_match)
+       {
+               return FALSE;
+       }
+       *out = shared;
+       if (me)
+       {
+               *me = my_match;
+       }
+       if (other)
+       {
+               *other = other_match;
+       }
+       return TRUE;
+}
+
+/**
+ * Implements credential_set_t.create_shared_enumerator
+ */
+static enumerator_t* create_shared_enumerator(private_stroke_cred_t *this, 
+                                                       shared_key_type_t type, identification_t *me,
+                                                       identification_t *other)
+{
+       shared_data_t *data = malloc_thing(shared_data_t);
+       
+       data->this = this;
+       data->me = me;
+       data->other = other;
+       data->type = type;
+       this->mutex->lock(this->mutex);
+       return enumerator_create_filter(this->shared->create_enumerator(this->shared),
+                                                                       (void*)shared_filter, data,
+                                                                       (void*)shared_data_destroy);
+}
+
+/**
+ * Add a certificate to chain
+ */
+static certificate_t* add_cert(private_stroke_cred_t *this, certificate_t *cert)
+{
+       certificate_t *current;
+       enumerator_t *enumerator;
+       bool new = TRUE;        
+
+       this->mutex->lock(this->mutex);
+       enumerator = this->certs->create_enumerator(this->certs);
+       while (enumerator->enumerate(enumerator, (void**)&current))
+       {
+               if (current->equals(current, cert))
+               {
+                       /* cert already in queue */
+                       cert->destroy(cert);
+                       cert = current;
+                       new = FALSE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (new)
+       {
+               this->certs->insert_last(this->certs, cert);
+       }
+       this->mutex->unlock(this->mutex);
+       return cert;
+}
+       
+/**
+ * Implementation of stroke_cred_t.load_ca.
+ */
+static certificate_t* load_ca(private_stroke_cred_t *this, char *filename)
+{
+       certificate_t *cert;
+       char path[PATH_MAX];
+       
+       if (*filename == '/')
+       {
+               snprintf(path, sizeof(path), "%s", filename);
+       }
+       else
+       {
+               snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
+       }
+       
+       cert = lib->creds->create(lib->creds,
+                                                         CRED_CERTIFICATE, CERT_X509,
+                                                         BUILD_FROM_FILE, path,
+                                                         BUILD_X509_FLAG, X509_CA,
+                                                         BUILD_END);
+       if (cert)
+       {
+               return (certificate_t*)add_cert(this, cert);
+       }
+       return NULL;
+}
+
+/**
+ * Add X.509 CRL to chain
+ */
+static void add_crl(private_stroke_cred_t *this, crl_t* crl)
+{
+       certificate_t *current, *cert = &crl->certificate;
+       enumerator_t *enumerator;
+       bool new = TRUE, found = FALSE; 
+
+       this->mutex->lock(this->mutex);
+       enumerator = this->certs->create_enumerator(this->certs);
+       while (enumerator->enumerate(enumerator, (void**)&current))
+       {
+               if (current->get_type(current) == CERT_X509_CRL)
+               {
+                       crl_t *crl_c = (crl_t*)current;
+                       identification_t *authkey = crl->get_authKeyIdentifier(crl);
+                       identification_t *authkey_c = crl_c->get_authKeyIdentifier(crl_c);
+
+                       /* if compare authorityKeyIdentifiers if available */
+                       if (authkey != NULL && authkey_c != NULL &&
+                               authkey->equals(authkey, authkey_c))
+                       {
+                               found = TRUE;
+                       }
+                       else
+                       {
+                               identification_t *issuer = cert->get_issuer(cert);
+                               identification_t *issuer_c = current->get_issuer(current);
+
+                               /* otherwise compare issuer distinguished names */
+                               if (issuer->equals(issuer, issuer_c))
+                               {
+                                       found = TRUE;
+                               }
+                       }
+                       if (found)
+                       {
+                               new = cert->is_newer(cert, current);
+                               if (new)
+                               {
+                                       this->certs->remove_at(this->certs, enumerator);
+                               }
+                               else
+                               {
+                                       cert->destroy(cert);
+                               }
+                               break;
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (new)
+       {
+               this->certs->insert_last(this->certs, cert);
+       }
+       this->mutex->unlock(this->mutex);
+}
+
+/**
+ * Implementation of stroke_cred_t.load_peer.
+ */
+static certificate_t* load_peer(private_stroke_cred_t *this, char *filename)
+{
+       certificate_t *cert;
+       char path[PATH_MAX];
+
+       if (*filename == '/')
+       {
+               snprintf(path, sizeof(path), "%s", filename);
+       }
+       else
+       {
+               snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
+       }
+       
+       cert = lib->creds->create(lib->creds,
+                                                         CRED_CERTIFICATE, CERT_X509,
+                                                         BUILD_FROM_FILE, path,
+                                                         BUILD_X509_FLAG, 0,
+                                                         BUILD_END);
+       if (cert)
+       {
+               cert = add_cert(this, cert);
+               return cert->get_ref(cert);
+       }
+       return NULL;
+}
+
+/**
+ * load trusted certificates from a directory
+ */
+static void load_certdir(private_stroke_cred_t *this, char *path,
+                                                certificate_type_t type, x509_flag_t flag)
+{
+       struct stat st;
+       char *file;
+       
+       enumerator_t *enumerator = enumerator_create_directory(path);
+
+       if (!enumerator)
+       {
+               DBG1(DBG_CFG, "  reading directory failed");
+               return;
+       }
+
+       while (enumerator->enumerate(enumerator, NULL, &file, &st))
+       {
+               certificate_t *cert;
+
+               if (!S_ISREG(st.st_mode))
+               {
+                       /* skip special file */
+                       continue;
+               }
+               switch (type)
+               {
+                       case CERT_X509:
+                               cert = lib->creds->create(lib->creds,
+                                                                                 CRED_CERTIFICATE, CERT_X509,
+                                                                                 BUILD_FROM_FILE, file,
+                                                                                 BUILD_X509_FLAG, flag,
+                                                                                 BUILD_END);
+                               if (cert)
+                               {
+                                       add_cert(this, cert);
+                               }
+                               break;
+                       case CERT_X509_CRL:
+                               cert = lib->creds->create(lib->creds,
+                                                                                 CRED_CERTIFICATE, CERT_X509_CRL,
+                                                                                 BUILD_FROM_FILE, file,
+                                                                                 BUILD_END);
+                               if (cert)
+                               {
+                                       add_crl(this, (crl_t*)cert);
+                               }
+                               break;
+                       case CERT_X509_AC:
+                               cert = lib->creds->create(lib->creds,
+                                                                                 CRED_CERTIFICATE, CERT_X509_AC,
+                                                                                 BUILD_FROM_FILE, file,
+                                                                                 BUILD_END);
+                               if (cert)
+                               {
+                                       cert->destroy(cert);
+                               }
+                               break;
+                       default:
+                               break;  
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Convert a string of characters into a binary secret
+ * A string between single or double quotes is treated as ASCII characters
+ * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
+ */
+static err_t extract_secret(chunk_t *secret, chunk_t *line)
+{
+       chunk_t raw_secret;
+       char delimiter = ' ';
+       bool quotes = FALSE;
+
+       if (!eat_whitespace(line))
+       {
+               return "missing secret";
+       }
+
+       if (*line->ptr == '\'' || *line->ptr == '"')
+       {
+               quotes = TRUE;
+               delimiter = *line->ptr;
+               line->ptr++;  line->len--;
+       }
+
+       if (!extract_token(&raw_secret, delimiter, line))
+       {
+               if (delimiter == ' ')
+               {
+                       raw_secret = *line;
+               }
+               else
+               {
+                       return "missing second delimiter";
+               }
+       }
+
+       if (quotes)
+       {       
+               /* treat as an ASCII string */
+               *secret = chunk_clone(raw_secret);
+       }
+       else
+       {
+               size_t len;
+               err_t ugh;
+
+               /* secret converted to binary form doesn't use more space than the raw_secret */
+               *secret = chunk_alloc(raw_secret.len);
+
+               /* convert from HEX or Base64 to binary */
+               ugh = ttodata(raw_secret.ptr, raw_secret.len, 0, secret->ptr, secret->len, &len);
+
+           if (ugh != NULL)
+               {
+                       chunk_free_randomized(secret);
+                       return ugh;
+               }
+               secret->len = len;
+       }
+       return NULL;
+}
+
+/**
+ * reload ipsec.secrets
+ */
+static void load_secrets(private_stroke_cred_t *this)
+{
+       size_t bytes;
+       int line_nr = 0;
+       chunk_t chunk, src, line;
+       FILE *fd;
+       private_key_t *private;
+       shared_key_t *shared;
+
+       DBG1(DBG_CFG, "loading secrets from '%s'", SECRETS_FILE);
+
+       fd = fopen(SECRETS_FILE, "r");
+       if (fd == NULL)
+       {
+               DBG1(DBG_CFG, "opening secrets file '%s' failed");
+               return;
+       }
+
+       /* TODO: do error checks */
+       fseek(fd, 0, SEEK_END);
+       chunk.len = ftell(fd);
+       rewind(fd);
+       chunk.ptr = malloc(chunk.len);
+       bytes = fread(chunk.ptr, 1, chunk.len, fd);
+       fclose(fd);
+       src = chunk;
+
+       this->mutex->lock(this->mutex);
+       while (this->shared->remove_last(this->shared,
+                                                                                  (void**)&shared) == SUCCESS)
+       {
+               shared->destroy(shared);
+       }
+       while (this->private->remove_last(this->private,
+                                                                                   (void**)&private) == SUCCESS)
+       {
+               private->destroy(private);
+       }
+       
+       while (fetchline(&src, &line))
+       {
+               chunk_t ids, token;
+               shared_key_type_t type;
+
+               line_nr++;
+
+               if (!eat_whitespace(&line))
+               {
+                       continue;
+               }
+               if (!extract_token(&ids, ':', &line))
+               {
+                       DBG1(DBG_CFG, "line %d: missing ':' separator", line_nr);
+                       goto error;
+               }
+               /* NULL terminate the ids string by replacing the : separator */
+               *(ids.ptr + ids.len) = '\0';
+
+               if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
+               {
+                       DBG1(DBG_CFG, "line %d: missing token", line_nr);
+                       goto error;
+               }
+               if (match("RSA", &token))
+               {
+                       char path[PATH_MAX];
+                       chunk_t filename;
+                       chunk_t secret = chunk_empty;
+                       private_key_t *key;
+                       bool pgp = FALSE;
+                       chunk_t chunk = chunk_empty;
+
+                       err_t ugh = extract_value(&filename, &line);
+
+                       if (ugh != NULL)
+                       {
+                               DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+                               goto error;
+                       }
+                       if (filename.len == 0)
+                       {
+                               DBG1(DBG_CFG, "line %d: empty filename", line_nr);
+                               goto error;
+                       }
+                       if (*filename.ptr == '/')
+                       {
+                               /* absolute path name */
+                               snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
+                       }
+                       else
+                       {
+                               /* relative path name */
+                               snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, 
+                                                filename.len, filename.ptr);
+                       }
+
+                       /* check for optional passphrase */
+                       if (eat_whitespace(&line))
+                       {
+                               ugh = extract_secret(&secret, &line);
+                               if (ugh != NULL)
+                               {
+                                       DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
+                                       goto error;
+                               }
+                       }
+
+                       if (pem_asn1_load_file(path, &secret, &chunk, &pgp))
+                       {
+                               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                                                BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
+                               if (key)
+                               {
+                                       DBG1(DBG_CFG, "  loaded private key file '%s'", path);
+                                       this->private->insert_last(this->private, key);
+                               }
+                       }
+                       chunk_free_randomized(&secret);
+               }
+               else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
+                                (match("EAP", &token) && (type = SHARED_EAP)) ||
+                                (match("XAUTH", &token) && (type = SHARED_EAP)) ||
+                                (match("PIN", &token) && (type = SHARED_PIN)))
+               {
+                       stroke_shared_key_t *shared_key;
+                       chunk_t secret = chunk_empty;
+                       bool any = TRUE;
+
+                       err_t ugh = extract_secret(&secret, &line);
+                       if (ugh != NULL)
+                       {
+                               DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
+                               goto error;
+                       }
+                       shared_key = stroke_shared_key_create(type, secret);
+                       DBG1(DBG_CFG, "  loaded %N secret for %s", shared_key_type_names, type,
+                                ids.len > 0 ? (char*)ids.ptr : "%any");
+                       DBG4(DBG_CFG, "  secret:", secret);
+                       
+                       this->shared->insert_last(this->shared, shared_key);
+                       while (ids.len > 0)
+                       {
+                               chunk_t id;
+                               identification_t *peer_id;
+
+                               ugh = extract_value(&id, &ids);
+                               if (ugh != NULL)
+                               {
+                                       DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
+                                       goto error;
+                               }
+                               if (id.len == 0)
+                               {
+                                       continue;
+                               }
+
+                               /* NULL terminate the ID string */
+                               *(id.ptr + id.len) = '\0';
+
+                               peer_id = identification_create_from_string(id.ptr);
+                               if (peer_id == NULL)
+                               {
+                                       DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
+                                       goto error;
+                               }
+                               if (peer_id->get_type(peer_id) == ID_ANY)
+                               {
+                                       peer_id->destroy(peer_id);
+                                       continue;
+                               }
+                               
+                               shared_key->add_owner(shared_key, peer_id);
+                               any = FALSE;
+                       }
+                       if (any)
+                       {
+                               shared_key->add_owner(shared_key,
+                                       identification_create_from_encoding(ID_ANY, chunk_empty));
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "line %d: token must be either "
+                                "RSA, PSK, EAP, or PIN", line_nr);
+                       goto error;
+               }
+       }
+error:
+       this->mutex->unlock(this->mutex);
+       chunk_free_randomized(&chunk);
+}
+
+/**
+ * load all certificates from ipsec.d
+ */
+static void load_certs(private_stroke_cred_t *this)
+{
+       DBG1(DBG_CFG, "loading ca certificates from '%s'",
+                CA_CERTIFICATE_DIR);
+       load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
+
+       DBG1(DBG_CFG, "loading aa certificates from '%s'",
+                AA_CERTIFICATE_DIR);
+       load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
+
+       DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
+                OCSP_CERTIFICATE_DIR);
+       load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER);
+
+       DBG1(DBG_CFG, "loading attribute certificates from '%s'",
+                ATTR_CERTIFICATE_DIR);
+       load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
+
+       DBG1(DBG_CFG, "loading crls from '%s'",
+                CRL_DIR);
+       load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
+}
+
+/**
+ * Implementation of stroke_cred_t.reread.
+ */
+static void reread(private_stroke_cred_t *this, stroke_msg_t *msg)
+{
+       if (msg->reread.flags & REREAD_SECRETS)
+       {
+               DBG1(DBG_CFG, "rereading secrets");
+               load_secrets(this);
+       }
+       if (msg->reread.flags & REREAD_CACERTS)
+       {
+               DBG1(DBG_CFG, "rereading ca certificates from '%s'",
+                        CA_CERTIFICATE_DIR);
+               load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
+       }
+       if (msg->reread.flags & REREAD_OCSPCERTS)
+       {
+               DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
+                        OCSP_CERTIFICATE_DIR);
+               load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
+                        X509_OCSP_SIGNER);
+       }
+       if (msg->reread.flags & REREAD_AACERTS)
+       {
+               DBG1(DBG_CFG, "rereading aa certificates from '%s'",
+                        AA_CERTIFICATE_DIR);
+               load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
+       }
+       if (msg->reread.flags & REREAD_ACERTS)
+       {
+               DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
+                        ATTR_CERTIFICATE_DIR);
+               load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0);
+       }
+       if (msg->reread.flags & REREAD_CRLS)
+       {
+               DBG1(DBG_CFG, "rereading crls from '%s'",
+                        CRL_DIR);
+               load_certdir(this, CRL_DIR, CERT_X509_CRL, 0);
+       }
+}
+
+/**
+ * Implementation of stroke_cred_t.destroy
+ */
+static void destroy(private_stroke_cred_t *this)
+{
+       this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy));
+       this->shared->destroy_offset(this->shared, offsetof(shared_key_t, destroy));
+       this->private->destroy_offset(this->private, offsetof(private_key_t, destroy));
+       this->mutex->destroy(this->mutex);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_cred_t *stroke_cred_create()
+{
+       private_stroke_cred_t *this = malloc_thing(private_stroke_cred_t);
+       
+       this->public.set.create_private_enumerator = (void*)create_private_enumerator;
+       this->public.set.create_cert_enumerator = (void*)create_cert_enumerator;
+       this->public.set.create_shared_enumerator = (void*)create_shared_enumerator;
+       this->public.set.create_cdp_enumerator = (void*)return_null;
+       this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg))reread;
+       this->public.load_ca = (certificate_t*(*)(stroke_cred_t*, char *filename))load_ca;
+       this->public.load_peer = (certificate_t*(*)(stroke_cred_t*, char *filename))load_peer;
+       this->public.destroy = (void(*)(stroke_cred_t*))destroy;
+       
+       this->certs = linked_list_create();
+       this->shared = linked_list_create();
+       this->private = linked_list_create();
+       this->mutex = mutex_create(MUTEX_RECURSIVE);
+
+       load_certs(this);
+       load_secrets(this);
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_cred.h b/src/charon/plugins/stroke/stroke_cred.h
new file mode 100644 (file)
index 0000000..cbfed11
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_cred stroke_cred
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_CRED_H_
+#define STROKE_CRED_H_
+
+#include <stroke_msg.h>
+#include <credentials/credential_set.h>
+#include <credentials/certificates/certificate.h>
+
+typedef struct stroke_cred_t stroke_cred_t;
+
+/**
+ * Stroke in-memory credential storage.
+ */
+struct stroke_cred_t {
+
+       /**
+        * Implements credential_set_t
+        */
+       credential_set_t set;
+       
+       /**
+        * Reread secrets from config files.
+        *
+        * @param msg           stroke message
+        */
+       void (*reread)(stroke_cred_t *this, stroke_msg_t *msg);
+       
+       /**
+        * Load a CA certificate, and serve it through the credential_set.
+        *
+        * @param filename              file to load CA cert from
+        * @return                              reference to loaded certificate, or NULL
+        */
+       certificate_t* (*load_ca)(stroke_cred_t *this, char *filename);
+       
+       /**
+        * Load a peer certificate and serve it rhrough the credential_set.
+        *
+        * @param filename              file to load peer cert from
+        * @return                              reference to loaded certificate, or NULL
+        */
+       certificate_t* (*load_peer)(stroke_cred_t *this, char *filename);
+       
+       /**
+     * Destroy a stroke_cred instance.
+     */
+    void (*destroy)(stroke_cred_t *this);
+};
+
+/**
+ * Create a stroke_cred instance.
+ */
+stroke_cred_t *stroke_cred_create();
+
+#endif /* STROKE_CRED_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_list.c b/src/charon/plugins/stroke/stroke_list.c
new file mode 100644 (file)
index 0000000..5ce02d9
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_list.h"
+
+#include <daemon.h>
+#include <credentials/certificates/x509.h>
+#include <credentials/certificates/crl.h>
+
+/* warning intervals for list functions */
+#define CERT_WARNING_INTERVAL  30      /* days */
+#define CRL_WARNING_INTERVAL   7       /* days */
+
+typedef struct private_stroke_list_t private_stroke_list_t;
+
+/**
+ * private data of stroke_list
+ */
+struct private_stroke_list_t {
+
+       /**
+        * public functions
+        */
+       stroke_list_t public;
+};
+
+/**
+ * log an IKE_SA to out
+ */
+static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
+{
+       ike_sa_id_t *id = ike_sa->get_id(ike_sa);
+       u_int32_t rekey, reauth;
+
+       fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
+                       ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+                       ike_sa_state_names, ike_sa->get_state(ike_sa),
+                       ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
+                       ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
+       
+       if (all)
+       {
+               fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
+                               ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+                               id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
+                               id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
+       
+               rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME);
+               reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME);
+               if (rekey)
+               {
+                       fprintf(out, ", rekeying in %V", &rekey);
+               }
+               if (reauth)
+               {
+                       fprintf(out, ", reauthentication in %V", &reauth);
+               }
+               if (!rekey && !reauth)
+               {
+                       fprintf(out, ", rekeying disabled");
+               }
+               fprintf(out, "\n");
+       }
+}
+
+/**
+ * log an CHILD_SA to out
+ */
+static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
+{
+       u_int32_t rekey, now = time(NULL);
+       u_int32_t use_in, use_out, use_fwd;
+       encryption_algorithm_t encr_alg;
+       integrity_algorithm_t int_alg;
+       size_t encr_len, int_len;
+       mode_t mode;
+       
+       child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
+                                               &int_alg, &int_len, &rekey, &use_in, &use_out,
+                                               &use_fwd);
+       
+       fprintf(out, "%12s{%d}:  %N, %N", 
+                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+                       child_sa_state_names, child_sa->get_state(child_sa),
+                       mode_names, mode);
+       
+       if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
+       {
+               fprintf(out, ", %N SPIs: %.8x_i %.8x_o",
+                               protocol_id_names, child_sa->get_protocol(child_sa),
+                               htonl(child_sa->get_spi(child_sa, TRUE)),
+                               htonl(child_sa->get_spi(child_sa, FALSE)));
+               
+               if (all)
+               {
+                       fprintf(out, "\n%12s{%d}:  ", child_sa->get_name(child_sa), 
+                                       child_sa->get_reqid(child_sa));
+                       
+                       
+                       if (child_sa->get_protocol(child_sa) == PROTO_ESP)
+                       {
+                               fprintf(out, "%N", encryption_algorithm_names, encr_alg);
+                               
+                               if (encr_len)
+                               {
+                                       fprintf(out, "-%d", encr_len);
+                               }
+                               fprintf(out, "/");
+                       }
+                       
+                       fprintf(out, "%N", integrity_algorithm_names, int_alg);
+                       if (int_len)
+                       {
+                               fprintf(out, "-%d", int_len);
+                       }
+                       fprintf(out, ", rekeying ");
+                       
+                       if (rekey)
+                       {
+                               fprintf(out, "in %#V", &now, &rekey);
+                       }
+                       else
+                       {
+                               fprintf(out, "disabled");
+                       }
+                       
+                       fprintf(out, ", last use: ");
+                       use_in = max(use_in, use_fwd);
+                       if (use_in)
+                       {
+                               fprintf(out, "%ds_i ", now - use_in);
+                       }
+                       else
+                       {
+                               fprintf(out, "no_i ");
+                       }
+                       if (use_out)
+                       {
+                               fprintf(out, "%ds_o ", now - use_out);
+                       }
+                       else
+                       {
+                               fprintf(out, "no_o ");
+                       }
+               }
+       }
+       
+       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
+                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+                       child_sa->get_traffic_selectors(child_sa, TRUE),
+                       child_sa->get_traffic_selectors(child_sa, FALSE));
+}
+
+/**
+ * Implementation of stroke_list_t.status.
+ */
+static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all)
+{
+       enumerator_t *enumerator, *children;
+       iterator_t *iterator;
+       host_t *host;
+       peer_cfg_t *peer_cfg;
+       ike_cfg_t *ike_cfg;
+       child_cfg_t *child_cfg;
+       ike_sa_t *ike_sa;
+       char *name = NULL;
+       
+       name = msg->status.name;
+       
+       if (all)
+       {
+               fprintf(out, "Performance:\n");
+               fprintf(out, "  worker threads: %d idle of %d,",
+                               charon->processor->get_idle_threads(charon->processor),
+                               charon->processor->get_total_threads(charon->processor));
+               fprintf(out, " job queue load: %d,",
+                               charon->processor->get_job_load(charon->processor));
+               fprintf(out, " scheduled events: %d\n",
+                               charon->scheduler->get_job_load(charon->scheduler));
+               iterator = charon->kernel_interface->create_address_iterator(
+                                                                                                       charon->kernel_interface);
+               fprintf(out, "Listening IP addresses:\n");
+               while (iterator->iterate(iterator, (void**)&host))
+               {
+                       fprintf(out, "  %H\n", host);
+               }
+               iterator->destroy(iterator);
+       
+               fprintf(out, "Connections:\n");
+               enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
+               while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
+               {
+                       if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
+                               (name && !streq(name, peer_cfg->get_name(peer_cfg))))
+                       {
+                               continue;
+                       }
+                       
+                       ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+                       fprintf(out, "%12s:  %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
+                                       ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
+                                       ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
+                       /* TODO: list CAs and groups */
+                       children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
+                       while (children->enumerate(children, &child_cfg))
+                       {
+                               linked_list_t *my_ts, *other_ts;
+                               my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
+                               other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
+                               fprintf(out, "%12s:    %#R=== %#R\n", child_cfg->get_name(child_cfg),
+                                               my_ts, other_ts);
+                               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+                               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+                       }
+                       children->destroy(children);
+               }
+               enumerator->destroy(enumerator);
+       }
+       
+       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+       if (all && iterator->get_count(iterator) > 0)
+       {
+               fprintf(out, "Security Associations:\n");
+       }
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               bool ike_printed = FALSE;
+               child_sa_t *child_sa;
+               iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
+
+               if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
+               {
+                       log_ike_sa(out, ike_sa, all);
+                       ike_printed = TRUE;
+               }
+
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       if (name == NULL || streq(name, child_sa->get_name(child_sa)))
+                       {
+                               if (!ike_printed)
+                               {
+                                       log_ike_sa(out, ike_sa, all);
+                                       ike_printed = TRUE;
+                               }
+                               log_child_sa(out, child_sa, all);
+                       }       
+               }
+               children->destroy(children);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * list all X.509 certificates matching the flags
+ */
+static void stroke_list_certs(char *label, x509_flag_t flags, bool utc, FILE *out)
+{
+       bool first = TRUE;
+       time_t now = time(NULL);
+       certificate_t *cert;
+       enumerator_t *enumerator;
+       
+       enumerator = charon->credentials->create_cert_enumerator(
+                                               charon->credentials, CERT_X509, KEY_ANY, NULL, FALSE);
+       while (enumerator->enumerate(enumerator, (void**)&cert))
+       {
+               x509_t *x509 = (x509_t*)cert;
+               x509_flag_t x509_flags = x509->get_flags(x509);
+
+               /* list only if flag is set, or flags == 0 (ignoring self-signed) */
+               if ((x509_flags & flags) || (flags == (x509_flags & ~X509_SELF_SIGNED)))
+               {
+                       enumerator_t *enumerator;
+                       identification_t *altName;
+                       bool first_altName = TRUE;
+                       chunk_t serial = x509->get_serial(x509);
+                       identification_t *authkey = x509->get_authKeyIdentifier(x509);
+                       time_t notBefore, notAfter;
+                       public_key_t *public = cert->get_public_key(cert);
+
+                       if (first)
+                       {
+                               fprintf(out, "\n");
+                               fprintf(out, "List of %s:\n", label);
+                               first = FALSE;
+                       }
+                       fprintf(out, "\n");
+
+                       /* list subjectAltNames */
+                       enumerator = x509->create_subjectAltName_enumerator(x509);
+                       while (enumerator->enumerate(enumerator, (void**)&altName))
+                       {
+                               if (first_altName)
+                               {
+                                       fprintf(out, "  altNames:  ");
+                                       first_altName = FALSE;
+                               }
+                               else
+                               {
+                                       fprintf(out, ", ");
+                               }
+                               fprintf(out, "%D", altName);
+                       }
+                       if (!first_altName)
+                       {
+                               fprintf(out, "\n");
+                       }
+                       enumerator->destroy(enumerator);
+
+                       fprintf(out, "  subject:  %D\n", cert->get_subject(cert));
+                       fprintf(out, "  issuer:   %D\n", cert->get_issuer(cert));
+                       fprintf(out, "  serial:    %#B\n", &serial);
+
+                       /* list validity */
+                       cert->get_validity(cert, &now, &notBefore, &notAfter);
+                       fprintf(out, "  validity:  not before %#T, ", &notBefore, utc);
+                       if (now < notBefore)
+                       {
+                               fprintf(out, "not valid yet (valid in %#V)\n", &now, &notBefore);
+                       }
+                       else
+                       {
+                               fprintf(out, "ok\n");
+                       }
+                       fprintf(out, "             not after  %#T, ", &notAfter, utc);
+                       if (now > notAfter)
+                       {
+                               fprintf(out, "expired (%#V ago)\n", &now, &notAfter);
+                       }
+                       else
+                       {
+                               fprintf(out, "ok");
+                               if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
+                               {
+                                       fprintf(out, " (expires in %#V)", &now, &notAfter);
+                               }
+                               fprintf(out, " \n");
+                       }
+       
+                       /* list public key information */
+                       if (public)
+                       {
+                               private_key_t *private = NULL;
+                               identification_t *id, *keyid;
+                       
+                               id    = public->get_id(public, ID_PUBKEY_SHA1);
+                               keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1);
+
+                               private = charon->credentials->get_private(
+                                                                       charon->credentials, 
+                                                                       public->get_type(public), keyid, NULL);
+                               fprintf(out, "  pubkey:    %N %d bits%s\n",
+                                               key_type_names, public->get_type(public),
+                                               public->get_keysize(public) * 8,
+                                               private ? ", has private key" : "");
+                               fprintf(out, "  keyid:     %D\n", keyid);
+                               fprintf(out, "  subjkey:   %D\n", id);
+                               DESTROY_IF(private);
+                               public->destroy(public);
+                       }
+       
+                       /* list optional authorityKeyIdentifier */
+                       if (authkey)
+                       {
+                               fprintf(out, "  authkey:   %D\n", authkey);
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * list all X.509 CRLs
+ */
+static void stroke_list_crls(bool utc, FILE *out)
+{
+       bool first = TRUE;
+       time_t thisUpdate, nextUpdate, now = time(NULL);
+       certificate_t *cert;
+       enumerator_t *enumerator;
+       
+       enumerator = charon->credentials->create_cert_enumerator(
+                                               charon->credentials, CERT_X509_CRL, KEY_ANY, NULL, FALSE);
+       while (enumerator->enumerate(enumerator, (void**)&cert))
+       {
+               crl_t *crl = (crl_t*)cert;
+               chunk_t serial  = crl->get_serial(crl);
+               identification_t *authkey = crl->get_authKeyIdentifier(crl);
+
+               if (first)
+               {
+                       fprintf(out, "\n");
+                       fprintf(out, "List of X.509 CRLs:\n");
+                       first = FALSE;
+               }
+               fprintf(out, "\n");
+
+               fprintf(out, "  issuer:   %D\n", cert->get_issuer(cert));
+
+               /* list optional crlNumber */
+               if (serial.ptr)
+               {
+                       fprintf(out, "  serial:    %#B\n", &serial);
+               }
+
+               /* count the number of revoked certificates */
+               {
+                       int count = 0;
+                       enumerator_t *enumerator = crl->create_enumerator(crl);
+
+                       while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
+                       {
+                               count++;
+                       }
+                       fprintf(out, "  revoked:   %d certificate%s\n", count,
+                                                       (count == 1)? "" : "s");
+                       enumerator->destroy(enumerator);
+               }
+
+               /* list validity */
+               cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
+               fprintf(out, "  updates:   this %#T\n",  &thisUpdate, utc);
+               fprintf(out, "             next %#T, ", &nextUpdate, utc);
+               if (now > nextUpdate)
+               {
+                       fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
+               }
+               else
+               {
+                       fprintf(out, "ok");
+                       if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
+                       {
+                               fprintf(out, " (expires in %#V)", &now, &nextUpdate);
+                       }
+                       fprintf(out, " \n");
+               }
+
+               /* list optional authorityKeyIdentifier */
+               if (authkey)
+               {
+                       fprintf(out, "  authkey:   %D\n", authkey);
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Implementation of stroke_list_t.list.
+ */
+static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
+{
+       if (msg->list.flags & LIST_CERTS)
+       {
+               stroke_list_certs("X.509 End Entity Certificates",
+                                                 0, msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_CACERTS)
+       {
+               stroke_list_certs("X.509 CA Certificates",
+                                                 X509_CA, msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_OCSPCERTS)
+       {
+               stroke_list_certs("X.509 OCSP Signer Certificates",
+                                                 X509_OCSP_SIGNER, msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_AACERTS)
+       {
+               stroke_list_certs("X.509 AA Certificates",
+                                                 X509_AA, msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_ACERTS)
+       {
+
+       }
+       if (msg->list.flags & LIST_CRLS)
+       {
+               stroke_list_crls(msg->list.utc, out);
+       }
+       if (msg->list.flags & LIST_OCSP)
+       {
+
+       }
+}
+
+/**
+ * Implementation of stroke_list_t.destroy
+ */
+static void destroy(private_stroke_list_t *this)
+{
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_list_t *stroke_list_create()
+{
+       private_stroke_list_t *this = malloc_thing(private_stroke_list_t);
+       
+       this->public.list = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out))list;
+       this->public.status = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out,bool))status;
+       this->public.destroy = (void(*)(stroke_list_t*))destroy;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_list.h b/src/charon/plugins/stroke/stroke_list.h
new file mode 100644 (file)
index 0000000..dabdbff
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_list stroke_list
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_LIST_H_
+#define STROKE_LIST_H_
+
+#include <stroke_msg.h>
+#include <library.h>
+
+typedef struct stroke_list_t stroke_list_t;
+
+/**
+ * Log status information to stroke console
+ */
+struct stroke_list_t {
+
+       /**
+        * List certificate information to stroke console.
+        *
+        * @param msg           stroke message
+        * @param out           stroke console stream
+        */
+       void (*list)(stroke_list_t *this, stroke_msg_t *msg, FILE *out);
+       
+       /**
+        * Log status information to stroke console.
+        *
+        * @param msg           stroke message
+        * @param out           stroke console stream
+        * @param all           TRUE for "statusall"
+        */
+       void (*status)(stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all);
+       
+       /**
+     * Destroy a stroke_list instance.
+     */
+    void (*destroy)(stroke_list_t *this);
+};
+
+/**
+ * Create a stroke_list instance.
+ */
+stroke_list_t *stroke_list_create();
+
+#endif /* STROKE_LIST_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_plugin.c b/src/charon/plugins/stroke/stroke_plugin.c
new file mode 100644 (file)
index 0000000..6933fc0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_plugin.h"
+
+#include <library.h>
+#include "stroke_socket.h"
+
+typedef struct private_stroke_plugin_t private_stroke_plugin_t;
+
+/**
+ * private data of stroke_plugin
+ */
+struct private_stroke_plugin_t {
+
+       /**
+        * public functions
+        */
+       stroke_plugin_t public;
+       
+       /**
+        * stroke socket, receives strokes
+        */
+       stroke_socket_t *socket;
+};
+
+/**
+ * Implementation of stroke_plugin_t.destroy
+ */
+static void destroy(private_stroke_plugin_t *this)
+{
+       this->socket->destroy(this->socket);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *plugin_create()
+{
+       private_stroke_plugin_t *this = malloc_thing(private_stroke_plugin_t);
+       
+       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
+       
+       this->socket = stroke_socket_create();
+       if (this->socket == NULL)
+       {
+               free(this);
+               return NULL;
+       }
+       return &this->public.plugin;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_plugin.h b/src/charon/plugins/stroke/stroke_plugin.h
new file mode 100644 (file)
index 0000000..7ea18b8
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id: stroke.h 3589 2008-03-13 14:14:44Z martin $
+ */
+
+/**
+ * @defgroup stroke stroke
+ * @ingroup cplugins
+ *
+ * @defgroup stroke_plugin stroke_plugin
+ * @{ @ingroup stroke
+ */
+#ifndef STROKE_PLUGIN_H_
+#define STROKE_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct stroke_plugin_t stroke_plugin_t;
+
+/**
+ * strongSwan 2.x style configuration and control interface.
+ *
+ * Stroke is a home-brewed communication interface inspired by whack. It
+ * uses a unix socket (/var/run/charon.ctl).
+ */
+struct stroke_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+/**
+ * Instanciate stroke plugin.
+ */
+plugin_t *plugin_create();
+
+#endif /* STROKE_PLUGIN_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_shared_key.c b/src/charon/plugins/stroke/stroke_shared_key.c
new file mode 100644 (file)
index 0000000..9c21eb8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_shared_key.h"
+
+#include <utils/linked_list.h>
+
+typedef struct private_stroke_shared_key_t private_stroke_shared_key_t;
+
+/**
+ * private data of shared_key
+ */
+struct private_stroke_shared_key_t {
+
+       /**
+        * implements shared_key_t
+        */
+       stroke_shared_key_t public;
+       
+       /**
+        * type of this key
+        */
+       shared_key_type_t type;
+
+       /**
+        * data of the key
+        */
+       chunk_t key;
+
+       /**
+        * list of key owners, as identification_t
+        */
+       linked_list_t *owners;
+       
+       /**
+        * reference counter
+        */
+       refcount_t ref;
+};
+
+/**
+ * Implementation of shared_key_t.get_type.
+ */
+static shared_key_type_t get_type(private_stroke_shared_key_t *this)
+{
+       return this->type;
+}
+
+/**
+ * Implementation of shared_key_t.get_ref.
+ */
+static private_stroke_shared_key_t* get_ref(private_stroke_shared_key_t *this)
+{
+       ref_get(&this->ref);
+       return this;
+}
+
+/**
+ * Implementation of shared_key_t.get_key.
+ */
+static chunk_t get_key(private_stroke_shared_key_t *this)
+{
+       return this->key;
+}      
+       
+/**
+ * Implementation of stroke_shared_key_t.has_owner.
+ */
+static id_match_t has_owner(private_stroke_shared_key_t *this, identification_t *owner)
+{
+       enumerator_t *enumerator;
+       id_match_t match, best = ID_MATCH_NONE;
+       identification_t *current;
+       
+       enumerator = this->owners->create_enumerator(this->owners);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               match  = owner->matches(owner, current);
+               if (match > best)
+               {
+                       best = match;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return best;
+}
+/**
+ * Implementation of stroke_shared_key_t.add_owner.
+ */
+static void add_owner(private_stroke_shared_key_t *this, identification_t *owner)
+{
+       this->owners->insert_last(this->owners, owner);
+}
+
+/**
+ * Implementation of stroke_shared_key_t.destroy
+ */
+static void destroy(private_stroke_shared_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               this->owners->destroy_offset(this->owners, offsetof(identification_t, destroy));
+               chunk_free(&this->key);
+               free(this);
+       }
+}
+
+/**
+ * create a shared key
+ */
+stroke_shared_key_t *stroke_shared_key_create(shared_key_type_t type, chunk_t key)
+{
+       private_stroke_shared_key_t *this = malloc_thing(private_stroke_shared_key_t);
+
+       this->public.shared.get_type = (shared_key_type_t(*)(shared_key_t*))get_type;
+       this->public.shared.get_key = (chunk_t(*)(shared_key_t*))get_key;
+       this->public.shared.get_ref = (shared_key_t*(*)(shared_key_t*))get_ref;
+       this->public.shared.destroy = (void(*)(shared_key_t*))destroy;
+       this->public.add_owner = (void(*)(stroke_shared_key_t*, identification_t *owner))add_owner;
+       this->public.has_owner = (id_match_t(*)(stroke_shared_key_t*, identification_t *owner))has_owner;
+
+       this->owners = linked_list_create();
+       this->type = type;
+       this->key = key;
+       this->ref = 1;
+       
+       return &this->public;
+}
diff --git a/src/charon/plugins/stroke/stroke_shared_key.h b/src/charon/plugins/stroke/stroke_shared_key.h
new file mode 100644 (file)
index 0000000..e93d8ce
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_shared_key stroke_shared_key
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_SHARED_KEY_H_
+#define STROKE_SHARED_KEY_H_
+
+#include <utils/identification.h>
+#include <credentials/keys/shared_key.h>
+
+typedef struct stroke_shared_key_t stroke_shared_key_t;
+
+/**
+ * Shared key implementation for keys read from ipsec.secrets
+ */
+struct stroke_shared_key_t {
+
+       /**
+        * Implements the shared_key_t interface.
+        */
+       shared_key_t shared;
+       
+       /**
+        * Add an owner to the key.
+        *
+        * @param owner         owner to add
+        */
+       void (*add_owner)(stroke_shared_key_t *this, identification_t *owner);
+       
+       /**
+        * Check if a key has a specific owner.
+        *
+        * @param owner         owner to check
+        * @return                      best match found
+        */
+       id_match_t (*has_owner)(stroke_shared_key_t *this, identification_t *owner);    
+};
+
+/**
+ * Create a stroke_shared_key instance.
+ */
+stroke_shared_key_t *stroke_shared_key_create(shared_key_type_t type, chunk_t key);
+
+#endif /* STROKE_SHARED_KEY_H_ @}*/
diff --git a/src/charon/plugins/stroke/stroke_socket.c b/src/charon/plugins/stroke/stroke_socket.c
new file mode 100644 (file)
index 0000000..eda64be
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "stroke_socket.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <processing/jobs/callback_job.h>
+#include <daemon.h>
+
+#include "stroke_config.h"
+#include "stroke_control.h"
+#include "stroke_cred.h"
+#include "stroke_ca.h"
+#include "stroke_list.h"
+
+typedef struct stroke_job_context_t stroke_job_context_t;
+typedef struct private_stroke_socket_t private_stroke_socket_t;
+
+/**
+ * private data of stroke_socket
+ */
+struct private_stroke_socket_t {
+
+       /**
+        * public functions
+        */
+       stroke_socket_t public;
+               
+       /**
+        * Unix socket to listen for strokes
+        */
+       int socket;
+       
+       /**
+        * job accepting stroke messages
+        */
+       callback_job_t *job;
+       
+       /**
+        * configuration backend
+        */
+       stroke_config_t *config;
+       
+       /**
+        * controller to control daemon
+        */
+       stroke_control_t *control;
+       
+       /**
+        * credential set
+        */
+       stroke_cred_t *cred;
+       
+       /**
+        * CA sections
+        */
+       stroke_ca_t *ca;
+       
+       /**
+        * Status information logging
+        */
+       stroke_list_t *list;
+};
+
+/**
+ * job context to pass to processing thread
+ */
+struct stroke_job_context_t {
+
+       /**
+        * file descriptor to read from
+        */
+       int fd;
+       
+       /**
+        * global stroke interface
+        */
+       private_stroke_socket_t *this;
+};
+
+/**
+ * Helper function which corrects the string pointers
+ * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
+ * contains RELATIVE addresses (relative to the beginning of the
+ * stroke_msg). They must be corrected if they reach our address
+ * space...
+ */
+static void pop_string(stroke_msg_t *msg, char **string)
+{
+       if (*string == NULL)
+       {
+               return;
+       }
+
+       /* check for sanity of string pointer and string */
+       if (string < (char**)msg ||
+               string > (char**)msg + sizeof(stroke_msg_t) ||
+               (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) ||
+               (unsigned long)*string > msg->length)
+       {
+               *string = "(invalid pointer in stroke msg)";
+       }
+       else
+       {
+               *string = (char*)msg + (unsigned long)*string;
+       }
+}
+
+/**
+ * Pop the strings of a stroke_end_t struct and log them for debugging purposes
+ */
+static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
+{
+       pop_string(msg, &end->address);
+       pop_string(msg, &end->subnet);
+       pop_string(msg, &end->sourceip);
+       pop_string(msg, &end->id);
+       pop_string(msg, &end->cert);
+       pop_string(msg, &end->ca);
+       pop_string(msg, &end->groups);
+       pop_string(msg, &end->updown);
+       
+       DBG2(DBG_CFG, "  %s=%s", label, end->address);
+       DBG2(DBG_CFG, "  %ssubnet=%s", label, end->subnet);
+       DBG2(DBG_CFG, "  %ssourceip=%s", label, end->sourceip);
+       DBG2(DBG_CFG, "  %sid=%s", label, end->id);
+       DBG2(DBG_CFG, "  %scert=%s", label, end->cert);
+       DBG2(DBG_CFG, "  %sca=%s", label, end->ca);
+       DBG2(DBG_CFG, "  %sgroups=%s", label, end->groups);
+       DBG2(DBG_CFG, "  %supdown=%s", label, end->updown);
+}
+
+/**
+ * Add a connection to the configuration list
+ */
+static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
+{
+       pop_string(msg, &msg->add_conn.name);
+       DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
+       DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
+       pop_end(msg, "left", &msg->add_conn.me);
+       pop_end(msg, "right", &msg->add_conn.other);
+       pop_string(msg, &msg->add_conn.algorithms.ike);
+       pop_string(msg, &msg->add_conn.algorithms.esp);
+       DBG2(DBG_CFG, "  ike=%s", msg->add_conn.algorithms.ike);
+       DBG2(DBG_CFG, "  esp=%s", msg->add_conn.algorithms.esp);
+       pop_string(msg, &msg->add_conn.p2p.mediated_by);
+       pop_string(msg, &msg->add_conn.p2p.peerid);
+       DBG2(DBG_CFG, "  p2p_mediation=%s", msg->add_conn.p2p.mediation ? "yes" : "no");
+       DBG2(DBG_CFG, "  p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by);
+       DBG2(DBG_CFG, "  p2p_peerid=%s", msg->add_conn.p2p.peerid);
+
+       this->config->add(this->config, msg);
+}
+
+/**
+ * Delete a connection from the list
+ */
+static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
+{
+       pop_string(msg, &msg->del_conn.name);
+       DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
+       
+       this->config->del(this->config, msg);
+}
+
+/**
+ * initiate a connection by name
+ */
+static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->initiate.name);
+       DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
+       
+       this->control->initiate(this->control, msg, out);
+}
+
+/**
+ * terminate a connection by name
+ */
+static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->terminate.name);
+       DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
+
+       this->control->terminate(this->control, msg, out);
+}
+
+/**
+ * route a policy (install SPD entries)
+ */
+static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->route.name);
+       DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);
+       
+       this->control->route(this->control, msg, out);
+}
+
+/**
+ * unroute a policy
+ */
+static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->terminate.name);
+       DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name);
+       
+       this->control->unroute(this->control, msg, out);
+}
+
+/**
+ * Add a ca information record to the cainfo list
+ */
+static void stroke_add_ca(private_stroke_socket_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->add_ca.name);
+       pop_string(msg, &msg->add_ca.cacert);
+       pop_string(msg, &msg->add_ca.crluri);
+       pop_string(msg, &msg->add_ca.crluri2);
+       pop_string(msg, &msg->add_ca.ocspuri);
+       pop_string(msg, &msg->add_ca.ocspuri2);
+
+       DBG2(DBG_CFG, "ca %s",        msg->add_ca.name);
+       DBG2(DBG_CFG, "  cacert=%s",  msg->add_ca.cacert);
+       DBG2(DBG_CFG, "  crluri=%s",  msg->add_ca.crluri);
+       DBG2(DBG_CFG, "  crluri2=%s", msg->add_ca.crluri2);
+       DBG2(DBG_CFG, "  ocspuri=%s", msg->add_ca.ocspuri);
+       DBG2(DBG_CFG, "  ocspuri2=%s", msg->add_ca.ocspuri2);
+       
+       DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
+       
+       this->ca->add(this->ca, msg);
+}
+
+/**
+ * Delete a ca information record from the cainfo list
+ */
+static void stroke_del_ca(private_stroke_socket_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->del_ca.name);
+       DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
+       
+       this->ca->del(this->ca, msg);
+}
+
+
+/**
+ * show status of daemon
+ */
+static void stroke_status(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out,
+                                                 bool all)
+{
+       pop_string(msg, &(msg->status.name));
+       
+       this->list->status(this->list, msg, out, all);
+}
+
+/**
+ * list various information
+ */
+static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       if (msg->list.flags & LIST_CAINFOS)
+       {
+               this->ca->list(this->ca, msg, out);
+       }
+       this->list->list(this->list, msg, out);
+}
+
+/**
+ * reread various information
+ */
+static void stroke_reread(private_stroke_socket_t *this,
+                                                 stroke_msg_t *msg, FILE *out)
+{
+       this->cred->reread(this->cred, msg);
+}
+
+/**
+ * purge various information
+ */
+static void stroke_purge(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       /* TODO: flush cache */
+}
+
+signal_t get_signal_from_logtype(char *type)
+{
+       if      (strcasecmp(type, "any") == 0) return SIG_ANY;
+       else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
+       else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
+       else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
+       else if (strcasecmp(type, "job") == 0) return DBG_JOB;
+       else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
+       else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
+       else if (strcasecmp(type, "net") == 0) return DBG_NET;
+       else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
+       else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
+       else return -1;
+}
+
+/**
+ * set the verbosity debug output
+ */
+static void stroke_loglevel(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+{
+       signal_t signal;
+       
+       pop_string(msg, &(msg->loglevel.type));
+       DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
+                msg->loglevel.level, msg->loglevel.type);
+       
+       signal = get_signal_from_logtype(msg->loglevel.type);
+       if (signal < 0)
+       {
+               fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
+               return;
+       }
+       
+       charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
+       charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
+}
+
+
+/**
+ * destroy a job context
+ */
+static void stroke_job_context_destroy(stroke_job_context_t *this)
+{
+       close(this->fd);
+       free(this);
+}
+
+/**
+ * process a stroke request from the socket pointed by "fd"
+ */
+static job_requeue_t process(stroke_job_context_t *ctx)
+{
+       stroke_msg_t *msg;
+       u_int16_t msg_length;
+       ssize_t bytes_read;
+       FILE *out;
+       private_stroke_socket_t *this = ctx->this;
+       int strokefd = ctx->fd;
+       
+       /* peek the length */
+       bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
+       if (bytes_read != sizeof(msg_length))
+       {
+               DBG1(DBG_CFG, "reading length of stroke message failed: %s",
+                        strerror(errno));
+               close(strokefd);
+               return JOB_REQUEUE_NONE;
+       }
+       
+       /* read message */
+       msg = malloc(msg_length);
+       bytes_read = recv(strokefd, msg, msg_length, 0);
+       if (bytes_read != msg_length)
+       {
+               DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
+               close(strokefd);
+               return JOB_REQUEUE_NONE;
+       }
+       
+       out = fdopen(strokefd, "w");
+       if (out == NULL)
+       {
+               DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
+               close(strokefd);
+               free(msg);
+               return JOB_REQUEUE_NONE;
+       }
+       
+       DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
+       
+       /* the stroke_* functions are blocking, as they listen on the bus. Add
+        * cancellation handlers. */
+       pthread_cleanup_push((void*)fclose, out);
+       pthread_cleanup_push(free, msg);
+       
+       switch (msg->type)
+       {
+               case STR_INITIATE:
+                       stroke_initiate(this, msg, out);
+                       break;
+               case STR_ROUTE:
+                       stroke_route(this, msg, out);
+                       break;
+               case STR_UNROUTE:
+                       stroke_unroute(this, msg, out);
+                       break;
+               case STR_TERMINATE:
+                       stroke_terminate(this, msg, out);
+                       break;
+               case STR_STATUS:
+                       stroke_status(this, msg, out, FALSE);
+                       break;
+               case STR_STATUS_ALL:
+                       stroke_status(this, msg, out, TRUE);
+                       break;
+               case STR_ADD_CONN:
+                       stroke_add_conn(this, msg);
+                       break;
+               case STR_DEL_CONN:
+                       stroke_del_conn(this, msg);
+                       break;
+               case STR_ADD_CA:
+                       stroke_add_ca(this, msg, out);
+                       break;
+               case STR_DEL_CA:
+                       stroke_del_ca(this, msg, out);
+                       break;
+               case STR_LOGLEVEL:
+                       stroke_loglevel(this, msg, out);
+                       break;
+               case STR_LIST:
+                       stroke_list(this, msg, out);
+                       break;
+               case STR_REREAD:
+                       stroke_reread(this, msg, out);
+                       break;
+               case STR_PURGE:
+                       stroke_purge(this, msg, out);
+                       break;
+               default:
+                       DBG1(DBG_CFG, "received unknown stroke");
+       }
+       /* remove and execute cancellation handlers */
+       pthread_cleanup_pop(1);
+       pthread_cleanup_pop(1);
+       
+       return JOB_REQUEUE_NONE;
+}
+
+/**
+ * Implementation of private_stroke_socket_t.stroke_receive.
+ */
+static job_requeue_t receive(private_stroke_socket_t *this)
+{
+       struct sockaddr_un strokeaddr;
+       int strokeaddrlen = sizeof(strokeaddr);
+       int strokefd;
+       int oldstate;
+       callback_job_t *job;
+       stroke_job_context_t *ctx;
+       
+       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+       strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
+       pthread_setcancelstate(oldstate, NULL);
+       
+       if (strokefd < 0)
+       {
+               DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
+               return JOB_REQUEUE_FAIR;
+       }
+       
+       ctx = malloc_thing(stroke_job_context_t);
+       ctx->fd = strokefd;
+       ctx->this = this;
+       job = callback_job_create((callback_job_cb_t)process,
+                                                         ctx, (void*)stroke_job_context_destroy, this->job);
+       charon->processor->queue_job(charon->processor, (job_t*)job);
+       
+       return JOB_REQUEUE_FAIR;
+}
+
+
+/**
+ * initialize and open stroke socket
+ */
+static bool open_socket(private_stroke_socket_t *this)
+{
+       struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
+       mode_t old;
+       
+       /* set up unix socket */
+       this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (this->socket == -1)
+       {
+               DBG1(DBG_CFG, "could not create stroke socket");
+               return FALSE;
+       }
+       
+       unlink(socket_addr.sun_path);
+       old = umask(~(S_IRWXU | S_IRWXG));
+       if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
+       {
+               DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
+               close(this->socket);
+               return FALSE;
+       }
+       umask(old);
+       if (chown(socket_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0)
+       {
+               DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
+                        strerror(errno));
+       }
+       
+       if (listen(this->socket, 0) < 0)
+       {
+               DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
+               close(this->socket);
+               unlink(socket_addr.sun_path);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Implementation of stroke_socket_t.destroy
+ */
+static void destroy(private_stroke_socket_t *this)
+{
+       this->job->cancel(this->job);
+       charon->credentials->remove_set(charon->credentials, &this->ca->set);
+       charon->credentials->remove_set(charon->credentials, &this->cred->set);
+       charon->backends->remove_backend(charon->backends, &this->config->backend);
+       this->cred->destroy(this->cred);
+       this->ca->destroy(this->ca);
+       this->config->destroy(this->config);
+       this->control->destroy(this->control);
+       this->list->destroy(this->list);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+stroke_socket_t *stroke_socket_create()
+{
+       private_stroke_socket_t *this = malloc_thing(private_stroke_socket_t);
+       
+       this->public.destroy = (void(*)(stroke_socket_t*))destroy;
+       
+       if (!open_socket(this))
+       {
+               free(this);
+               return NULL;
+       }
+       
+       this->cred = stroke_cred_create();
+       this->ca = stroke_ca_create(this->cred);
+       this->config = stroke_config_create(this->cred);
+       this->control = stroke_control_create();
+       this->list = stroke_list_create();
+       
+       charon->credentials->add_set(charon->credentials, &this->ca->set);
+       charon->credentials->add_set(charon->credentials, &this->cred->set);
+       charon->backends->add_backend(charon->backends, &this->config->backend);
+       
+       this->job = callback_job_create((callback_job_cb_t)receive,
+                                                                       this, NULL, NULL);
+       charon->processor->queue_job(charon->processor, (job_t*)this->job);
+       
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/stroke/stroke_socket.h b/src/charon/plugins/stroke/stroke_socket.h
new file mode 100644 (file)
index 0000000..7bc9668
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup stroke_socket stroke_socket
+ * @{ @ingroup stroke
+ */
+
+#ifndef STROKE_SOCKET_H_
+#define STROKE_SOCKET_H_
+
+typedef struct stroke_socket_t stroke_socket_t;
+
+/**
+ * Stroke socket, opens UNIX communication socket, reads and dispatches.
+ */
+struct stroke_socket_t {
+               
+       /**
+     * Destroy a stroke_socket instance.
+     */
+    void (*destroy)(stroke_socket_t *this);
+};
+
+/**
+ * Create a stroke_socket instance.
+ */
+stroke_socket_t *stroke_socket_create();
+
+#endif /* STROKE_SOCKET_H_ @}*/