update_peerid() does not accept %any as a certificate's subjectAltName
[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 {
340 identification_t *me, *other, *peer_id = NULL;
341 peer_cfg_t *mediated_by = NULL;
342 host_t *vip = NULL;
343 certificate_t *cert;
344 unique_policy_t unique;
345 u_int32_t rekey = 0, reauth = 0, over, jitter;
346
347 me = identification_create_from_string(msg->add_conn.me.id ?
348 msg->add_conn.me.id : msg->add_conn.me.address);
349 if (!me)
350 {
351 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
352 return NULL;
353 }
354 other = identification_create_from_string(msg->add_conn.other.id ?
355 msg->add_conn.other.id : msg->add_conn.other.address);
356 if (!other)
357 {
358 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
359 me->destroy(me);
360 return NULL;
361 }
362
363
364 #ifdef ME
365 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
366 {
367 DBG1(DBG_CFG, "a mediation connection cannot be a"
368 " mediated connection at the same time, aborting");
369 me->destroy(me);
370 other->destroy(other);
371 return NULL;
372 }
373
374 if (msg->add_conn.ikeme.mediated_by)
375 {
376 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
377 msg->add_conn.ikeme.mediated_by);
378 if (!mediated_by)
379 {
380 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
381 msg->add_conn.ikeme.mediated_by);
382 me->destroy(me);
383 other->destroy(other);
384 return NULL;
385 }
386
387 if (!mediated_by->is_mediation(mediated_by))
388 {
389 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
390 "no mediation connection, aborting",
391 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
392 mediated_by->destroy(mediated_by);
393 me->destroy(me);
394 other->destroy(other);
395 return NULL;
396 }
397 }
398
399 if (msg->add_conn.ikeme.peerid)
400 {
401 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
402 if (!peer_id)
403 {
404 DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid);
405 mediated_by->destroy(mediated_by);
406 me->destroy(me);
407 other->destroy(other);
408 return NULL;
409 }
410 }
411 else
412 {
413 /* no peer ID supplied, assume right ID */
414 peer_id = other->clone(other);
415 }
416 #endif /* ME */
417
418 if (msg->add_conn.me.cert)
419 {
420 cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
421 if (cert)
422 {
423 this->ca->check_for_hash_and_url(this->ca, cert);
424 me = update_peerid(cert, me);
425 cert->destroy(cert);
426 }
427 }
428 if (msg->add_conn.other.cert)
429 {
430 cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
431 if (cert)
432 {
433 other = update_peerid(cert, other);
434 cert->destroy(cert);
435 }
436 }
437 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
438 over = msg->add_conn.rekey.margin;
439 if (msg->add_conn.rekey.reauth)
440 {
441 reauth = msg->add_conn.rekey.ike_lifetime - over;
442 }
443 else
444 {
445 rekey = msg->add_conn.rekey.ike_lifetime - over;
446 }
447 if (msg->add_conn.me.sourceip_size)
448 {
449 if (msg->add_conn.me.sourceip)
450 {
451 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
452 }
453 if (!vip)
454 { /* if it is set to something like %poolname, request an address */
455 if (msg->add_conn.me.subnets)
456 { /* use the same address as in subnet, if any */
457 if (strchr(msg->add_conn.me.subnets, '.'))
458 {
459 vip = host_create_any(AF_INET);
460 }
461 else
462 {
463 vip = host_create_any(AF_INET6);
464 }
465 }
466 else
467 {
468 if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
469 {
470 vip = host_create_any(AF_INET6);
471 }
472 else
473 {
474 vip = host_create_any(AF_INET);
475 }
476 }
477 }
478 }
479 switch (msg->add_conn.unique)
480 {
481 case 1: /* yes */
482 case 2: /* replace */
483 unique = UNIQUE_REPLACE;
484 break;
485 case 3: /* keep */
486 unique = UNIQUE_KEEP;
487 break;
488 default: /* no */
489 unique = UNIQUE_NO;
490 break;
491 }
492 if (msg->add_conn.dpd.action == 0)
493 { /* dpdaction=none disables DPD */
494 msg->add_conn.dpd.delay = 0;
495 }
496
497 /* other.sourceip is managed in stroke_attributes. If it is set, we define
498 * the pool name as the connection name, which the attribute provider
499 * uses to serve pool addresses. */
500 return peer_cfg_create(msg->add_conn.name,
501 msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
502 msg->add_conn.me.sendcert, unique, msg->add_conn.auth_method,
503 msg->add_conn.eap_type, msg->add_conn.eap_vendor,
504 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
505 msg->add_conn.mobike, msg->add_conn.dpd.delay,
506 vip, msg->add_conn.other.sourceip_size ?
507 msg->add_conn.name : msg->add_conn.other.sourceip,
508 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
509 }
510
511 /**
512 * fill in auth_info from stroke message
513 */
514 static void build_auth_info(private_stroke_config_t *this,
515 stroke_msg_t *msg, auth_info_t *auth)
516 {
517 identification_t *my_ca = NULL, *other_ca = NULL;
518 bool my_ca_same = FALSE;
519 bool other_ca_same = FALSE;
520 cert_validation_t valid;
521
522 if (msg->add_conn.other.groups)
523 {
524 /* TODO: AC groups */
525 }
526
527 switch (msg->add_conn.crl_policy)
528 {
529 case CRL_STRICT_YES:
530 valid = VALIDATION_GOOD;
531 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
532 break;
533 case CRL_STRICT_IFURI:
534 valid = VALIDATION_SKIPPED;
535 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
536 break;
537 default:
538 break;
539 }
540
541 if (msg->add_conn.me.ca)
542 {
543 if (streq(msg->add_conn.me.ca, "%same"))
544 {
545 my_ca_same = TRUE;
546 }
547 else
548 {
549 my_ca = identification_create_from_string(msg->add_conn.me.ca);
550 }
551 }
552 if (msg->add_conn.other.ca)
553 {
554 if (streq(msg->add_conn.other.ca, "%same"))
555 {
556 other_ca_same = TRUE;
557 }
558 else
559 {
560 other_ca = identification_create_from_string(msg->add_conn.other.ca);
561 }
562 }
563 if (other_ca_same && my_ca)
564 {
565 other_ca = my_ca->clone(my_ca);
566 }
567 else if (my_ca_same && other_ca)
568 {
569 my_ca = other_ca->clone(other_ca);
570 }
571
572 if (other_ca)
573 {
574 DBG2(DBG_CFG, " other ca: %D", other_ca);
575 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
576 CERT_X509, KEY_ANY, other_ca, TRUE);
577 if (cert)
578 {
579 auth->add_item(auth, AUTHZ_CA_CERT, cert);
580 cert->destroy(cert);
581 }
582 else
583 {
584 auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
585 }
586 other_ca->destroy(other_ca);
587 }
588 if (my_ca)
589 {
590 DBG2(DBG_CFG, " my ca: %D", my_ca);
591 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
592 CERT_X509, KEY_ANY, my_ca, TRUE);
593 if (cert)
594 {
595 auth->add_item(auth, AUTHN_CA_CERT, cert);
596 cert->destroy(cert);
597 }
598 else
599 {
600 auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
601 }
602 my_ca->destroy(my_ca);
603 }
604 }
605
606 /**
607 * build a traffic selector from a stroke_end
608 */
609 static void add_ts(private_stroke_config_t *this,
610 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
611 {
612 traffic_selector_t *ts;
613
614 if (end->tohost)
615 {
616 ts = traffic_selector_create_dynamic(end->protocol,
617 end->port ? end->port : 0, end->port ? end->port : 65535);
618 child_cfg->add_traffic_selector(child_cfg, local, ts);
619 }
620 else
621 {
622 host_t *net;
623
624 if (!end->subnets)
625 {
626 net = host_create_from_string(end->address, IKEV2_UDP_PORT);
627 if (net)
628 {
629 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
630 end->port);
631 child_cfg->add_traffic_selector(child_cfg, local, ts);
632 }
633 }
634 else
635 {
636 char *del, *start, *bits;
637
638 start = end->subnets;
639 do
640 {
641 int intbits = 0;
642
643 del = strchr(start, ',');
644 if (del)
645 {
646 *del = '\0';
647 }
648 bits = strchr(start, '/');
649 if (bits)
650 {
651 *bits = '\0';
652 intbits = atoi(bits + 1);
653 }
654
655 net = host_create_from_string(start, IKEV2_UDP_PORT);
656 if (net)
657 {
658 ts = traffic_selector_create_from_subnet(net, intbits,
659 end->protocol, end->port);
660 child_cfg->add_traffic_selector(child_cfg, local, ts);
661 }
662 else
663 {
664 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
665 }
666 start = del + 1;
667 }
668 while (del);
669 }
670 }
671 }
672
673 /**
674 * build a child config from the stroke message
675 */
676 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
677 stroke_msg_t *msg)
678 {
679 child_cfg_t *child_cfg;
680 action_t dpd;
681
682 switch (msg->add_conn.dpd.action)
683 { /* map startes magic values to our action type */
684 case 2: /* =hold */
685 dpd = ACTION_ROUTE;
686 break;
687 case 3: /* =restart */
688 dpd = ACTION_RESTART;
689 break;
690 default:
691 dpd = ACTION_NONE;
692 break;
693 }
694 child_cfg = child_cfg_create(
695 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
696 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
697 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
698 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
699 msg->add_conn.mode, dpd, ACTION_NONE, msg->add_conn.ipcomp);
700
701 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
702 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
703
704 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
705
706 return child_cfg;
707 }
708
709 /**
710 * Implementation of stroke_config_t.add.
711 */
712 static void add(private_stroke_config_t *this, stroke_msg_t *msg)
713 {
714 ike_cfg_t *ike_cfg, *existing_ike;
715 peer_cfg_t *peer_cfg, *existing;
716 child_cfg_t *child_cfg;
717 enumerator_t *enumerator;
718 bool use_existing = FALSE;
719
720 ike_cfg = build_ike_cfg(this, msg);
721 if (!ike_cfg)
722 {
723 return;
724 }
725 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
726 if (!peer_cfg)
727 {
728 ike_cfg->destroy(ike_cfg);
729 return;
730 }
731
732 build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg));
733 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
734 while (enumerator->enumerate(enumerator, &existing))
735 {
736 existing_ike = existing->get_ike_cfg(existing);
737 if (existing->equals(existing, peer_cfg) &&
738 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
739 {
740 use_existing = TRUE;
741 peer_cfg->destroy(peer_cfg);
742 peer_cfg = existing;
743 peer_cfg->get_ref(peer_cfg);
744 DBG1(DBG_CFG, "added child to existing configuration '%s'",
745 peer_cfg->get_name(peer_cfg));
746 break;
747 }
748 }
749 enumerator->destroy(enumerator);
750
751 child_cfg = build_child_cfg(this, msg);
752 if (!child_cfg)
753 {
754 peer_cfg->destroy(peer_cfg);
755 return;
756 }
757 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
758
759 if (use_existing)
760 {
761 peer_cfg->destroy(peer_cfg);
762 }
763 else
764 {
765 /* add config to backend */
766 DBG1(DBG_CFG, "added configuration '%s': %s[%D]...%s[%D]", msg->add_conn.name,
767 ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
768 ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
769 this->mutex->lock(this->mutex);
770 this->list->insert_last(this->list, peer_cfg);
771 this->mutex->unlock(this->mutex);
772 }
773 }
774
775 /**
776 * Implementation of stroke_config_t.del.
777 */
778 static void del(private_stroke_config_t *this, stroke_msg_t *msg)
779 {
780 enumerator_t *enumerator, *children;
781 peer_cfg_t *peer;
782 child_cfg_t *child;
783
784 this->mutex->lock(this->mutex);
785 enumerator = this->list->create_enumerator(this->list);
786 while (enumerator->enumerate(enumerator, (void**)&peer))
787 {
788 /* remove peer config with such a name */
789 if (streq(peer->get_name(peer), msg->del_conn.name))
790 {
791 this->list->remove_at(this->list, enumerator);
792 peer->destroy(peer);
793 continue;
794 }
795 /* remove any child with such a name */
796 children = peer->create_child_cfg_enumerator(peer);
797 while (children->enumerate(children, &child))
798 {
799 if (streq(child->get_name(child), msg->del_conn.name))
800 {
801 peer->remove_child_cfg(peer, enumerator);
802 child->destroy(child);
803 }
804 }
805 children->destroy(children);
806 }
807 enumerator->destroy(enumerator);
808 this->mutex->unlock(this->mutex);
809
810 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
811 }
812
813 /**
814 * Implementation of stroke_config_t.destroy
815 */
816 static void destroy(private_stroke_config_t *this)
817 {
818 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
819 this->mutex->destroy(this->mutex);
820 free(this);
821 }
822
823 /*
824 * see header file
825 */
826 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
827 {
828 private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
829
830 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
831 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
832 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
833 this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add;
834 this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del;
835 this->public.destroy = (void(*)(stroke_config_t*))destroy;
836
837 this->list = linked_list_create();
838 this->mutex = mutex_create(MUTEX_RECURSIVE);
839 this->ca = ca;
840 this->cred = cred;
841
842 return &this->public;
843 }
844