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