diff options
Diffstat (limited to 'src/charon/plugins/stroke')
-rw-r--r-- | src/charon/plugins/stroke/Makefile.in | 2 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_ca.c | 32 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_config.c | 107 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_control.c | 73 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_control.h | 7 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_cred.c | 75 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_list.c | 293 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_socket.c | 21 |
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**)§ion)) { @@ -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**)§ion)) { @@ -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**)¤t)) { @@ -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**)¤t)) { @@ -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); |