summaryrefslogtreecommitdiff
path: root/src/charon/plugins/stroke
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/plugins/stroke')
-rw-r--r--src/charon/plugins/stroke/Makefile.in2
-rw-r--r--src/charon/plugins/stroke/stroke_ca.c32
-rw-r--r--src/charon/plugins/stroke/stroke_config.c107
-rw-r--r--src/charon/plugins/stroke/stroke_control.c73
-rw-r--r--src/charon/plugins/stroke/stroke_control.h7
-rw-r--r--src/charon/plugins/stroke/stroke_cred.c75
-rw-r--r--src/charon/plugins/stroke/stroke_list.c293
-rw-r--r--src/charon/plugins/stroke/stroke_socket.c21
8 files changed, 526 insertions, 84 deletions
diff --git a/src/charon/plugins/stroke/Makefile.in b/src/charon/plugins/stroke/Makefile.in
index a528377d0..1ff213165 100644
--- a/src/charon/plugins/stroke/Makefile.in
+++ b/src/charon/plugins/stroke/Makefile.in
@@ -190,6 +190,8 @@ localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
piddir = @piddir@
diff --git a/src/charon/plugins/stroke/stroke_ca.c b/src/charon/plugins/stroke/stroke_ca.c
index 897365eb0..8569f49c3 100644
--- a/src/charon/plugins/stroke/stroke_ca.c
+++ b/src/charon/plugins/stroke/stroke_ca.c
@@ -16,10 +16,12 @@
* $Id$
*/
+#define _GNU_SOURCE
+#include <pthread.h>
+
#include "stroke_ca.h"
#include "stroke_cred.h"
-#include <utils/mutex.h>
#include <utils/linked_list.h>
#include <crypto/hashers/hasher.h>
@@ -38,9 +40,9 @@ struct private_stroke_ca_t {
stroke_ca_t public;
/**
- * mutex to lock access to list
+ * read-write lock to lists
*/
- mutex_t *mutex;
+ pthread_rwlock_t lock;
/**
* list of starters CA sections and its certificates (ca_section_t)
@@ -134,7 +136,7 @@ typedef struct {
*/
static void cdp_data_destroy(cdp_data_t *data)
{
- data->this->mutex->unlock(data->this->mutex);
+ pthread_rwlock_unlock(&data->this->lock);
free(data);
}
@@ -234,7 +236,7 @@ static enumerator_t *create_cdp_enumerator(private_stroke_ca_t *this,
data->type = type;
data->id = id;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
return enumerator_create_nested(this->sections->create_enumerator(this->sections),
(type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp,
data, (void*)cdp_data_destroy);
@@ -276,9 +278,9 @@ static void add(private_stroke_ca_t *this, stroke_msg_t *msg)
{
ca->certuribase = strdup(msg->add_ca.certuribase);
}
- this->mutex->lock(this->mutex);
+ pthread_rwlock_wrlock(&this->lock);
this->sections->insert_last(this->sections, ca);
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
}
}
@@ -291,7 +293,7 @@ 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);
+ pthread_rwlock_wrlock(&this->lock);
enumerator = this->sections->create_enumerator(this->sections);
while (enumerator->enumerate(enumerator, &ca))
{
@@ -303,7 +305,7 @@ static void del(private_stroke_ca_t *this, stroke_msg_t *msg)
ca = NULL;
}
enumerator->destroy(enumerator);
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
if (ca == NULL)
{
DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name);
@@ -354,7 +356,7 @@ static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cer
return;
}
- this->mutex->lock(this->mutex);
+ pthread_rwlock_wrlock(&this->lock);
enumerator = this->sections->create_enumerator(this->sections);
while (enumerator->enumerate(enumerator, (void**)&section))
{
@@ -370,7 +372,7 @@ static void check_for_hash_and_url(private_stroke_ca_t *this, certificate_t* cer
}
}
enumerator->destroy(enumerator);
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
hasher->destroy(hasher);
}
@@ -384,7 +386,7 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
ca_section_t *section;
enumerator_t *enumerator;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
enumerator = this->sections->create_enumerator(this->sections);
while (enumerator->enumerate(enumerator, (void**)&section))
{
@@ -417,7 +419,7 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
}
}
enumerator->destroy(enumerator);
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
}
/**
@@ -426,7 +428,7 @@ static void list(private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out)
static void destroy(private_stroke_ca_t *this)
{
this->sections->destroy_function(this->sections, (void*)ca_section_destroy);
- this->mutex->destroy(this->mutex);
+ pthread_rwlock_destroy(&this->lock);
free(this);
}
@@ -449,7 +451,7 @@ stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
this->public.destroy = (void(*)(stroke_ca_t*))destroy;
this->sections = linked_list_create();
- this->mutex = mutex_create(MUTEX_RECURSIVE);
+ pthread_rwlock_init(&this->lock, NULL);
this->cred = cred;
return &this->public;
diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c
index 0069191b5..f10fe2051 100644
--- a/src/charon/plugins/stroke/stroke_config.c
+++ b/src/charon/plugins/stroke/stroke_config.c
@@ -209,7 +209,7 @@ static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *nam
*/
static identification_t *update_peerid(certificate_t *cert, identification_t *id)
{
- if (!cert->has_subject(cert, id))
+ if (id->get_type(id) == ID_ANY || !cert->has_subject(cert, id))
{
DBG1(DBG_CFG, " peerid %D not confirmed by certificate, "
"defaulting to subject DN", id);
@@ -335,7 +335,9 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
* 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)
+ stroke_msg_t *msg, ike_cfg_t *ike_cfg,
+ identification_t **my_issuer,
+ identification_t **other_issuer)
{
identification_t *me, *other, *peer_id = NULL;
peer_cfg_t *mediated_by = NULL;
@@ -420,6 +422,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
if (cert)
{
+ identification_t *issuer = cert->get_issuer(cert);
+
+ *my_issuer = issuer->clone(issuer);
this->ca->check_for_hash_and_url(this->ca, cert);
me = update_peerid(cert, me);
cert->destroy(cert);
@@ -430,6 +435,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
if (cert)
{
+ identification_t *issuer = cert->get_issuer(cert);
+
+ *other_issuer = issuer->clone(issuer);
other = update_peerid(cert, other);
cert->destroy(cert);
}
@@ -499,8 +507,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
* uses to serve pool addresses. */
return peer_cfg_create(msg->add_conn.name,
msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
- msg->add_conn.me.sendcert, unique, msg->add_conn.auth_method,
- msg->add_conn.eap_type, msg->add_conn.eap_vendor,
+ msg->add_conn.me.sendcert, unique,
msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
msg->add_conn.mobike, msg->add_conn.dpd.delay,
vip, msg->add_conn.other.sourceip_size ?
@@ -512,18 +519,15 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
* 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)
+ stroke_msg_t *msg, auth_info_t *auth,
+ identification_t *my_ca,
+ identification_t *other_ca)
{
- identification_t *my_ca = NULL, *other_ca = NULL;
+ identification_t *id;
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:
@@ -540,6 +544,11 @@ static void build_auth_info(private_stroke_config_t *this,
if (msg->add_conn.me.ca)
{
+ if (my_ca)
+ {
+ my_ca->destroy(my_ca);
+ my_ca = NULL;
+ }
if (streq(msg->add_conn.me.ca, "%same"))
{
my_ca_same = TRUE;
@@ -549,8 +558,14 @@ static void build_auth_info(private_stroke_config_t *this,
my_ca = identification_create_from_string(msg->add_conn.me.ca);
}
}
+
if (msg->add_conn.other.ca)
{
+ if (other_ca)
+ {
+ other_ca->destroy(other_ca);
+ other_ca = NULL;
+ }
if (streq(msg->add_conn.other.ca, "%same"))
{
other_ca_same = TRUE;
@@ -560,6 +575,7 @@ static void build_auth_info(private_stroke_config_t *this,
other_ca = identification_create_from_string(msg->add_conn.other.ca);
}
}
+
if (other_ca_same && my_ca)
{
other_ca = my_ca->clone(my_ca);
@@ -585,6 +601,7 @@ static void build_auth_info(private_stroke_config_t *this,
}
other_ca->destroy(other_ca);
}
+
if (my_ca)
{
DBG2(DBG_CFG, " my ca: %D", my_ca);
@@ -601,6 +618,66 @@ static void build_auth_info(private_stroke_config_t *this,
}
my_ca->destroy(my_ca);
}
+ auth->add_item(auth, AUTHN_AUTH_CLASS, &msg->add_conn.auth_method);
+ if (msg->add_conn.eap_type)
+ {
+ auth->add_item(auth, AUTHN_EAP_TYPE, &msg->add_conn.eap_type);
+ if (msg->add_conn.eap_vendor)
+ {
+ auth->add_item(auth, AUTHN_EAP_VENDOR, &msg->add_conn.eap_vendor);
+ }
+ }
+
+ if (msg->add_conn.eap_identity)
+ {
+ if (streq(msg->add_conn.eap_identity, "%identity"))
+ {
+ id = identification_create_from_encoding(ID_ANY, chunk_empty);
+ }
+ else
+ {
+ id = identification_create_from_encoding(ID_EAP, chunk_create(
+ msg->add_conn.eap_identity,
+ strlen(msg->add_conn.eap_identity)));
+ }
+ auth->add_item(auth, AUTHN_EAP_IDENTITY, id);
+ id->destroy(id);
+ }
+
+ if (msg->add_conn.other.groups)
+ {
+ chunk_t line = { msg->add_conn.other.groups,
+ strlen(msg->add_conn.other.groups) };
+
+ while (eat_whitespace(&line))
+ {
+ chunk_t group;
+
+ /* extract the next comma-separated group attribute */
+ if (!extract_token(&group, ',', &line))
+ {
+ group = line;
+ line.len = 0;
+ }
+
+ /* remove any trailing spaces */
+ while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
+ {
+ group.len--;
+ }
+
+ /* add the group attribute to the list */
+ if (group.len > 0)
+ {
+ identification_t *ac_group;
+
+ ac_group = identification_create_from_encoding(
+ ID_IETF_ATTR_STRING, group);
+ auth->add_item(auth, AUTHZ_AC_GROUP, ac_group);
+ ac_group->destroy(ac_group);
+ }
+ }
+ }
}
/**
@@ -696,7 +773,7 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
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, dpd, ACTION_NONE, msg->add_conn.ipcomp);
+ msg->add_conn.mode, dpd, dpd, msg->add_conn.ipcomp);
add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
@@ -714,6 +791,7 @@ 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;
+ identification_t *my_issuer = NULL, *other_issuer = NULL;
enumerator_t *enumerator;
bool use_existing = FALSE;
@@ -722,14 +800,15 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg)
{
return;
}
- peer_cfg = build_peer_cfg(this, msg, ike_cfg);
+ peer_cfg = build_peer_cfg(this, msg, ike_cfg, &my_issuer, &other_issuer);
if (!peer_cfg)
{
ike_cfg->destroy(ike_cfg);
return;
}
- build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg));
+ build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg),
+ my_issuer, other_issuer);
enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
while (enumerator->enumerate(enumerator, &existing))
{
diff --git a/src/charon/plugins/stroke/stroke_control.c b/src/charon/plugins/stroke/stroke_control.c
index 2956b1576..ed9dd7b16 100644
--- a/src/charon/plugins/stroke/stroke_control.c
+++ b/src/charon/plugins/stroke/stroke_control.c
@@ -18,6 +18,7 @@
#include "stroke_control.h"
#include <daemon.h>
+#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_stroke_control_t private_stroke_control_t;
@@ -55,7 +56,7 @@ struct stroke_log_info_t {
* 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)
+ ike_sa_t *ike_sa, void *data, char *format, va_list args)
{
if (level <= info->level)
{
@@ -240,6 +241,75 @@ static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *o
}
/**
+ * Implementation of stroke_control_t.terminate_srcip.
+ */
+static void terminate_srcip(private_stroke_control_t *this,
+ stroke_msg_t *msg, FILE *out)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ host_t *start = NULL, *end = NULL, *vip;
+ chunk_t chunk_start, chunk_end, chunk_vip;
+
+ if (msg->terminate_srcip.start)
+ {
+ start = host_create_from_string(msg->terminate_srcip.start, 0);
+ }
+ if (!start)
+ {
+ DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
+ return;
+ }
+ chunk_start = start->get_address(start);
+ if (msg->terminate_srcip.end)
+ {
+ end = host_create_from_string(msg->terminate_srcip.end, 0);
+ if (!end)
+ {
+ DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
+ start->destroy(start);
+ return;
+ }
+ chunk_end = end->get_address(end);
+ }
+
+ enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (!vip)
+ {
+ continue;
+ }
+ if (!end)
+ {
+ if (!vip->ip_equals(vip, start))
+ {
+ continue;
+ }
+ }
+ else
+ {
+ chunk_vip = vip->get_address(vip);
+ if (chunk_vip.len != chunk_start.len ||
+ chunk_vip.len != chunk_end.len ||
+ memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
+ memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
+ {
+ continue;
+ }
+ }
+
+ /* schedule delete asynchronously */
+ charon->processor->queue_job(charon->processor, (job_t*)
+ delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
+ }
+ enumerator->destroy(enumerator);
+ start->destroy(start);
+ DESTROY_IF(end);
+}
+
+/**
* Implementation of stroke_control_t.route.
*/
static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
@@ -336,6 +406,7 @@ stroke_control_t *stroke_control_create()
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.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
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;
diff --git a/src/charon/plugins/stroke/stroke_control.h b/src/charon/plugins/stroke/stroke_control.h
index 917679209..926964458 100644
--- a/src/charon/plugins/stroke/stroke_control.h
+++ b/src/charon/plugins/stroke/stroke_control.h
@@ -49,6 +49,13 @@ struct stroke_control_t {
void (*terminate)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
/**
+ * Terminate a connection by peers virtual IP.
+ *
+ * @param msg stroke message
+ */
+ void (*terminate_srcip)(stroke_control_t *this, stroke_msg_t *msg, FILE *out);
+
+ /**
* Route a connection.
*
* @param msg stroke message
diff --git a/src/charon/plugins/stroke/stroke_cred.c b/src/charon/plugins/stroke/stroke_cred.c
index 223500488..c699a083e 100644
--- a/src/charon/plugins/stroke/stroke_cred.c
+++ b/src/charon/plugins/stroke/stroke_cred.c
@@ -15,17 +15,18 @@
* $Id$
*/
-#include "stroke_cred.h"
-#include "stroke_shared_key.h"
-
+#define _GNU_SOURCE
+#include <pthread.h>
#include <sys/stat.h>
#include <limits.h>
+#include "stroke_cred.h"
+#include "stroke_shared_key.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/pem.h>
#include <daemon.h>
@@ -70,9 +71,9 @@ struct private_stroke_cred_t {
linked_list_t *private;
/**
- * mutex to lock lists above
+ * read-write lock to lists
*/
- mutex_t *mutex;
+ pthread_rwlock_t lock;
/**
* cache CRLs to disk?
@@ -93,7 +94,7 @@ typedef struct {
*/
static void id_data_destroy(id_data_t *data)
{
- data->this->mutex->unlock(data->this->mutex);
+ pthread_rwlock_unlock(&data->this->lock);
free(data);
}
@@ -139,7 +140,7 @@ static enumerator_t* create_private_enumerator(private_stroke_cred_t *this,
data->this = this;
data->id = id;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
return enumerator_create_filter(this->private->create_enumerator(this->private),
(void*)private_filter, data,
(void*)id_data_destroy);
@@ -240,7 +241,7 @@ static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this,
data->this = this;
data->id = id;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
return enumerator_create_filter(this->certs->create_enumerator(this->certs),
(cert == CERT_X509_CRL)? (void*)crl_filter : (void*)ac_filter,
data, (void*)id_data_destroy);
@@ -253,7 +254,7 @@ static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this,
data->this = this;
data->id = id;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
return enumerator_create_filter(this->certs->create_enumerator(this->certs),
(void*)certs_filter, data,
(void*)id_data_destroy);
@@ -271,7 +272,7 @@ typedef struct {
*/
static void shared_data_destroy(shared_data_t *data)
{
- data->this->mutex->unlock(data->this->mutex);
+ pthread_rwlock_unlock(&data->this->lock);
free(data);
}
@@ -323,7 +324,7 @@ static enumerator_t* create_shared_enumerator(private_stroke_cred_t *this,
data->me = me;
data->other = other;
data->type = type;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
return enumerator_create_filter(this->shared->create_enumerator(this->shared),
(void*)shared_filter, data,
(void*)shared_data_destroy);
@@ -338,7 +339,7 @@ static certificate_t* add_cert(private_stroke_cred_t *this, certificate_t *cert)
enumerator_t *enumerator;
bool new = TRUE;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_rdlock(&this->lock);
enumerator = this->certs->create_enumerator(this->certs);
while (enumerator->enumerate(enumerator, (void**)&current))
{
@@ -357,7 +358,7 @@ static certificate_t* add_cert(private_stroke_cred_t *this, certificate_t *cert)
{
this->certs->insert_last(this->certs, cert);
}
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
return cert;
}
@@ -399,7 +400,7 @@ static bool add_crl(private_stroke_cred_t *this, crl_t* crl)
enumerator_t *enumerator;
bool new = TRUE, found = FALSE;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_wrlock(&this->lock);
enumerator = this->certs->create_enumerator(this->certs);
while (enumerator->enumerate(enumerator, (void**)&current))
{
@@ -447,7 +448,7 @@ static bool add_crl(private_stroke_cred_t *this, crl_t* crl)
{
this->certs->insert_last(this->certs, cert);
}
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
return new;
}
@@ -458,9 +459,9 @@ static bool add_ac(private_stroke_cred_t *this, ac_t* ac)
{
certificate_t *cert = &ac->certificate;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_wrlock(&this->lock);
this->certs->insert_last(this->certs, cert);
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
return TRUE;
}
@@ -697,7 +698,7 @@ static void load_secrets(private_stroke_cred_t *this)
fclose(fd);
src = chunk;
- this->mutex->lock(this->mutex);
+ pthread_rwlock_wrlock(&this->lock);
while (this->shared->remove_last(this->shared,
(void**)&shared) == SUCCESS)
{
@@ -782,6 +783,7 @@ static void load_secrets(private_stroke_cred_t *this)
{
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
+ free(chunk.ptr);
if (key)
{
DBG1(DBG_CFG, " loaded private key file '%s'", path);
@@ -826,20 +828,27 @@ static void load_secrets(private_stroke_cred_t *this)
{
continue;
}
-
- /* NULL terminate the ID string */
- *(id.ptr + id.len) = '\0';
-
- peer_id = identification_create_from_string(id.ptr);
- if (peer_id == NULL)
+
+ if (type == SHARED_EAP)
{
- DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
- goto error;
+ /* we use a special EAP identity type for EAP secrets */
+ peer_id = identification_create_from_encoding(ID_EAP, id);
}
- if (peer_id->get_type(peer_id) == ID_ANY)
+ else
{
- peer_id->destroy(peer_id);
- 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);
@@ -859,7 +868,7 @@ static void load_secrets(private_stroke_cred_t *this)
}
}
error:
- this->mutex->unlock(this->mutex);
+ pthread_rwlock_unlock(&this->lock);
chunk_clear(&chunk);
}
@@ -940,7 +949,7 @@ 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);
+ pthread_rwlock_destroy(&this->lock);
free(this);
}
@@ -965,7 +974,7 @@ stroke_cred_t *stroke_cred_create()
this->certs = linked_list_create();
this->shared = linked_list_create();
this->private = linked_list_create();
- this->mutex = mutex_create(MUTEX_RECURSIVE);
+ pthread_rwlock_init(&this->lock, NULL);
load_certs(this);
load_secrets(this);
diff --git a/src/charon/plugins/stroke/stroke_list.c b/src/charon/plugins/stroke/stroke_list.c
index 44699ba0a..d531dca47 100644
--- a/src/charon/plugins/stroke/stroke_list.c
+++ b/src/charon/plugins/stroke/stroke_list.c
@@ -22,6 +22,7 @@
#include <credentials/certificates/x509.h>
#include <credentials/certificates/ac.h>
#include <credentials/certificates/crl.h>
+#include <config/peer_cfg.h>
/* warning intervals for list functions */
#define CERT_WARNING_INTERVAL 30 /* days */
@@ -47,6 +48,23 @@ struct private_stroke_list_t {
};
/**
+ * get the authentication class of a config
+ */
+auth_class_t get_auth_class(peer_cfg_t *config)
+{
+ auth_class_t *class;
+ auth_info_t *auth_info;
+
+ auth_info = config->get_auth(config);
+ if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class))
+ {
+ return *class;
+ }
+ /* fallback to pubkey authentication */
+ return AUTH_CLASS_PUBKEY;
+}
+
+/**
* log an IKE_SA to out
*/
static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
@@ -80,7 +98,8 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
}
if (reauth)
{
- fprintf(out, ", reauthentication in %V", &reauth);
+ fprintf(out, ", %N reauthentication in %V", auth_class_names,
+ get_auth_class(ike_sa->get_peer_cfg(ike_sa)), &reauth);
}
if (!rekey && !reauth)
{
@@ -108,7 +127,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
encryption_algorithm_t encr_alg;
integrity_algorithm_t int_alg;
size_t encr_len, int_len;
- mode_t mode;
+ ipsec_mode_t mode;
child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
&int_alg, &int_len, &rekey, &use_in, &use_out,
@@ -117,15 +136,25 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
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);
+ ipsec_mode_names, mode);
if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
{
+ u_int16_t my_cpi = child_sa->get_cpi(child_sa, TRUE);
+ u_int16_t other_cpi = child_sa->get_cpi(child_sa, FALSE);
+
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)));
-
+ ntohl(child_sa->get_spi(child_sa, TRUE)),
+ ntohl(child_sa->get_spi(child_sa, FALSE)));
+
+ /* Is IPCOMP activated ? */
+ if (my_cpi && other_cpi)
+ {
+ fprintf(out, ", IPCOMP CPIs: %.4x_i %.4x_o",
+ ntohs(my_cpi), ntohs(other_cpi));
+ }
+
if (all)
{
fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
@@ -198,21 +227,20 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
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, *plugin;
bool found = FALSE;
- time_t uptime;
-
- name = msg->status.name;
+ char *name = msg->status.name;
if (all)
{
- uptime = time(NULL) - this->uptime;
+ peer_cfg_t *peer_cfg;
+ char *plugin;
+ host_t *host;
+ u_int32_t dpd;
+ time_t uptime = time(NULL) - this->uptime;
+
fprintf(out, "Performance:\n");
fprintf(out, " uptime: %V, since %#T\n", &uptime, &this->uptime, FALSE);
fprintf(out, " worker threads: %d idle of %d,",
@@ -231,40 +259,154 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
enumerator->destroy(enumerator);
fprintf(out, "\n");
- iterator = charon->kernel_interface->create_address_iterator(
- charon->kernel_interface);
+ enumerator = charon->kernel_interface->create_address_enumerator(
+ charon->kernel_interface, FALSE, FALSE);
fprintf(out, "Listening IP addresses:\n");
- while (iterator->iterate(iterator, (void**)&host))
+ while (enumerator->enumerate(enumerator, (void**)&host))
{
fprintf(out, " %H\n", host);
}
- iterator->destroy(iterator);
+ enumerator->destroy(enumerator);
fprintf(out, "Connections:\n");
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
{
+ void *ptr;
+ certificate_t *cert;
+ auth_item_t item;
+ auth_info_t *auth;
+ enumerator_t *auth_enumerator;
+ identification_t *my_ca = NULL, *other_ca = NULL;
+ identification_t *eap_identity = NULL;
+ u_int32_t *eap_type = NULL;
+ bool ac_groups = FALSE;
+
if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
(name && !streq(name, peer_cfg->get_name(peer_cfg))))
{
continue;
}
+ /* determine any required CAs, EAP type, EAP identity,
+ * and the presence of AC groups
+ */
+ auth = peer_cfg->get_auth(peer_cfg);
+ auth_enumerator = auth->create_item_enumerator(auth);
+ while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
+ {
+ switch (item)
+ {
+ case AUTHN_EAP_TYPE:
+ eap_type = (u_int32_t *)ptr;
+ break;
+ case AUTHN_EAP_IDENTITY:
+ eap_identity = (identification_t *)ptr;
+ break;
+ case AUTHN_CA_CERT:
+ cert = (certificate_t *)ptr;
+ my_ca = cert->get_subject(cert);
+ break;
+ case AUTHN_CA_CERT_NAME:
+ my_ca = (identification_t *)ptr;
+ break;
+ case AUTHZ_CA_CERT:
+ cert = (certificate_t *)ptr;
+ other_ca = cert->get_subject(cert);
+ break;
+ case AUTHZ_CA_CERT_NAME:
+ other_ca = (identification_t *)ptr;
+ break;
+ case AUTHZ_AC_GROUP:
+ ac_groups = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ auth_enumerator->destroy(auth_enumerator);
+
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
fprintf(out, "%12s: %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg),
ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
- /* TODO: list CAs and groups */
+ if (my_ca || other_ca)
+ {
+ fprintf(out, "%12s: CAs: ", peer_cfg->get_name(peer_cfg));
+ if (my_ca)
+ {
+ fprintf(out, "\"%D\"...", my_ca);
+ }
+ else
+ {
+ fprintf(out, "%%any...");
+ }
+ if (other_ca)
+ {
+ fprintf(out, "\"%D\"\n", other_ca);
+ }
+ else
+ {
+ fprintf(out, "%%any\n");
+ }
+ }
+
+ if (ac_groups)
+ {
+ bool first = TRUE;
+
+ fprintf(out, "%12s: groups: ", peer_cfg->get_name(peer_cfg));
+ auth_enumerator = auth->create_item_enumerator(auth);
+ while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
+ {
+ if (item == AUTHZ_AC_GROUP)
+ {
+ identification_t *group = (identification_t *)ptr;
+
+ fprintf(out, "%s%D", first? "":", ", group);
+ first = FALSE;
+ }
+ }
+ auth_enumerator->destroy(auth_enumerator);
+ fprintf(out, "\n");
+ }
+
+ fprintf(out, "%12s: %N ", peer_cfg->get_name(peer_cfg),
+ auth_class_names, get_auth_class(peer_cfg));
+ if (eap_type)
+ {
+ fprintf(out, "and %N ", eap_type_names, *eap_type);
+ }
+ fprintf(out, "authentication");
+ if (eap_identity)
+ {
+ fprintf(out, ", EAP identity: '%D'", eap_identity);
+ }
+ dpd = peer_cfg->get_dpd(peer_cfg);
+ if (dpd)
+ {
+ fprintf(out, ", dpddelay=%us", dpd);
+ }
+ fprintf(out, "\n");
+
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),
+ fprintf(out, "%12s: %#R=== %#R", 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));
+
+ if (dpd)
+ {
+ fprintf(out, ", dpdaction=%N", action_names,
+ child_cfg->get_dpd_action(child_cfg));
+ }
+ fprintf(out, "\n");
}
children->destroy(children);
}
@@ -365,6 +507,53 @@ static linked_list_t* create_unique_cert_list(certificate_type_t type)
}
/**
+ * list all raw public keys
+ */
+static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
+{
+ bool first = TRUE;
+
+ enumerator_t *enumerator = list->create_enumerator(list);
+ certificate_t *cert;
+
+ while (enumerator->enumerate(enumerator, (void**)&cert))
+ {
+ public_key_t *public = cert->get_public_key(cert);
+
+ if (public)
+ {
+ private_key_t *private = NULL;
+ identification_t *id, *keyid;
+
+ if (first)
+ {
+ fprintf(out, "\n");
+ fprintf(out, "List of Raw Public Keys:\n");
+ first = FALSE;
+ }
+ fprintf(out, "\n");
+
+ /* list public key information */
+ 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);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
* list all X.509 certificates matching the flags
*/
static void stroke_list_certs(linked_list_t *list, char *label,
@@ -649,12 +838,71 @@ static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out)
}
/**
+ * List of registered cryptographical algorithms
+ */
+static void list_algs(FILE *out)
+{
+ enumerator_t *enumerator;
+ encryption_algorithm_t encryption;
+ integrity_algorithm_t integrity;
+ hash_algorithm_t hash;
+ pseudo_random_function_t prf;
+ diffie_hellman_group_t group;
+
+ fprintf(out, "\n");
+ fprintf(out, "List of registered IKEv2 Algorithms:\n");
+ fprintf(out, "\n encryption: ");
+ enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &encryption))
+ {
+ fprintf(out, "%N ", encryption_algorithm_names, encryption);
+ }
+ enumerator->destroy(enumerator);
+ fprintf(out, "\n integrity: ");
+ enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &integrity))
+ {
+ fprintf(out, "%N ", integrity_algorithm_names, integrity);
+ }
+ enumerator->destroy(enumerator);
+ fprintf(out, "\n hasher: ");
+ enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &hash))
+ {
+ fprintf(out, "%N ", hash_algorithm_names, hash);
+ }
+ enumerator->destroy(enumerator);
+ fprintf(out, "\n prf: ");
+ enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &prf))
+ {
+ fprintf(out, "%N ", pseudo_random_function_names, prf);
+ }
+ enumerator->destroy(enumerator);
+ fprintf(out, "\n dh-group: ");
+ enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &group))
+ {
+ fprintf(out, "%N ", diffie_hellman_group_names, group);
+ }
+ enumerator->destroy(enumerator);
+ fprintf(out, "\n");
+}
+
+/**
* Implementation of stroke_list_t.list.
*/
static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
{
linked_list_t *cert_list = NULL;
+ if (msg->list.flags & LIST_PUBKEYS)
+ {
+ linked_list_t *pubkey_list = create_unique_cert_list(CERT_TRUSTED_PUBKEY);
+
+ stroke_list_pubkeys(pubkey_list, msg->list.utc, out);
+ pubkey_list->destroy_offset(pubkey_list, offsetof(certificate_t, destroy));
+ }
if (msg->list.flags & (LIST_CERTS | LIST_CACERTS | LIST_OCSPCERTS | LIST_AACERTS))
{
cert_list = create_unique_cert_list(CERT_X509);
@@ -698,8 +946,13 @@ static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
linked_list_t *ocsp_list = create_unique_cert_list(CERT_X509_OCSP_RESPONSE);
stroke_list_ocsp(ocsp_list, msg->list.utc, out);
+
ocsp_list->destroy_offset(ocsp_list, offsetof(certificate_t, destroy));
}
+ if (msg->list.flags & LIST_ALGS)
+ {
+ list_algs(out);
+ }
DESTROY_OFFSET_IF(cert_list, offsetof(certificate_t, destroy));
}
diff --git a/src/charon/plugins/stroke/stroke_socket.c b/src/charon/plugins/stroke/stroke_socket.c
index 92e295a0c..175322aa8 100644
--- a/src/charon/plugins/stroke/stroke_socket.c
+++ b/src/charon/plugins/stroke/stroke_socket.c
@@ -169,10 +169,12 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
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.eap_identity);
pop_string(msg, &msg->add_conn.algorithms.ike);
pop_string(msg, &msg->add_conn.algorithms.esp);
pop_string(msg, &msg->add_conn.ikeme.mediated_by);
pop_string(msg, &msg->add_conn.ikeme.peerid);
+ DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
@@ -215,6 +217,20 @@ static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, F
DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
this->control->terminate(this->control, msg, out);
+}
+
+/**
+ * terminate a connection by peers virtual IP
+ */
+static void stroke_terminate_srcip(private_stroke_socket_t *this,
+ stroke_msg_t *msg, FILE *out)
+{
+ pop_string(msg, &msg->terminate_srcip.start);
+ pop_string(msg, &msg->terminate_srcip.end);
+ DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s",
+ msg->terminate_srcip.start, msg->terminate_srcip.end);
+
+ this->control->terminate_srcip(this->control, msg, out);
}
/**
@@ -430,6 +446,9 @@ static job_requeue_t process(stroke_job_context_t *ctx)
case STR_TERMINATE:
stroke_terminate(this, msg, out);
break;
+ case STR_TERMINATE_SRCIP:
+ stroke_terminate_srcip(this, msg, out);
+ break;
case STR_STATUS:
stroke_status(this, msg, out, FALSE);
break;
@@ -537,7 +556,7 @@ static bool open_socket(private_stroke_socket_t *this)
strerror(errno));
}
- if (listen(this->socket, 0) < 0)
+ if (listen(this->socket, 10) < 0)
{
DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
close(this->socket);