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