fixed some compiler warnings
[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.mediated_by)
378 {
379 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
380 msg->add_conn.ikeme.mediated_by);
381 if (!mediated_by)
382 {
383 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
384 msg->add_conn.ikeme.mediated_by);
385 me->destroy(me);
386 other->destroy(other);
387 return NULL;
388 }
389
390 if (!mediated_by->is_mediation(mediated_by))
391 {
392 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is"
393 "no mediation connection, aborting",
394 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
395 mediated_by->destroy(mediated_by);
396 me->destroy(me);
397 other->destroy(other);
398 return NULL;
399 }
400 }
401
402 if (msg->add_conn.ikeme.peerid)
403 {
404 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
405 if (!peer_id)
406 {
407 DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid);
408 mediated_by->destroy(mediated_by);
409 me->destroy(me);
410 other->destroy(other);
411 return NULL;
412 }
413 }
414 else
415 {
416 /* no peer ID supplied, assume right ID */
417 peer_id = other->clone(other);
418 }
419 #endif /* ME */
420
421 if (msg->add_conn.me.cert)
422 {
423 cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
424 if (cert)
425 {
426 identification_t *issuer = cert->get_issuer(cert);
427
428 *my_issuer = issuer->clone(issuer);
429 this->ca->check_for_hash_and_url(this->ca, cert);
430 me = update_peerid(cert, me);
431 cert->destroy(cert);
432 }
433 }
434 if (msg->add_conn.other.cert)
435 {
436 cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
437 if (cert)
438 {
439 identification_t *issuer = cert->get_issuer(cert);
440
441 *other_issuer = issuer->clone(issuer);
442 other = update_peerid(cert, other);
443 cert->destroy(cert);
444 }
445 }
446 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
447 over = msg->add_conn.rekey.margin;
448 if (msg->add_conn.rekey.reauth)
449 {
450 reauth = msg->add_conn.rekey.ike_lifetime - over;
451 }
452 else
453 {
454 rekey = msg->add_conn.rekey.ike_lifetime - over;
455 }
456 if (msg->add_conn.me.sourceip_size)
457 {
458 if (msg->add_conn.me.sourceip)
459 {
460 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
461 }
462 if (!vip)
463 { /* if it is set to something like %poolname, request an address */
464 if (msg->add_conn.me.subnets)
465 { /* use the same address as in subnet, if any */
466 if (strchr(msg->add_conn.me.subnets, '.'))
467 {
468 vip = host_create_any(AF_INET);
469 }
470 else
471 {
472 vip = host_create_any(AF_INET6);
473 }
474 }
475 else
476 {
477 if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
478 {
479 vip = host_create_any(AF_INET6);
480 }
481 else
482 {
483 vip = host_create_any(AF_INET);
484 }
485 }
486 }
487 }
488 switch (msg->add_conn.unique)
489 {
490 case 1: /* yes */
491 case 2: /* replace */
492 unique = UNIQUE_REPLACE;
493 break;
494 case 3: /* keep */
495 unique = UNIQUE_KEEP;
496 break;
497 default: /* no */
498 unique = UNIQUE_NO;
499 break;
500 }
501 if (msg->add_conn.dpd.action == 0)
502 { /* dpdaction=none disables DPD */
503 msg->add_conn.dpd.delay = 0;
504 }
505
506 /* other.sourceip is managed in stroke_attributes. If it is set, we define
507 * the pool name as the connection name, which the attribute provider
508 * uses to serve pool addresses. */
509 return peer_cfg_create(msg->add_conn.name,
510 msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
511 msg->add_conn.me.sendcert, unique,
512 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
513 msg->add_conn.mobike, msg->add_conn.dpd.delay,
514 vip, msg->add_conn.other.sourceip_size ?
515 msg->add_conn.name : msg->add_conn.other.sourceip,
516 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
517 }
518
519 /**
520 * fill in auth_info from stroke message
521 */
522 static void build_auth_info(private_stroke_config_t *this,
523 stroke_msg_t *msg, auth_info_t *auth,
524 identification_t *my_ca,
525 identification_t *other_ca)
526 {
527 identification_t *id;
528 bool my_ca_same = FALSE;
529 bool other_ca_same = FALSE;
530 cert_validation_t valid;
531
532 switch (msg->add_conn.crl_policy)
533 {
534 case CRL_STRICT_YES:
535 valid = VALIDATION_GOOD;
536 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
537 break;
538 case CRL_STRICT_IFURI:
539 valid = VALIDATION_SKIPPED;
540 auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
541 break;
542 default:
543 break;
544 }
545
546 if (msg->add_conn.me.ca)
547 {
548 if (my_ca)
549 {
550 my_ca->destroy(my_ca);
551 my_ca = NULL;
552 }
553 if (streq(msg->add_conn.me.ca, "%same"))
554 {
555 my_ca_same = TRUE;
556 }
557 else
558 {
559 my_ca = identification_create_from_string(msg->add_conn.me.ca);
560 }
561 }
562
563 if (msg->add_conn.other.ca)
564 {
565 if (other_ca)
566 {
567 other_ca->destroy(other_ca);
568 other_ca = NULL;
569 }
570 if (streq(msg->add_conn.other.ca, "%same"))
571 {
572 other_ca_same = TRUE;
573 }
574 else
575 {
576 other_ca = identification_create_from_string(msg->add_conn.other.ca);
577 }
578 }
579
580 if (other_ca_same && my_ca)
581 {
582 other_ca = my_ca->clone(my_ca);
583 }
584 else if (my_ca_same && other_ca)
585 {
586 my_ca = other_ca->clone(other_ca);
587 }
588
589 if (other_ca)
590 {
591 DBG2(DBG_CFG, " other ca: %D", other_ca);
592 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
593 CERT_X509, KEY_ANY, other_ca, TRUE);
594 if (cert)
595 {
596 auth->add_item(auth, AUTHZ_CA_CERT, cert);
597 cert->destroy(cert);
598 }
599 else
600 {
601 auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
602 }
603 other_ca->destroy(other_ca);
604 }
605
606 if (my_ca)
607 {
608 DBG2(DBG_CFG, " my ca: %D", my_ca);
609 certificate_t *cert = charon->credentials->get_cert(charon->credentials,
610 CERT_X509, KEY_ANY, my_ca, TRUE);
611 if (cert)
612 {
613 auth->add_item(auth, AUTHN_CA_CERT, cert);
614 cert->destroy(cert);
615 }
616 else
617 {
618 auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
619 }
620 my_ca->destroy(my_ca);
621 }
622 auth->add_item(auth, AUTHN_AUTH_CLASS, &msg->add_conn.auth_method);
623 if (msg->add_conn.eap_type)
624 {
625 auth->add_item(auth, AUTHN_EAP_TYPE, &msg->add_conn.eap_type);
626 if (msg->add_conn.eap_vendor)
627 {
628 auth->add_item(auth, AUTHN_EAP_VENDOR, &msg->add_conn.eap_vendor);
629 }
630 }
631
632 if (msg->add_conn.eap_identity)
633 {
634 if (streq(msg->add_conn.eap_identity, "%identity"))
635 {
636 id = identification_create_from_encoding(ID_ANY, chunk_empty);
637 }
638 else
639 {
640 id = identification_create_from_encoding(ID_EAP, chunk_create(
641 msg->add_conn.eap_identity,
642 strlen(msg->add_conn.eap_identity)));
643 }
644 auth->add_item(auth, AUTHN_EAP_IDENTITY, id);
645 id->destroy(id);
646 }
647
648 if (msg->add_conn.other.groups)
649 {
650 chunk_t line = { msg->add_conn.other.groups,
651 strlen(msg->add_conn.other.groups) };
652
653 while (eat_whitespace(&line))
654 {
655 chunk_t group;
656
657 /* extract the next comma-separated group attribute */
658 if (!extract_token(&group, ',', &line))
659 {
660 group = line;
661 line.len = 0;
662 }
663
664 /* remove any trailing spaces */
665 while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
666 {
667 group.len--;
668 }
669
670 /* add the group attribute to the list */
671 if (group.len > 0)
672 {
673 identification_t *ac_group;
674
675 ac_group = identification_create_from_encoding(
676 ID_IETF_ATTR_STRING, group);
677 auth->add_item(auth, AUTHZ_AC_GROUP, ac_group);
678 ac_group->destroy(ac_group);
679 }
680 }
681 }
682 }
683
684 /**
685 * build a traffic selector from a stroke_end
686 */
687 static void add_ts(private_stroke_config_t *this,
688 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
689 {
690 traffic_selector_t *ts;
691
692 if (end->tohost)
693 {
694 ts = traffic_selector_create_dynamic(end->protocol,
695 end->port ? end->port : 0, end->port ? end->port : 65535);
696 child_cfg->add_traffic_selector(child_cfg, local, ts);
697 }
698 else
699 {
700 host_t *net;
701
702 if (!end->subnets)
703 {
704 net = host_create_from_string(end->address, IKEV2_UDP_PORT);
705 if (net)
706 {
707 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
708 end->port);
709 child_cfg->add_traffic_selector(child_cfg, local, ts);
710 }
711 }
712 else
713 {
714 char *del, *start, *bits;
715
716 start = end->subnets;
717 do
718 {
719 int intbits = 0;
720
721 del = strchr(start, ',');
722 if (del)
723 {
724 *del = '\0';
725 }
726 bits = strchr(start, '/');
727 if (bits)
728 {
729 *bits = '\0';
730 intbits = atoi(bits + 1);
731 }
732
733 net = host_create_from_string(start, IKEV2_UDP_PORT);
734 if (net)
735 {
736 ts = traffic_selector_create_from_subnet(net, intbits,
737 end->protocol, end->port);
738 child_cfg->add_traffic_selector(child_cfg, local, ts);
739 }
740 else
741 {
742 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
743 }
744 start = del + 1;
745 }
746 while (del);
747 }
748 }
749 }
750
751 /**
752 * build a child config from the stroke message
753 */
754 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
755 stroke_msg_t *msg)
756 {
757 child_cfg_t *child_cfg;
758 action_t dpd;
759
760 switch (msg->add_conn.dpd.action)
761 { /* map startes magic values to our action type */
762 case 2: /* =hold */
763 dpd = ACTION_ROUTE;
764 break;
765 case 3: /* =restart */
766 dpd = ACTION_RESTART;
767 break;
768 default:
769 dpd = ACTION_NONE;
770 break;
771 }
772 child_cfg = child_cfg_create(
773 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
774 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
775 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
776 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
777 msg->add_conn.mode, dpd, dpd, msg->add_conn.ipcomp);
778
779 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
780 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
781
782 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
783
784 return child_cfg;
785 }
786
787 /**
788 * Implementation of stroke_config_t.add.
789 */
790 static void add(private_stroke_config_t *this, stroke_msg_t *msg)
791 {
792 ike_cfg_t *ike_cfg, *existing_ike;
793 peer_cfg_t *peer_cfg, *existing;
794 child_cfg_t *child_cfg;
795 identification_t *my_issuer = NULL, *other_issuer = NULL;
796 enumerator_t *enumerator;
797 bool use_existing = FALSE;
798
799 ike_cfg = build_ike_cfg(this, msg);
800 if (!ike_cfg)
801 {
802 return;
803 }
804 peer_cfg = build_peer_cfg(this, msg, ike_cfg, &my_issuer, &other_issuer);
805 if (!peer_cfg)
806 {
807 ike_cfg->destroy(ike_cfg);
808 return;
809 }
810
811 build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg),
812 my_issuer, other_issuer);
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': %s[%D]...%s[%D]", msg->add_conn.name,
847 ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
848 ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
849 this->mutex->lock(this->mutex);
850 this->list->insert_last(this->list, peer_cfg);
851 this->mutex->unlock(this->mutex);
852 }
853 }
854
855 /**
856 * Implementation of stroke_config_t.del.
857 */
858 static void del(private_stroke_config_t *this, stroke_msg_t *msg)
859 {
860 enumerator_t *enumerator, *children;
861 peer_cfg_t *peer;
862 child_cfg_t *child;
863
864 this->mutex->lock(this->mutex);
865 enumerator = this->list->create_enumerator(this->list);
866 while (enumerator->enumerate(enumerator, (void**)&peer))
867 {
868 /* remove peer config with such a name */
869 if (streq(peer->get_name(peer), msg->del_conn.name))
870 {
871 this->list->remove_at(this->list, enumerator);
872 peer->destroy(peer);
873 continue;
874 }
875 /* remove any child with such a name */
876 children = peer->create_child_cfg_enumerator(peer);
877 while (children->enumerate(children, &child))
878 {
879 if (streq(child->get_name(child), msg->del_conn.name))
880 {
881 peer->remove_child_cfg(peer, enumerator);
882 child->destroy(child);
883 }
884 }
885 children->destroy(children);
886 }
887 enumerator->destroy(enumerator);
888 this->mutex->unlock(this->mutex);
889
890 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
891 }
892
893 /**
894 * Implementation of stroke_config_t.destroy
895 */
896 static void destroy(private_stroke_config_t *this)
897 {
898 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
899 this->mutex->destroy(this->mutex);
900 free(this);
901 }
902
903 /*
904 * see header file
905 */
906 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
907 {
908 private_stroke_config_t *this = malloc_thing(private_stroke_config_t);
909
910 this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
911 this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
912 this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name;
913 this->public.add = (void(*)(stroke_config_t*, stroke_msg_t *msg))add;
914 this->public.del = (void(*)(stroke_config_t*, stroke_msg_t *msg))del;
915 this->public.destroy = (void(*)(stroke_config_t*))destroy;
916
917 this->list = linked_list_create();
918 this->mutex = mutex_create(MUTEX_RECURSIVE);
919 this->ca = ca;
920 this->cred = cred;
921
922 return &this->public;
923 }
924