force unique connections for mediation connections
[strongswan.git] / src / charon / plugins / stroke / stroke_config.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "stroke_config.h"
19
20 #include <daemon.h>
21 #include <utils/mutex.h>
22 #include <utils/lexparser.h>
23
24 typedef struct private_stroke_config_t private_stroke_config_t;
25
26 /**
27 * private data of stroke_config
28 */
29 struct private_stroke_config_t {
30
31 /**
32 * public functions
33 */
34 stroke_config_t public;
35
36 /**
37 * list of peer_cfg_t
38 */
39 linked_list_t *list;
40
41 /**
42 * mutex to lock config list
43 */
44 mutex_t *mutex;
45
46 /**
47 * ca sections
48 */
49 stroke_ca_t *ca;
50
51 /**
52 * credentials
53 */
54 stroke_cred_t *cred;
55 };
56
57 /**
58 * data to pass peer_filter
59 */
60 typedef struct {
61 private_stroke_config_t *this;
62 identification_t *me;
63 identification_t *other;
64 } peer_data_t;
65
66 /**
67 * destroy id enumerator data and unlock list
68 */
69 static void peer_data_destroy(peer_data_t *data)
70 {
71 data->this->mutex->unlock(data->this->mutex);
72 free(data);
73 }
74
75 /**
76 * filter function for peer configs
77 */
78 static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out)
79 {
80 bool match_me = FALSE, match_other = FALSE;
81 identification_t *me, *other;
82
83 me = (*in)->get_my_id(*in);
84 other = (*in)->get_other_id(*in);
85
86 /* own ID may have wildcards in data (no IDr payload) or in config */
87 match_me = (!data->me || data->me->matches(data->me, me) ||
88 me->matches(me, data->me));
89 /* others ID has wildcards in config only */
90 match_other = (!data->other || data->other->matches(data->other, other));
91
92 if (match_me && match_other)
93 {
94 *out = *in;
95 return TRUE;
96 }
97 return FALSE;
98 }
99
100 /**
101 * Implementation of backend_t.create_peer_cfg_enumerator.
102 */
103 static enumerator_t* create_peer_cfg_enumerator(private_stroke_config_t *this,
104 identification_t *me,
105 identification_t *other)
106 {
107 peer_data_t *data;
108
109 data = malloc_thing(peer_data_t);
110 data->this = this;
111 data->me = me;
112 data->other = other;
113
114 this->mutex->lock(this->mutex);
115 return enumerator_create_filter(this->list->create_enumerator(this->list),
116 (void*)peer_filter, data,
117 (void*)peer_data_destroy);
118 }
119
120 /**
121 * data to pass ike_filter
122 */
123 typedef struct {
124 private_stroke_config_t *this;
125 host_t *me;
126 host_t *other;
127 } ike_data_t;
128
129 /**
130 * destroy id enumerator data and unlock list
131 */
132 static void ike_data_destroy(ike_data_t *data)
133 {
134 data->this->mutex->unlock(data->this->mutex);
135 free(data);
136 }
137
138 /**
139 * filter function for ike configs
140 */
141 static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out)
142 {
143 *out = (*in)->get_ike_cfg(*in);
144 return TRUE;
145 }
146
147 /**
148 * Implementation of backend_t.create_ike_cfg_enumerator.
149 */
150 static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this,
151 host_t *me, host_t *other)
152 {
153 ike_data_t *data;
154
155 data = malloc_thing(ike_data_t);
156 data->this = this;
157 data->me = me;
158 data->other = other;
159
160 this->mutex->lock(this->mutex);
161 return enumerator_create_filter(this->list->create_enumerator(this->list),
162 (void*)ike_filter, data,
163 (void*)ike_data_destroy);
164 }
165
166 /**
167 * implements backend_t.get_peer_cfg_by_name.
168 */
169 static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *name)
170 {
171 enumerator_t *e1, *e2;
172 peer_cfg_t *current, *found = NULL;
173 child_cfg_t *child;
174
175 this->mutex->lock(this->mutex);
176 e1 = this->list->create_enumerator(this->list);
177 while (e1->enumerate(e1, &current))
178 {
179 /* compare peer_cfgs name first */
180 if (streq(current->get_name(current), name))
181 {
182 found = current;
183 found->get_ref(found);
184 break;
185 }
186 /* compare all child_cfg names otherwise */
187 e2 = current->create_child_cfg_enumerator(current);
188 while (e2->enumerate(e2, &child))
189 {
190 if (streq(child->get_name(child), name))
191 {
192 found = current;
193 found->get_ref(found);
194 break;
195 }
196 }
197 e2->destroy(e2);
198 if (found)
199 {
200 break;
201 }
202 }
203 e1->destroy(e1);
204 this->mutex->unlock(this->mutex);
205 return found;
206 }
207
208 /**
209 * check if a certificate has an ID
210 */
211 static identification_t *update_peerid(certificate_t *cert, identification_t *id)
212 {
213 if (id->get_type(id) == ID_ANY || !cert->has_subject(cert, id))
214 {
215 DBG1(DBG_CFG, " peerid %D not confirmed by certificate, "
216 "defaulting to subject DN", id);
217 id->destroy(id);
218 id = cert->get_subject(cert);
219 return id->clone(id);
220 }
221 return id;
222 }
223
224 /**
225 * parse a proposal string, either into ike_cfg or child_cfg
226 */
227 static void add_proposals(private_stroke_config_t *this, char *string,
228 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
229 {
230 if (string)
231 {
232 char *single;
233 char *strict;
234 proposal_t *proposal;
235 protocol_id_t proto = PROTO_ESP;
236
237 if (ike_cfg)
238 {
239 proto = PROTO_IKE;
240 }
241 strict = string + strlen(string) - 1;
242 if (*strict == '!')
243 {
244 *strict = '\0';
245 }
246 else
247 {
248 strict = NULL;
249 }
250 while ((single = strsep(&string, ",")))
251 {
252 proposal = proposal_create_from_string(proto, single);
253 if (proposal)
254 {
255 if (ike_cfg)
256 {
257 ike_cfg->add_proposal(ike_cfg, proposal);
258 }
259 else
260 {
261 child_cfg->add_proposal(child_cfg, proposal);
262 }
263 continue;
264 }
265 DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
266 }
267 if (strict)
268 {
269 return;
270 }
271 /* add default porposal to the end if not strict */
272 }
273 if (ike_cfg)
274 {
275 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
276 }
277 else
278 {
279 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
280 }
281 }
282
283 /**
284 * Build an IKE config from a stroke message
285 */
286 static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
287 {
288 stroke_end_t tmp_end;
289 ike_cfg_t *ike_cfg;
290 char *interface;
291 host_t *host;
292
293 host = host_create_from_dns(msg->add_conn.other.address, 0, 0);
294 if (host)
295 {
296 interface = charon->kernel_interface->get_interface(
297 charon->kernel_interface, host);
298 host->destroy(host);
299 if (interface)
300 {
301 DBG2(DBG_CFG, "left is other host, swapping ends");
302 tmp_end = msg->add_conn.me;
303 msg->add_conn.me = msg->add_conn.other;
304 msg->add_conn.other = tmp_end;
305 free(interface);
306 }
307 else
308 {
309 host = host_create_from_dns(msg->add_conn.me.address, 0, 0);
310 if (host)
311 {
312 interface = charon->kernel_interface->get_interface(
313 charon->kernel_interface, host);
314 host->destroy(host);
315 if (!interface)
316 {
317 DBG1(DBG_CFG, "left nor right host is our side, "
318 "assuming left=local");
319 }
320 else
321 {
322 free(interface);
323 }
324
325 }
326 }
327 }
328 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
329 msg->add_conn.force_encap,
330 msg->add_conn.me.address,
331 msg->add_conn.other.address);
332 add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
333 return ike_cfg;
334 }
335 /**
336 * build a peer_cfg from a stroke msg
337 */
338 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
339 stroke_msg_t *msg, ike_cfg_t *ike_cfg,
340 identification_t **my_issuer,
341 identification_t **other_issuer)
342 {
343 identification_t *me, *other, *peer_id = NULL;
344 peer_cfg_t *mediated_by = NULL;
345 host_t *vip = NULL;
346 certificate_t *cert;
347 unique_policy_t unique;
348 u_int32_t rekey = 0, reauth = 0, over, jitter;
349
350 me = identification_create_from_string(msg->add_conn.me.id ?
351 msg->add_conn.me.id : msg->add_conn.me.address);
352 if (!me)
353 {
354 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
355 return NULL;
356 }
357 other = identification_create_from_string(msg->add_conn.other.id ?
358 msg->add_conn.other.id : msg->add_conn.other.address);
359 if (!other)
360 {
361 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
362 me->destroy(me);
363 return NULL;
364 }
365
366
367 #ifdef ME
368 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
369 {
370 DBG1(DBG_CFG, "a mediation connection cannot be a"
371 " mediated connection at the same time, aborting");
372 me->destroy(me);
373 other->destroy(other);
374 return NULL;
375 }
376
377 if (msg->add_conn.ikeme.mediation)
378 {
379 /* force unique connections for mediation connections */
380 msg->add_conn.unique = 1;
381 }
382
383 if (msg->add_conn.ikeme.mediated_by)
384 {
385 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
386 msg->add_conn.ikeme.mediated_by);
387 if (!mediated_by)
388 {
389 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
390 msg->add_conn.ikeme.mediated_by);
391 me->destroy(me);
392 other->destroy(other);
393 return NULL;
394 }
395
396 if (!mediated_by->is_mediation(mediated_by))
397 {
398 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
399 "no mediation connection, aborting",
400 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
401 mediated_by->destroy(mediated_by);
402 me->destroy(me);
403 other->destroy(other);
404 return NULL;
405 }
406 }
407
408 if (msg->add_conn.ikeme.peerid)
409 {
410 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
411 if (!peer_id)
412 {
413 DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid);
414 mediated_by->destroy(mediated_by);
415 me->destroy(me);
416 other->destroy(other);
417 return NULL;
418 }
419 }
420 else
421 {
422 /* no peer ID supplied, assume right ID */
423 peer_id = other->clone(other);
424 }
425 #endif /* ME */
426
427 if (msg->add_conn.me.cert)
428 {
429 cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
430 if (cert)
431 {
432 identification_t *issuer = cert->get_issuer(cert);
433
434 *my_issuer = issuer->clone(issuer);
435 this->ca->check_for_hash_and_url(this->ca, cert);
436 me = update_peerid(cert, me);
437 cert->destroy(cert);
438 }
439 }
440 if (msg->add_conn.other.cert)
441 {
442 cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
443 if (cert)
444 {
445 identification_t *issuer = cert->get_issuer(cert);
446
447 *other_issuer = issuer->clone(issuer);
448 other = update_peerid(cert, other);
449 cert->destroy(cert);
450 }
451 }
452 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
453 over = msg->add_conn.rekey.margin;
454 if (msg->add_conn.rekey.reauth)
455 {
456 reauth = msg->add_conn.rekey.ike_lifetime - over;
457 }
458 else
459 {
460 rekey = msg->add_conn.rekey.ike_lifetime - over;
461 }
462 if (msg->add_conn.me.sourceip_size)
463 {
464 if (msg->add_conn.me.sourceip)
465 {
466 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
467 }
468 if (!vip)
469 { /* if it is set to something like %poolname, request an address */
470 if (msg->add_conn.me.subnets)
471 { /* use the same address as in subnet, if any */
472 if (strchr(msg->add_conn.me.subnets, '.'))
473 {
474 vip = host_create_any(AF_INET);
475 }
476 else
477 {
478 vip = host_create_any(AF_INET6);
479 }
480 }
481 else
482 {
483 if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
484 {
485 vip = host_create_any(AF_INET6);
486 }
487 else
488 {
489 vip = host_create_any(AF_INET);
490 }
491 }
492 }
493 }
494 switch (msg->add_conn.unique)
495 {
496 case 1: /* yes */
497 case 2: /* replace */
498 unique = UNIQUE_REPLACE;
499 break;
500 case 3: /* keep */
501 unique = UNIQUE_KEEP;
502 break;
503 default: /* no */
504 unique = UNIQUE_NO;
505 break;
506 }
507 if (msg->add_conn.dpd.action == 0)
508 { /* dpdaction=none disables DPD */
509 msg->add_conn.dpd.delay = 0;
510 }
511
512 /* other.sourceip is managed in stroke_attributes. If it is set, we define
513 * the pool name as the connection name, which the attribute provider
514 * uses to serve pool addresses. */
515 return peer_cfg_create(msg->add_conn.name,
516 msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
517 msg->add_conn.me.sendcert, unique,
518 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
519 msg->add_conn.mobike, msg->add_conn.dpd.delay,
520 vip, msg->add_conn.other.sourceip_size ?
521 msg->add_conn.name : msg->add_conn.other.sourceip,
522 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
523 }
524
525 /**
526 * fill in auth_info from stroke message
527 */
528 static void build_auth_info(private_stroke_config_t *this,
529 stroke_msg_t *msg, auth_info_t *auth,
530 identification_t *my_ca,
531 identification_t *other_ca)
532 {
533 identification_t *id;
534 bool my_ca_same = FALSE;
535 bool other_ca_same = FALSE;
536 cert_validation_t valid;
537
538 switch (msg->add_conn.crl_policy)
539 {
540 case CRL_STRICT_YES:
541 valid = VALIDATION_GOOD;
542 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
543 break;
544 case CRL_STRICT_IFURI:
545 valid = VALIDATION_SKIPPED;
546 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
547 break;
548 default:
549 break;
550 }
551
552 if (msg->add_conn.me.ca)
553 {
554 if (my_ca)
555 {
556 my_ca->destroy(my_ca);
557 my_ca = NULL;
558 }
559 if (streq(msg->add_conn.me.ca, "%same"))
560 {
561 my_ca_same = TRUE;
562 }
563 else
564 {
565 my_ca = identification_create_from_string(msg->add_conn.me.ca);
566 }
567 }
568
569 if (msg->add_conn.other.ca)
570 {
571 if (other_ca)
572 {
573 other_ca->destroy(other_ca);
574 other_ca = NULL;
575 }
576 if (streq(msg->add_conn.other.ca, "%same"))
577 {
578 other_ca_same = TRUE;
579 }
580 else
581 {
582 other_ca = identification_create_from_string(msg->add_conn.other.ca);
583 }
584 }
585
586 if (other_ca_same && my_ca)
587 {
588 other_ca = my_ca->clone(my_ca);
589 }
590 else if (my_ca_same && other_ca)
591 {
592 my_ca = other_ca->clone(other_ca);
593 }
594
595 if (other_ca)
596 {
597 DBG2(DBG_CFG, " other ca: %D", other_ca);
598 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
599 CERT_X509, KEY_ANY, other_ca, TRUE);
600 if (cert)
601 {
602 auth->add_item(auth, AUTHZ_CA_CERT, cert);
603 cert->destroy(cert);
604 }
605 else
606 {
607 auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
608 }
609 other_ca->destroy(other_ca);
610 }
611
612 if (my_ca)
613 {
614 DBG2(DBG_CFG, " my ca: %D", my_ca);
615 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
616 CERT_X509, KEY_ANY, my_ca, TRUE);
617 if (cert)
618 {
619 auth->add_item(auth, AUTHN_CA_CERT, cert);
620 cert->destroy(cert);
621 }
622 else
623 {
624 auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
625 }
626 my_ca->destroy(my_ca);
627 }
628 auth->add_item(auth, AUTHN_AUTH_CLASS, &msg->add_conn.auth_method);
629 if (msg->add_conn.eap_type)
630 {
631 auth->add_item(auth, AUTHN_EAP_TYPE, &msg->add_conn.eap_type);
632 if (msg->add_conn.eap_vendor)
633 {
634 auth->add_item(auth, AUTHN_EAP_VENDOR, &msg->add_conn.eap_vendor);
635 }
636 }
637
638 if (msg->add_conn.eap_identity)
639 {
640 if (streq(msg->add_conn.eap_identity, "%identity"))
641 {
642 id = identification_create_from_encoding(ID_ANY, chunk_empty);
643 }
644 else
645 {
646 id = identification_create_from_encoding(ID_EAP, chunk_create(
647 msg->add_conn.eap_identity,
648 strlen(msg->add_conn.eap_identity)));
649 }
650 auth->add_item(auth, AUTHN_EAP_IDENTITY, id);
651 id->destroy(id);
652 }
653
654 if (msg->add_conn.other.groups)
655 {
656 chunk_t line = { msg->add_conn.other.groups,
657 strlen(msg->add_conn.other.groups) };
658
659 while (eat_whitespace(&line))
660 {
661 chunk_t group;
662
663 /* extract the next comma-separated group attribute */
664 if (!extract_token(&group, ',', &line))
665 {
666 group = line;
667 line.len = 0;
668 }
669
670 /* remove any trailing spaces */
671 while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
672 {
673 group.len--;
674 }
675
676 /* add the group attribute to the list */
677 if (group.len > 0)
678 {
679 identification_t *ac_group;
680
681 ac_group = identification_create_from_encoding(
682 ID_IETF_ATTR_STRING, group);
683 auth->add_item(auth, AUTHZ_AC_GROUP, ac_group);
684 ac_group->destroy(ac_group);
685 }
686 }
687 }
688 }
689
690 /**
691 * build a traffic selector from a stroke_end
692 */
693 static void add_ts(private_stroke_config_t *this,
694 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
695 {
696 traffic_selector_t *ts;
697
698 if (end->tohost)
699 {
700 ts = traffic_selector_create_dynamic(end->protocol,
701 end->port ? end->port : 0, end->port ? end->port : 65535);
702 child_cfg->add_traffic_selector(child_cfg, local, ts);
703 }
704 else
705 {
706 host_t *net;
707
708 if (!end->subnets)
709 {
710 net = host_create_from_string(end->address, IKEV2_UDP_PORT);
711 if (net)
712 {
713 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
714 end->port);
715 child_cfg->add_traffic_selector(child_cfg, local, ts);
716 }
717 }
718 else
719 {
720 char *del, *start, *bits;
721
722 start = end->subnets;
723 do
724 {
725 int intbits = 0;
726
727 del = strchr(start, ',');
728 if (del)
729 {
730 *del = '\0';
731 }
732 bits = strchr(start, '/');
733 if (bits)
734 {
735 *bits = '\0';
736 intbits = atoi(bits + 1);
737 }
738
739 net = host_create_from_string(start, IKEV2_UDP_PORT);
740 if (net)
741 {
742 ts = traffic_selector_create_from_subnet(net, intbits,
743 end->protocol, end->port);
744 child_cfg->add_traffic_selector(child_cfg, local, ts);
745 }
746 else
747 {
748 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
749 }
750 start = del + 1;
751 }
752 while (del);
753 }
754 }
755 }
756
757 /**
758 * build a child config from the stroke message
759 */
760 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
761 stroke_msg_t *msg)
762 {
763 child_cfg_t *child_cfg;
764 action_t dpd;
765
766 switch (msg->add_conn.dpd.action)
767 { /* map startes magic values to our action type */
768 case 2: /* =hold */
769 dpd = ACTION_ROUTE;
770 break;
771 case 3: /* =restart */
772 dpd = ACTION_RESTART;
773 break;
774 default:
775 dpd = ACTION_NONE;
776 break;
777 }
778 child_cfg = child_cfg_create(
779 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
780 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
781 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
782 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
783 msg->add_conn.mode, dpd, dpd, msg->add_conn.ipcomp);
784 child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
785 msg->add_conn.install_policy);
786 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
787 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
788
789 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
790
791 return child_cfg;
792 }
793
794 /**
795 * Implementation of stroke_config_t.add.
796 */
797 static void add(private_stroke_config_t *this, stroke_msg_t *msg)
798 {
799 ike_cfg_t *ike_cfg, *existing_ike;
800 peer_cfg_t *peer_cfg, *existing;
801 child_cfg_t *child_cfg;
802 identification_t *my_issuer = NULL, *other_issuer = NULL;
803 enumerator_t *enumerator;
804 bool use_existing = FALSE;
805
806 ike_cfg = build_ike_cfg(this, msg);
807 if (!ike_cfg)
808 {
809 return;
810 }
811 peer_cfg = build_peer_cfg(this, msg, ike_cfg, &my_issuer, &other_issuer);
812 if (!peer_cfg)
813 {
814 ike_cfg->destroy(ike_cfg);
815 return;
816 }
817
818 build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg),
819 my_issuer, other_issuer);
820 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
821 while (enumerator->enumerate(enumerator, &existing))
822 {
823 existing_ike = existing->get_ike_cfg(existing);
824 if (existing->equals(existing, peer_cfg) &&
825 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
826 {
827 use_existing = TRUE;
828 peer_cfg->destroy(peer_cfg);
829 peer_cfg = existing;
830 peer_cfg->get_ref(peer_cfg);
831 DBG1(DBG_CFG, "added child to existing configuration '%s'",
832 peer_cfg->get_name(peer_cfg));
833 break;
834 }
835 }
836 enumerator->destroy(enumerator);
837
838 child_cfg = build_child_cfg(this, msg);
839 if (!child_cfg)
840 {
841 peer_cfg->destroy(peer_cfg);
842 return;
843 }
844 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
845
846 if (use_existing)
847 {
848 peer_cfg->destroy(peer_cfg);
849 }
850 else
851 {
852 /* add config to backend */
853 DBG1(DBG_CFG, "added configuration '%s': %s[%D]...%s[%D]", msg->add_conn.name,
854 ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
855 ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
856 this->mutex->lock(this->mutex);
857 this->list->insert_last(this->list, peer_cfg);
858 this->mutex->unlock(this->mutex);
859 }
860 }
861
862 /**
863 * Implementation of stroke_config_t.del.
864 */
865 static void del(private_stroke_config_t *this, stroke_msg_t *msg)
866 {
867 enumerator_t *enumerator, *children;
868 peer_cfg_t *peer;
869 child_cfg_t *child;
870
871 this->mutex->lock(this->mutex);
872 enumerator = this->list->create_enumerator(this->list);
873 while (enumerator->enumerate(enumerator, (void**)&peer))
874 {
875 /* remove peer config with such a name */
876 if (streq(peer->get_name(peer), msg->del_conn.name))
877 {
878 this->list->remove_at(this->list, enumerator);
879 peer->destroy(peer);
880 continue;
881 }
882 /* remove any child with such a name */
883 children = peer->create_child_cfg_enumerator(peer);
884 while (children->enumerate(children, &child))
885 {
886 if (streq(child->get_name(child), msg->del_conn.name))
887 {
888 peer->remove_child_cfg(peer, enumerator);
889 child->destroy(child);
890 }
891 }
892 children->destroy(children);
893 }
894 enumerator->destroy(enumerator);
895 this->mutex->unlock(this->mutex);
896
897 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
898 }
899
900 /**
901 * Implementation of stroke_config_t.destroy
902 */
903 static void destroy(private_stroke_config_t *this)
904 {
905 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
906 this->mutex->destroy(this->mutex);
907 free(this);
908 }
909
910 /*
911 * see header file
912 */
913 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
914 {
915 private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
916
917 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
918 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
919 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
920 this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add;
921 this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del;
922 this->public.destroy = (void(*)(stroke_config_t*))destroy;
923
924 this->list = linked_list_create();
925 this->mutex = mutex_create(MUTEX_RECURSIVE);
926 this->ca = ca;
927 this->cred = cred;
928
929 return &this->public;
930 }
931