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