931dc9c39ddb155a9e91ca1b67649654bcdf7d2c
[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 ike_cfg_t *ike_cfg;
143 host_t *me, *other;
144
145 ike_cfg = (*in)->get_ike_cfg(*in);
146
147 me = ike_cfg->get_my_host(ike_cfg);
148 other = ike_cfg->get_other_host(ike_cfg);
149 if ((!data->me || me->is_anyaddr(me) || me->ip_equals(me, data->me)) &&
150 (!data->other || other->is_anyaddr(other) || other->ip_equals(other, data->other)))
151 {
152 *out = ike_cfg;
153 return TRUE;
154 }
155 return FALSE;
156 }
157
158 /**
159 * Implementation of backend_t.create_ike_cfg_enumerator.
160 */
161 static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this,
162 host_t *me, host_t *other)
163 {
164 ike_data_t *data;
165
166 data = malloc_thing(ike_data_t);
167 data->this = this;
168 data->me = me;
169 data->other = other;
170
171 this->mutex->lock(this->mutex);
172 return enumerator_create_filter(this->list->create_enumerator(this->list),
173 (void*)ike_filter, data,
174 (void*)ike_data_destroy);
175 }
176
177 /**
178 * implements backend_t.get_peer_cfg_by_name.
179 */
180 static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *name)
181 {
182 enumerator_t *e1, *e2;
183 peer_cfg_t *current, *found = NULL;
184 child_cfg_t *child;
185
186 this->mutex->lock(this->mutex);
187 e1 = this->list->create_enumerator(this->list);
188 while (e1->enumerate(e1, &current))
189 {
190 /* compare peer_cfgs name first */
191 if (streq(current->get_name(current), name))
192 {
193 found = current;
194 found->get_ref(found);
195 break;
196 }
197 /* compare all child_cfg names otherwise */
198 e2 = current->create_child_cfg_enumerator(current);
199 while (e2->enumerate(e2, &child))
200 {
201 if (streq(child->get_name(child), name))
202 {
203 found = current;
204 found->get_ref(found);
205 break;
206 }
207 }
208 e2->destroy(e2);
209 if (found)
210 {
211 break;
212 }
213 }
214 e1->destroy(e1);
215 this->mutex->unlock(this->mutex);
216 return found;
217 }
218
219 /**
220 * check if a certificate has an ID
221 */
222 static identification_t *update_peerid(certificate_t *cert, identification_t *id)
223 {
224 if (!cert->has_subject(cert, id))
225 {
226 DBG1(DBG_CFG, " peerid %D not confirmed by certificate, "
227 "defaulting to subject DN", id);
228 id->destroy(id);
229 id = cert->get_subject(cert);
230 return id->clone(id);
231 }
232 return id;
233 }
234
235 /**
236 * parse a proposal string, either into ike_cfg or child_cfg
237 */
238 static void add_proposals(private_stroke_config_t *this, char *string,
239 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
240 {
241 if (string)
242 {
243 char *single;
244 char *strict;
245 proposal_t *proposal;
246 protocol_id_t proto = PROTO_ESP;
247
248 if (ike_cfg)
249 {
250 proto = PROTO_IKE;
251 }
252 strict = string + strlen(string) - 1;
253 if (*strict == '!')
254 {
255 *strict = '\0';
256 }
257 else
258 {
259 strict = NULL;
260 }
261 while ((single = strsep(&string, ",")))
262 {
263 proposal = proposal_create_from_string(proto, single);
264 if (proposal)
265 {
266 if (ike_cfg)
267 {
268 ike_cfg->add_proposal(ike_cfg, proposal);
269 }
270 else
271 {
272 child_cfg->add_proposal(child_cfg, proposal);
273 }
274 continue;
275 }
276 DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
277 }
278 if (strict)
279 {
280 return;
281 }
282 /* add default porposal to the end if not strict */
283 }
284 if (ike_cfg)
285 {
286 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
287 }
288 else
289 {
290 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
291 }
292 }
293
294 /**
295 * Build an IKE config from a stroke message
296 */
297 static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
298 {
299 host_t *me = NULL, *other = NULL, *tmp;
300 stroke_end_t tmp_end;
301 ike_cfg_t *ike_cfg;
302 char *interface;
303
304 if (msg->add_conn.me.address)
305 {
306 me = host_create_from_string(msg->add_conn.me.address, IKEV2_UDP_PORT);
307 }
308 if (!me)
309 {
310 DBG1(DBG_CFG, "invalid left host: %s", msg->add_conn.me.address);
311 return NULL;
312 }
313 if (msg->add_conn.other.address)
314 {
315 other = host_create_from_string(msg->add_conn.other.address, IKEV2_UDP_PORT);
316 }
317 if (!other)
318 {
319 DBG1(DBG_CFG, "invalid right host: %s", msg->add_conn.other.address);
320 me->destroy(me);
321 return NULL;
322 }
323 interface = charon->kernel_interface->get_interface(
324 charon->kernel_interface, other);
325 if (interface)
326 {
327 DBG2(DBG_CFG, "left is other host, swapping ends");
328 tmp = me;
329 me = other;
330 other = tmp;
331 tmp_end = msg->add_conn.me;
332 msg->add_conn.me = msg->add_conn.other;
333 msg->add_conn.other = tmp_end;
334 free(interface);
335 }
336 else
337 {
338 interface = charon->kernel_interface->get_interface(
339 charon->kernel_interface, me);
340 if (!interface)
341 {
342 DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
343 }
344 else
345 {
346 free(interface);
347 }
348 }
349 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
350 msg->add_conn.force_encap, me, other);
351 add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
352 return ike_cfg;
353 }
354 /**
355 * build a peer_cfg from a stroke msg
356 */
357 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
358 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
359 {
360 identification_t *me, *other, *peer_id = NULL;
361 peer_cfg_t *mediated_by = NULL;
362 host_t *vip = NULL;
363 certificate_t *cert;
364 unique_policy_t unique;
365 u_int32_t rekey = 0, reauth = 0, over, jitter;
366
367 me = identification_create_from_string(msg->add_conn.me.id ?
368 msg->add_conn.me.id : msg->add_conn.me.address);
369 if (!me)
370 {
371 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
372 return NULL;
373 }
374 other = identification_create_from_string(msg->add_conn.other.id ?
375 msg->add_conn.other.id : msg->add_conn.other.address);
376 if (!other)
377 {
378 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
379 me->destroy(me);
380 return NULL;
381 }
382
383
384 #ifdef ME
385 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
386 {
387 DBG1(DBG_CFG, "a mediation connection cannot be a"
388 " mediated connection at the same time, aborting");
389 me->destroy(me);
390 other->destroy(other);
391 return NULL;
392 }
393
394 if (msg->add_conn.ikeme.mediated_by)
395 {
396 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
397 msg->add_conn.ikeme.mediated_by);
398 if (!mediated_by)
399 {
400 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
401 msg->add_conn.ikeme.mediated_by);
402 me->destroy(me);
403 other->destroy(other);
404 return NULL;
405 }
406
407 if (!mediated_by->is_mediation(mediated_by))
408 {
409 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
410 "no mediation connection, aborting",
411 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
412 mediated_by->destroy(mediated_by);
413 me->destroy(me);
414 other->destroy(other);
415 return NULL;
416 }
417 }
418
419 if (msg->add_conn.ikeme.peerid)
420 {
421 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
422 if (!peer_id)
423 {
424 DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid);
425 mediated_by->destroy(mediated_by);
426 me->destroy(me);
427 other->destroy(other);
428 return NULL;
429 }
430 }
431 else
432 {
433 /* no peer ID supplied, assume right ID */
434 peer_id = other->clone(other);
435 }
436 #endif /* ME */
437
438 if (msg->add_conn.me.cert)
439 {
440 cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
441 if (cert)
442 {
443 this->ca->check_for_hash_and_url(this->ca, cert);
444 me = update_peerid(cert, me);
445 cert->destroy(cert);
446 }
447 }
448 if (msg->add_conn.other.cert)
449 {
450 cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
451 if (cert)
452 {
453 other = update_peerid(cert, other);
454 cert->destroy(cert);
455 }
456 }
457 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
458 over = msg->add_conn.rekey.margin;
459 if (msg->add_conn.rekey.reauth)
460 {
461 reauth = msg->add_conn.rekey.ike_lifetime - over;
462 }
463 else
464 {
465 rekey = msg->add_conn.rekey.ike_lifetime - over;
466 }
467 if (msg->add_conn.me.sourceip_size)
468 {
469 if (msg->add_conn.me.sourceip)
470 {
471 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
472 }
473 if (!vip)
474 { /* if it is set to something like %poolname, request an address */
475 if (msg->add_conn.me.subnet)
476 { /* use the same addreass as in subnet, if any */
477 if (strchr(msg->add_conn.me.subnet, '.'))
478 {
479 vip = host_create_any(AF_INET);
480 }
481 else
482 {
483 vip = host_create_any(AF_INET6);
484 }
485 }
486 else
487 {
488 host_t* my_host = ike_cfg->get_my_host(ike_cfg);
489 vip = host_create_any(my_host->get_family(my_host));
490 }
491 }
492 }
493 switch (msg->add_conn.unique)
494 {
495 case 1: /* yes */
496 case 2: /* replace */
497 unique = UNIQUE_REPLACE;
498 break;
499 case 3: /* keep */
500 unique = UNIQUE_KEEP;
501 break;
502 default: /* no */
503 unique = UNIQUE_NO;
504 break;
505 }
506 if (msg->add_conn.dpd.action == 0)
507 { /* dpdaction=none disables DPD */
508 msg->add_conn.dpd.delay = 0;
509 }
510
511 /* other.sourceip is managed in stroke_attributes. If it is set, we define
512 * the pool name as the connection name, which the attribute provider
513 * uses to serve pool addresses. */
514 return peer_cfg_create(msg->add_conn.name,
515 msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
516 msg->add_conn.me.sendcert, unique, msg->add_conn.auth_method,
517 msg->add_conn.eap_type, msg->add_conn.eap_vendor,
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 {
531 identification_t *my_ca = NULL, *other_ca = NULL;
532 bool my_ca_same = FALSE;
533 bool other_ca_same = FALSE;
534 cert_validation_t valid;
535
536 if (msg->add_conn.other.groups)
537 {
538 /* TODO: AC groups */
539 }
540
541 switch (msg->add_conn.crl_policy)
542 {
543 case CRL_STRICT_YES:
544 valid = VALIDATION_GOOD;
545 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
546 break;
547 case CRL_STRICT_IFURI:
548 valid = VALIDATION_SKIPPED;
549 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
550 break;
551 default:
552 break;
553 }
554
555 if (msg->add_conn.me.ca)
556 {
557 if (streq(msg->add_conn.me.ca, "%same"))
558 {
559 my_ca_same = TRUE;
560 }
561 else
562 {
563 my_ca = identification_create_from_string(msg->add_conn.me.ca);
564 }
565 }
566 if (msg->add_conn.other.ca)
567 {
568 if (streq(msg->add_conn.other.ca, "%same"))
569 {
570 other_ca_same = TRUE;
571 }
572 else
573 {
574 other_ca = identification_create_from_string(msg->add_conn.other.ca);
575 }
576 }
577 if (other_ca_same && my_ca)
578 {
579 other_ca = my_ca->clone(my_ca);
580 }
581 else if (my_ca_same && other_ca)
582 {
583 my_ca = other_ca->clone(other_ca);
584 }
585
586 if (other_ca)
587 {
588 DBG2(DBG_CFG, " other ca: %D", other_ca);
589 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
590 CERT_X509, KEY_ANY, other_ca, TRUE);
591 if (cert)
592 {
593 auth->add_item(auth, AUTHZ_CA_CERT, cert);
594 cert->destroy(cert);
595 }
596 else
597 {
598 auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
599 }
600 other_ca->destroy(other_ca);
601 }
602 if (my_ca)
603 {
604 DBG2(DBG_CFG, " my ca: %D", my_ca);
605 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
606 CERT_X509, KEY_ANY, my_ca, TRUE);
607 if (cert)
608 {
609 auth->add_item(auth, AUTHN_CA_CERT, cert);
610 cert->destroy(cert);
611 }
612 else
613 {
614 auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
615 }
616 my_ca->destroy(my_ca);
617 }
618 }
619
620 /**
621 * build a traffic selector from a stroke_end
622 */
623 static traffic_selector_t *build_ts(private_stroke_config_t *this,
624 stroke_end_t *end)
625 {
626 if (end->tohost)
627 {
628 return traffic_selector_create_dynamic(end->protocol,
629 end->port ? end->port : 0, end->port ? end->port : 65535);
630 }
631 else
632 {
633 host_t *net;
634
635 net = host_create_from_string(end->subnet ? end->subnet : end->address,
636 IKEV2_UDP_PORT);
637 if (!net)
638 {
639 DBG1(DBG_CFG, "invalid subnet: %s", end->subnet);
640 return NULL;
641 }
642 return traffic_selector_create_from_subnet(net,
643 end->subnet ? end->subnet_mask : 0, end->protocol, end->port);
644 }
645 }
646
647 /**
648 * build a child config from the stroke message
649 */
650 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
651 stroke_msg_t *msg)
652 {
653 child_cfg_t *child_cfg;
654 traffic_selector_t *ts;
655 action_t dpd;
656
657 switch (msg->add_conn.dpd.action)
658 { /* map startes magic values to our action type */
659 case 2: /* =hold */
660 dpd = ACTION_ROUTE;
661 break;
662 case 3: /* =restart */
663 dpd = ACTION_RESTART;
664 break;
665 default:
666 dpd = ACTION_NONE;
667 break;
668 }
669 child_cfg = child_cfg_create(
670 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
671 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
672 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
673 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
674 msg->add_conn.mode, dpd, ACTION_NONE);
675
676 ts = build_ts(this, &msg->add_conn.me);
677 if (!ts)
678 {
679 child_cfg->destroy(child_cfg);
680 return NULL;
681 }
682 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
683
684 ts = build_ts(this, &msg->add_conn.other);
685 if (!ts)
686 {
687 child_cfg->destroy(child_cfg);
688 return NULL;
689 }
690 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
691
692 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
693
694 return child_cfg;
695 }
696
697 /**
698 * Implementation of stroke_config_t.add.
699 */
700 static void add(private_stroke_config_t *this, stroke_msg_t *msg)
701 {
702 ike_cfg_t *ike_cfg, *existing_ike;
703 peer_cfg_t *peer_cfg, *existing;
704 child_cfg_t *child_cfg;
705 enumerator_t *enumerator;
706 bool use_existing = FALSE;
707
708 ike_cfg = build_ike_cfg(this, msg);
709 if (!ike_cfg)
710 {
711 return;
712 }
713 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
714 if (!peer_cfg)
715 {
716 ike_cfg->destroy(ike_cfg);
717 return;
718 }
719
720 build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg));
721 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
722 while (enumerator->enumerate(enumerator, &existing))
723 {
724 existing_ike = existing->get_ike_cfg(existing);
725 if (existing->equals(existing, peer_cfg) &&
726 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
727 {
728 use_existing = TRUE;
729 peer_cfg->destroy(peer_cfg);
730 peer_cfg = existing;
731 peer_cfg->get_ref(peer_cfg);
732 DBG1(DBG_CFG, "added child to existing configuration '%s'",
733 peer_cfg->get_name(peer_cfg));
734 break;
735 }
736 }
737 enumerator->destroy(enumerator);
738
739 child_cfg = build_child_cfg(this, msg);
740 if (!child_cfg)
741 {
742 peer_cfg->destroy(peer_cfg);
743 return;
744 }
745 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
746
747 if (use_existing)
748 {
749 peer_cfg->destroy(peer_cfg);
750 }
751 else
752 {
753 /* add config to backend */
754 DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]", msg->add_conn.name,
755 ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
756 ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
757 this->mutex->lock(this->mutex);
758 this->list->insert_last(this->list, peer_cfg);
759 this->mutex->unlock(this->mutex);
760 }
761 }
762
763 /**
764 * Implementation of stroke_config_t.del.
765 */
766 static void del(private_stroke_config_t *this, stroke_msg_t *msg)
767 {
768 enumerator_t *enumerator, *children;
769 peer_cfg_t *peer;
770 child_cfg_t *child;
771
772 this->mutex->lock(this->mutex);
773 enumerator = this->list->create_enumerator(this->list);
774 while (enumerator->enumerate(enumerator, (void**)&peer))
775 {
776 /* remove peer config with such a name */
777 if (streq(peer->get_name(peer), msg->del_conn.name))
778 {
779 this->list->remove_at(this->list, enumerator);
780 peer->destroy(peer);
781 continue;
782 }
783 /* remove any child with such a name */
784 children = peer->create_child_cfg_enumerator(peer);
785 while (children->enumerate(children, &child))
786 {
787 if (streq(child->get_name(child), msg->del_conn.name))
788 {
789 peer->remove_child_cfg(peer, enumerator);
790 child->destroy(child);
791 }
792 }
793 children->destroy(children);
794 }
795 enumerator->destroy(enumerator);
796 this->mutex->unlock(this->mutex);
797
798 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
799 }
800
801 /**
802 * Implementation of stroke_config_t.destroy
803 */
804 static void destroy(private_stroke_config_t *this)
805 {
806 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
807 this->mutex->destroy(this->mutex);
808 free(this);
809 }
810
811 /*
812 * see header file
813 */
814 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
815 {
816 private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
817
818 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
819 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
820 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
821 this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add;
822 this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del;
823 this->public.destroy = (void(*)(stroke_config_t*))destroy;
824
825 this->list = linked_list_create();
826 this->mutex = mutex_create(MUTEX_RECURSIVE);
827 this->ca = ca;
828 this->cred = cred;
829
830 return &this->public;
831 }
832