diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-05-25 19:01:36 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-05-25 19:01:36 +0000 |
commit | 1ac70afcc1f7d6d2738a34308810719b0976d29f (patch) | |
tree | 805f6ce2a15d1a717781d7cbceac8408a74b6b0c /src/libcharon/plugins/stroke/stroke_config.c | |
parent | ed7d79f96177044949744da10f4431c1d6242241 (diff) | |
download | vyos-strongswan-1ac70afcc1f7d6d2738a34308810719b0976d29f.tar.gz vyos-strongswan-1ac70afcc1f7d6d2738a34308810719b0976d29f.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.4.0)
Diffstat (limited to 'src/libcharon/plugins/stroke/stroke_config.c')
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c new file mode 100644 index 000000000..bbc1e7a31 --- /dev/null +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -0,0 +1,949 @@ +/* + * 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. + */ + +#include "stroke_config.h" + +#include <daemon.h> +#include <threading/mutex.h> +#include <utils/lexparser.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; + + /** + * ca sections + */ + stroke_ca_t *ca; + + /** + * credentials + */ + stroke_cred_t *cred; +}; + +/** + * 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) +{ + this->mutex->lock(this->mutex); + return enumerator_create_cleaner(this->list->create_enumerator(this->list), + (void*)this->mutex->unlock, this->mutex); +} + +/** + * filter function for ike configs + */ +static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) +{ + *out = (*in)->get_ike_cfg(*in); + return TRUE; +} + +/** + * 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) +{ + this->mutex->lock(this->mutex); + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)ike_filter, this->mutex, + (void*)this->mutex->unlock); +} + +/** + * 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, ¤t)) + { + /* 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; +} + +/** + * 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) +{ + stroke_end_t tmp_end; + ike_cfg_t *ike_cfg; + char *interface; + host_t *host; + + host = host_create_from_dns(msg->add_conn.other.address, 0, 0); + if (host) + { + interface = charon->kernel_interface->get_interface( + charon->kernel_interface, host); + host->destroy(host); + if (interface) + { + DBG2(DBG_CFG, "left is other host, swapping ends"); + tmp_end = msg->add_conn.me; + msg->add_conn.me = msg->add_conn.other; + msg->add_conn.other = tmp_end; + free(interface); + } + else + { + host = host_create_from_dns(msg->add_conn.me.address, 0, 0); + if (host) + { + interface = charon->kernel_interface->get_interface( + charon->kernel_interface, host); + host->destroy(host); + 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, + msg->add_conn.me.address, msg->add_conn.me.ikeport, + msg->add_conn.other.address, msg->add_conn.other.ikeport); + add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); + return ike_cfg; +} + +/** + * Add CRL constraint to config + */ +static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy) +{ + /* CRL/OCSP policy, for remote config only */ + if (!local) + { + switch (policy) + { + case CRL_STRICT_YES: + /* if yes, we require a GOOD validation */ + cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD); + break; + case CRL_STRICT_IFURI: + /* for ifuri, a SKIPPED validation is sufficient */ + cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED); + break; + default: + break; + } + } +} + +/** + * build authentication config + */ +static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, + stroke_msg_t *msg, bool local, bool primary) +{ + identification_t *identity; + certificate_t *certificate; + char *auth, *id, *cert, *ca; + stroke_end_t *end, *other_end; + auth_cfg_t *cfg; + char eap_buf[32]; + + /* select strings */ + if (local) + { + end = &msg->add_conn.me; + other_end = &msg->add_conn.other; + } + else + { + end = &msg->add_conn.other; + other_end = &msg->add_conn.me; + } + if (primary) + { + auth = end->auth; + id = end->id; + if (!id) + { /* leftid/rightid fallback to address */ + id = end->address; + } + cert = end->cert; + ca = end->ca; + if (ca && streq(ca, "%same")) + { + ca = other_end->ca; + } + } + else + { + auth = end->auth2; + id = end->id2; + if (local && !id) + { /* leftid2 falls back to leftid */ + id = end->id; + } + cert = end->cert2; + ca = end->ca2; + if (ca && streq(ca, "%same")) + { + ca = other_end->ca2; + } + } + + if (!auth) + { + if (primary) + { + if (local) + { /* "leftauth" not defined, fall back to deprecated "authby" */ + switch (msg->add_conn.auth_method) + { + default: + case AUTH_CLASS_PUBKEY: + auth = "pubkey"; + break; + case AUTH_CLASS_PSK: + auth = "psk"; + break; + case AUTH_CLASS_EAP: + auth = "eap"; + break; + } + } + else + { /* "rightauth" not defined, fall back to deprecated "eap" */ + if (msg->add_conn.eap_type) + { + if (msg->add_conn.eap_vendor) + { + snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d", + msg->add_conn.eap_type, + msg->add_conn.eap_vendor); + } + else + { + snprintf(eap_buf, sizeof(eap_buf), "eap-%d", + msg->add_conn.eap_type); + } + auth = eap_buf; + } + else + { /* not EAP => no constraints for this peer */ + auth = "any"; + } + } + } + else + { /* no second authentication round, fine */ + return NULL; + } + } + + cfg = auth_cfg_create(); + + /* add identity and peer certifcate */ + identity = identification_create_from_string(id); + if (cert) + { + certificate = this->cred->load_peer(this->cred, cert); + if (certificate) + { + if (local) + { + this->ca->check_for_hash_and_url(this->ca, certificate); + } + cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate); + if (identity->get_type(identity) == ID_ANY || + !certificate->has_subject(certificate, identity)) + { + DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, " + "defaulting to '%Y'", identity, + certificate->get_subject(certificate)); + identity->destroy(identity); + identity = certificate->get_subject(certificate); + identity = identity->clone(identity); + } + } + } + cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + + /* CA constraint */ + if (ca) + { + identity = identification_create_from_string(ca); + certificate = charon->credentials->get_cert(charon->credentials, + CERT_X509, KEY_ANY, identity, TRUE); + identity->destroy(identity); + if (certificate) + { + cfg->add(cfg, AUTH_RULE_CA_CERT, certificate); + } + else + { + DBG1(DBG_CFG, "CA certificate %s not found, discarding CA " + "constraint", ca); + } + } + + /* AC groups */ + if (end->groups) + { + enumerator_t *enumerator; + char *group; + + enumerator = enumerator_create_token(end->groups, ",", " "); + while (enumerator->enumerate(enumerator, &group)) + { + identity = identification_create_from_encoding(ID_IETF_ATTR_STRING, + chunk_create(group, strlen(group))); + cfg->add(cfg, AUTH_RULE_AC_GROUP, identity); + } + enumerator->destroy(enumerator); + } + + /* authentication metod (class, actually) */ + if (streq(auth, "pubkey") || + streq(auth, "rsasig") || streq(auth, "rsa") || + streq(auth, "ecdsasig") || streq(auth, "ecdsa")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + build_crl_policy(cfg, local, msg->add_conn.crl_policy); + } + else if (streq(auth, "psk") || streq(auth, "secret")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + } + else if (strneq(auth, "eap", 3)) + { + enumerator_t *enumerator; + char *str; + int i = 0, type = 0, vendor; + + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + + /* parse EAP string, format: eap[-type[-vendor]] */ + enumerator = enumerator_create_token(auth, "-", " "); + while (enumerator->enumerate(enumerator, &str)) + { + switch (i) + { + case 1: + type = eap_type_from_string(str); + if (!type) + { + type = atoi(str); + if (!type) + { + DBG1(DBG_CFG, "unknown EAP method: %s", str); + break; + } + } + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); + break; + case 2: + if (type) + { + vendor = atoi(str); + if (vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); + } + else + { + DBG1(DBG_CFG, "unknown EAP vendor: %s", str); + } + } + break; + default: + break; + } + i++; + } + enumerator->destroy(enumerator); + + if (msg->add_conn.eap_identity) + { + if (streq(msg->add_conn.eap_identity, "%identity")) + { + identity = identification_create_from_encoding(ID_ANY, + chunk_empty); + } + else + { + identity = identification_create_from_string( + msg->add_conn.eap_identity); + } + cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity); + } + } + else + { + if (!streq(auth, "any")) + { + DBG1(DBG_CFG, "authentication method %s unknown, fallback to any", + auth); + } + build_crl_policy(cfg, local, msg->add_conn.crl_policy); + } + return 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 *peer_id = NULL; + peer_cfg_t *mediated_by = NULL; + host_t *vip = NULL; + unique_policy_t unique; + u_int32_t rekey = 0, reauth = 0, over, jitter; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth_cfg; + +#ifdef ME + if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by) + { + DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection " + "at the same time, aborting"); + return NULL; + } + + if (msg->add_conn.ikeme.mediation) + { + /* force unique connections for mediation connections */ + msg->add_conn.unique = 1; + } + + if (msg->add_conn.ikeme.mediated_by) + { + mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends, + msg->add_conn.ikeme.mediated_by); + if (!mediated_by) + { + DBG1(DBG_CFG, "mediation connection '%s' not found, aborting", + msg->add_conn.ikeme.mediated_by); + 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.ikeme.mediated_by, msg->add_conn.name); + mediated_by->destroy(mediated_by); + return NULL; + } + if (msg->add_conn.ikeme.peerid) + { + peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid); + } + else if (msg->add_conn.other.id) + { + peer_id = identification_create_from_string(msg->add_conn.other.id); + } + } +#endif /* ME */ + + 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.sourceip_mask) + { + if (msg->add_conn.me.sourceip) + { + vip = host_create_from_string(msg->add_conn.me.sourceip, 0); + } + if (!vip) + { /* if it is set to something like %poolname, request an address */ + if (msg->add_conn.me.subnets) + { /* use the same address as in subnet, if any */ + if (strchr(msg->add_conn.me.subnets, '.')) + { + vip = host_create_any(AF_INET); + } + else + { + vip = host_create_any(AF_INET6); + } + } + else + { + if (strchr(ike_cfg->get_my_addr(ike_cfg), ':')) + { + vip = host_create_any(AF_INET6); + } + else + { + vip = host_create_any(AF_INET); + } + } + } + } + switch (msg->add_conn.unique) + { + case 1: /* yes */ + case 2: /* replace */ + unique = UNIQUE_REPLACE; + break; + case 3: /* keep */ + unique = UNIQUE_KEEP; + break; + default: /* no */ + unique = UNIQUE_NO; + break; + } + if (msg->add_conn.dpd.action == 0) + { /* dpdaction=none disables DPD */ + msg->add_conn.dpd.delay = 0; + } + + /* other.sourceip is managed in stroke_attributes. If it is set, we define + * the pool name as the connection name, which the attribute provider + * uses to serve pool addresses. */ + peer_cfg = peer_cfg_create(msg->add_conn.name, + msg->add_conn.ikev2 ? 2 : 1, ike_cfg, + 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_mask ? + msg->add_conn.name : msg->add_conn.other.sourceip, + msg->add_conn.ikeme.mediation, mediated_by, peer_id); + + /* build leftauth= */ + auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE); + if (auth_cfg) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE); + } + else + { /* we require at least one config on our side */ + peer_cfg->destroy(peer_cfg); + return NULL; + } + /* build leftauth2= */ + auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE); + if (auth_cfg) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE); + } + /* build rightauth= */ + auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE); + if (auth_cfg) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); + } + /* build rightauth2= */ + auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE); + if (auth_cfg) + { + peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE); + } + return peer_cfg; +} + +/** + * build a traffic selector from a stroke_end + */ +static void add_ts(private_stroke_config_t *this, + stroke_end_t *end, child_cfg_t *child_cfg, bool local) +{ + traffic_selector_t *ts; + + if (end->tohost) + { + ts = traffic_selector_create_dynamic(end->protocol, + end->port ? end->port : 0, end->port ? end->port : 65535); + child_cfg->add_traffic_selector(child_cfg, local, ts); + } + else + { + host_t *net; + + if (!end->subnets) + { + net = host_create_from_string(end->address, 0); + if (net) + { + ts = traffic_selector_create_from_subnet(net, 0, end->protocol, + end->port); + child_cfg->add_traffic_selector(child_cfg, local, ts); + } + } + else + { + char *del, *start, *bits; + + start = end->subnets; + do + { + int intbits = 0; + + del = strchr(start, ','); + if (del) + { + *del = '\0'; + } + bits = strchr(start, '/'); + if (bits) + { + *bits = '\0'; + intbits = atoi(bits + 1); + } + + net = host_create_from_string(start, 0); + if (net) + { + ts = traffic_selector_create_from_subnet(net, intbits, + end->protocol, end->port); + child_cfg->add_traffic_selector(child_cfg, local, ts); + } + else + { + DBG1(DBG_CFG, "invalid subnet: %s, skipped", start); + } + start = del + 1; + } + while (del); + } + } +} + +/** + * 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; + action_t dpd; + lifetime_cfg_t lifetime = { + .time = { + .life = msg->add_conn.rekey.ipsec_lifetime, + .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, + .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100 + }, + .bytes = { + .life = msg->add_conn.rekey.life_bytes, + .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes, + .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100 + }, + .packets = { + .life = msg->add_conn.rekey.life_packets, + .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets, + .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100 + } + }; + + switch (msg->add_conn.dpd.action) + { /* map startes magic values to our action type */ + case 2: /* =hold */ + dpd = ACTION_ROUTE; + break; + case 3: /* =restart */ + dpd = ACTION_RESTART; + break; + default: + dpd = ACTION_NONE; + break; + } + + child_cfg = child_cfg_create( + msg->add_conn.name, &lifetime, + msg->add_conn.me.updown, msg->add_conn.me.hostaccess, + msg->add_conn.mode, dpd, dpd, msg->add_conn.ipcomp, + msg->add_conn.inactivity); + child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode, + msg->add_conn.install_policy); + add_ts(this, &msg->add_conn.me, child_cfg, TRUE); + add_ts(this, &msg->add_conn.other, child_cfg, FALSE); + + 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; + } + + 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'", msg->add_conn.name); + 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; + bool deleted = FALSE; + + this->mutex->lock(this->mutex); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + bool keep = FALSE; + + /* 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, children); + child->destroy(child); + deleted = TRUE; + } + else + { + keep = TRUE; + } + } + children->destroy(children); + + /* if peer config matches, or has no children anymore, remove it */ + if (!keep || streq(peer->get_name(peer), msg->del_conn.name)) + { + this->list->remove_at(this->list, enumerator); + peer->destroy(peer); + deleted = TRUE; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (deleted) + { + DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name); + } + else + { + DBG1(DBG_CFG, "connection '%s' not found", 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_ca_t *ca, 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_TYPE_RECURSIVE); + this->ca = ca; + this->cred = cred; + + return &this->public; +} + |