6b8dc234b8bb9ec9d4dafef64674dce26f203b18
[strongswan.git] / src / libcharon / plugins / stroke / stroke_config.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "stroke_config.h"
18
19 #include <hydra.h>
20 #include <daemon.h>
21 #include <threading/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 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
58 private_stroke_config_t *this, identification_t *me, identification_t *other)
59 {
60 this->mutex->lock(this->mutex);
61 return enumerator_create_cleaner(this->list->create_enumerator(this->list),
62 (void*)this->mutex->unlock, this->mutex);
63 }
64
65 /**
66 * filter function for ike configs
67 */
68 static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
69 {
70 *out = (*in)->get_ike_cfg(*in);
71 return TRUE;
72 }
73
74 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
75 private_stroke_config_t *this, host_t *me, host_t *other)
76 {
77 this->mutex->lock(this->mutex);
78 return enumerator_create_filter(this->list->create_enumerator(this->list),
79 (void*)ike_filter, this->mutex,
80 (void*)this->mutex->unlock);
81 }
82
83 METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
84 private_stroke_config_t *this, char *name)
85 {
86 enumerator_t *e1, *e2;
87 peer_cfg_t *current, *found = NULL;
88 child_cfg_t *child;
89
90 this->mutex->lock(this->mutex);
91 e1 = this->list->create_enumerator(this->list);
92 while (e1->enumerate(e1, &current))
93 {
94 /* compare peer_cfgs name first */
95 if (streq(current->get_name(current), name))
96 {
97 found = current;
98 found->get_ref(found);
99 break;
100 }
101 /* compare all child_cfg names otherwise */
102 e2 = current->create_child_cfg_enumerator(current);
103 while (e2->enumerate(e2, &child))
104 {
105 if (streq(child->get_name(child), name))
106 {
107 found = current;
108 found->get_ref(found);
109 break;
110 }
111 }
112 e2->destroy(e2);
113 if (found)
114 {
115 break;
116 }
117 }
118 e1->destroy(e1);
119 this->mutex->unlock(this->mutex);
120 return found;
121 }
122
123 /**
124 * parse a proposal string, either into ike_cfg or child_cfg
125 */
126 static void add_proposals(private_stroke_config_t *this, char *string,
127 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
128 {
129 if (string)
130 {
131 char *single;
132 char *strict;
133 proposal_t *proposal;
134 protocol_id_t proto = PROTO_ESP;
135
136 if (ike_cfg)
137 {
138 proto = PROTO_IKE;
139 }
140 strict = string + strlen(string) - 1;
141 if (*strict == '!')
142 {
143 *strict = '\0';
144 }
145 else
146 {
147 strict = NULL;
148 }
149 while ((single = strsep(&string, ",")))
150 {
151 proposal = proposal_create_from_string(proto, single);
152 if (proposal)
153 {
154 if (ike_cfg)
155 {
156 ike_cfg->add_proposal(ike_cfg, proposal);
157 }
158 else
159 {
160 child_cfg->add_proposal(child_cfg, proposal);
161 }
162 continue;
163 }
164 DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
165 }
166 if (strict)
167 {
168 return;
169 }
170 /* add default porposal to the end if not strict */
171 }
172 if (ike_cfg)
173 {
174 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
175 }
176 else
177 {
178 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
179 }
180 }
181
182 /**
183 * Build an IKE config from a stroke message
184 */
185 static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
186 {
187 stroke_end_t tmp_end;
188 ike_cfg_t *ike_cfg;
189 char *interface;
190 host_t *host;
191
192 host = host_create_from_dns(msg->add_conn.other.address, 0, 0);
193 if (host)
194 {
195 interface = hydra->kernel_interface->get_interface(
196 hydra->kernel_interface, host);
197 host->destroy(host);
198 if (interface)
199 {
200 DBG2(DBG_CFG, "left is other host, swapping ends");
201 tmp_end = msg->add_conn.me;
202 msg->add_conn.me = msg->add_conn.other;
203 msg->add_conn.other = tmp_end;
204 free(interface);
205 }
206 else
207 {
208 host = host_create_from_dns(msg->add_conn.me.address, 0, 0);
209 if (host)
210 {
211 interface = hydra->kernel_interface->get_interface(
212 hydra->kernel_interface, host);
213 host->destroy(host);
214 if (!interface)
215 {
216 DBG1(DBG_CFG, "left nor right host is our side, "
217 "assuming left=local");
218 }
219 else
220 {
221 free(interface);
222 }
223
224 }
225 }
226 }
227 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
228 msg->add_conn.force_encap,
229 msg->add_conn.me.address, msg->add_conn.me.ikeport,
230 msg->add_conn.other.address, msg->add_conn.other.ikeport);
231 add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
232 return ike_cfg;
233 }
234
235 /**
236 * Add CRL constraint to config
237 */
238 static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
239 {
240 /* CRL/OCSP policy, for remote config only */
241 if (!local)
242 {
243 switch (policy)
244 {
245 case CRL_STRICT_YES:
246 /* if yes, we require a GOOD validation */
247 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
248 break;
249 case CRL_STRICT_IFURI:
250 /* for ifuri, a SKIPPED validation is sufficient */
251 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
252 break;
253 default:
254 break;
255 }
256 }
257 }
258
259 /**
260 * build authentication config
261 */
262 static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
263 stroke_msg_t *msg, bool local, bool primary)
264 {
265 identification_t *identity;
266 certificate_t *certificate;
267 char *auth, *id, *pubkey, *cert, *ca;
268 stroke_end_t *end, *other_end;
269 auth_cfg_t *cfg;
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 auth = "pubkey";
318 }
319 else
320 { /* no second authentication round, fine. But load certificates
321 * for other purposes (EAP-TLS) */
322 if (cert)
323 {
324 certificate = this->cred->load_peer(this->cred, cert);
325 if (certificate)
326 {
327 certificate->destroy(certificate);
328 }
329 }
330 return NULL;
331 }
332 }
333
334 cfg = auth_cfg_create();
335
336 /* add identity and peer certifcate */
337 identity = identification_create_from_string(id);
338 if (cert)
339 {
340 certificate = this->cred->load_peer(this->cred, cert);
341 if (certificate)
342 {
343 if (local)
344 {
345 this->ca->check_for_hash_and_url(this->ca, certificate);
346 }
347 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
348 if (identity->get_type(identity) == ID_ANY ||
349 !certificate->has_subject(certificate, identity))
350 {
351 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
352 "defaulting to '%Y'", identity,
353 certificate->get_subject(certificate));
354 identity->destroy(identity);
355 identity = certificate->get_subject(certificate);
356 identity = identity->clone(identity);
357 }
358 }
359 }
360 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
361
362 /* add raw RSA public key */
363 pubkey = end->rsakey;
364 if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
365 {
366 certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey,
367 identity);
368 if (certificate)
369 {
370 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
371 }
372 }
373
374 /* CA constraint */
375 if (ca)
376 {
377 identity = identification_create_from_string(ca);
378 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
379 KEY_ANY, identity, TRUE);
380 identity->destroy(identity);
381 if (certificate)
382 {
383 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
384 }
385 else
386 {
387 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
388 "constraint", ca);
389 }
390 }
391
392 /* groups */
393 if (end->groups)
394 {
395 enumerator_t *enumerator;
396 char *group;
397
398 enumerator = enumerator_create_token(end->groups, ",", " ");
399 while (enumerator->enumerate(enumerator, &group))
400 {
401 cfg->add(cfg, AUTH_RULE_GROUP,
402 identification_create_from_string(group));
403 }
404 enumerator->destroy(enumerator);
405 }
406
407 /* certificatePolicies */
408 if (end->cert_policy)
409 {
410 enumerator_t *enumerator;
411 char *policy;
412
413 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
414 while (enumerator->enumerate(enumerator, &policy))
415 {
416 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
417 }
418 enumerator->destroy(enumerator);
419 }
420
421 /* authentication metod (class, actually) */
422 if (streq(auth, "pubkey") ||
423 strneq(auth, "rsa", strlen("rsa")) ||
424 strneq(auth, "ecdsa", strlen("ecdsa")))
425 {
426 u_int strength;
427
428 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
429 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
430
431 if (sscanf(auth, "rsa-%d", &strength) == 1)
432 {
433 cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
434 }
435 if (sscanf(auth, "ecdsa-%d", &strength) == 1)
436 {
437 cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
438 }
439 }
440 else if (streq(auth, "psk") || streq(auth, "secret"))
441 {
442 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
443 }
444 else if (strneq(auth, "xauth", 5))
445 {
446 char *pos;
447
448 pos = strchr(auth, '-');
449 if (pos)
450 {
451 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
452 }
453 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
454 if (msg->add_conn.xauth_identity)
455 {
456 cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
457 identification_create_from_string(msg->add_conn.xauth_identity));
458 }
459 }
460 else if (strneq(auth, "eap", 3))
461 {
462 enumerator_t *enumerator;
463 char *str;
464 int i = 0, type = 0, vendor;
465
466 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
467
468 /* parse EAP string, format: eap[-type[-vendor]] */
469 enumerator = enumerator_create_token(auth, "-", " ");
470 while (enumerator->enumerate(enumerator, &str))
471 {
472 switch (i)
473 {
474 case 1:
475 type = eap_type_from_string(str);
476 if (!type)
477 {
478 type = atoi(str);
479 if (!type)
480 {
481 DBG1(DBG_CFG, "unknown EAP method: %s", str);
482 break;
483 }
484 }
485 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
486 break;
487 case 2:
488 if (type)
489 {
490 vendor = atoi(str);
491 if (vendor)
492 {
493 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
494 }
495 else
496 {
497 DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
498 }
499 }
500 break;
501 default:
502 break;
503 }
504 i++;
505 }
506 enumerator->destroy(enumerator);
507
508 if (msg->add_conn.eap_identity)
509 {
510 if (streq(msg->add_conn.eap_identity, "%identity"))
511 {
512 identity = identification_create_from_encoding(ID_ANY,
513 chunk_empty);
514 }
515 else
516 {
517 identity = identification_create_from_string(
518 msg->add_conn.eap_identity);
519 }
520 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
521 }
522 if (msg->add_conn.aaa_identity)
523 {
524 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
525 identification_create_from_string(msg->add_conn.aaa_identity));
526 }
527 }
528 else
529 {
530 if (!streq(auth, "any"))
531 {
532 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
533 auth);
534 }
535 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
536 }
537 return cfg;
538 }
539
540 /**
541 * build a peer_cfg from a stroke msg
542 */
543 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
544 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
545 {
546 identification_t *peer_id = NULL;
547 peer_cfg_t *mediated_by = NULL;
548 host_t *vip = NULL;
549 unique_policy_t unique;
550 u_int32_t rekey = 0, reauth = 0, over, jitter;
551 peer_cfg_t *peer_cfg;
552 auth_cfg_t *auth_cfg;
553
554 #ifdef ME
555 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
556 {
557 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
558 "at the same time, aborting");
559 return NULL;
560 }
561
562 if (msg->add_conn.ikeme.mediation)
563 {
564 /* force unique connections for mediation connections */
565 msg->add_conn.unique = 1;
566 }
567
568 if (msg->add_conn.ikeme.mediated_by)
569 {
570 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
571 msg->add_conn.ikeme.mediated_by);
572 if (!mediated_by)
573 {
574 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
575 msg->add_conn.ikeme.mediated_by);
576 return NULL;
577 }
578 if (!mediated_by->is_mediation(mediated_by))
579 {
580 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
581 "no mediation connection, aborting",
582 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
583 mediated_by->destroy(mediated_by);
584 return NULL;
585 }
586 if (msg->add_conn.ikeme.peerid)
587 {
588 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
589 }
590 else if (msg->add_conn.other.id)
591 {
592 peer_id = identification_create_from_string(msg->add_conn.other.id);
593 }
594 }
595 #endif /* ME */
596
597 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
598 over = msg->add_conn.rekey.margin;
599 if (msg->add_conn.rekey.reauth)
600 {
601 reauth = msg->add_conn.rekey.ike_lifetime - over;
602 }
603 else
604 {
605 rekey = msg->add_conn.rekey.ike_lifetime - over;
606 }
607 if (msg->add_conn.me.sourceip_mask)
608 {
609 if (msg->add_conn.me.sourceip)
610 {
611 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
612 }
613 if (!vip)
614 { /* if it is set to something like %poolname, request an address */
615 if (msg->add_conn.me.subnets)
616 { /* use the same address as in subnet, if any */
617 if (strchr(msg->add_conn.me.subnets, '.'))
618 {
619 vip = host_create_any(AF_INET);
620 }
621 else
622 {
623 vip = host_create_any(AF_INET6);
624 }
625 }
626 else
627 {
628 if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
629 {
630 vip = host_create_any(AF_INET6);
631 }
632 else
633 {
634 vip = host_create_any(AF_INET);
635 }
636 }
637 }
638 }
639 switch (msg->add_conn.unique)
640 {
641 case 1: /* yes */
642 case 2: /* replace */
643 unique = UNIQUE_REPLACE;
644 break;
645 case 3: /* keep */
646 unique = UNIQUE_KEEP;
647 break;
648 default: /* no */
649 unique = UNIQUE_NO;
650 break;
651 }
652 if (msg->add_conn.dpd.action == 0)
653 { /* dpdaction=none disables DPD */
654 msg->add_conn.dpd.delay = 0;
655 }
656
657 /* other.sourceip is managed in stroke_attributes. If it is set, we define
658 * the pool name as the connection name, which the attribute provider
659 * uses to serve pool addresses. */
660 peer_cfg = peer_cfg_create(msg->add_conn.name,
661 msg->add_conn.version, ike_cfg,
662 msg->add_conn.me.sendcert, unique,
663 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
664 msg->add_conn.mobike, msg->add_conn.aggressive,
665 msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
666 vip, msg->add_conn.other.sourceip_mask ?
667 msg->add_conn.name : msg->add_conn.other.sourceip,
668 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
669
670 /* build leftauth= */
671 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
672 if (auth_cfg)
673 {
674 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
675 }
676 else
677 { /* we require at least one config on our side */
678 peer_cfg->destroy(peer_cfg);
679 return NULL;
680 }
681 /* build leftauth2= */
682 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
683 if (auth_cfg)
684 {
685 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
686 }
687 /* build rightauth= */
688 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
689 if (auth_cfg)
690 {
691 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
692 }
693 /* build rightauth2= */
694 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
695 if (auth_cfg)
696 {
697 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
698 }
699 return peer_cfg;
700 }
701
702 /**
703 * build a traffic selector from a stroke_end
704 */
705 static void add_ts(private_stroke_config_t *this,
706 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
707 {
708 traffic_selector_t *ts;
709
710 if (end->tohost)
711 {
712 ts = traffic_selector_create_dynamic(end->protocol,
713 end->port ? end->port : 0, end->port ? end->port : 65535);
714 child_cfg->add_traffic_selector(child_cfg, local, ts);
715 }
716 else
717 {
718 host_t *net;
719
720 if (!end->subnets)
721 {
722 net = host_create_from_string(end->address, 0);
723 if (net)
724 {
725 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
726 end->port);
727 child_cfg->add_traffic_selector(child_cfg, local, ts);
728 }
729 }
730 else
731 {
732 char *del, *start, *bits;
733
734 start = end->subnets;
735 do
736 {
737 int intbits = 0;
738
739 del = strchr(start, ',');
740 if (del)
741 {
742 *del = '\0';
743 }
744 bits = strchr(start, '/');
745 if (bits)
746 {
747 *bits = '\0';
748 intbits = atoi(bits + 1);
749 }
750
751 net = host_create_from_string(start, 0);
752 if (net)
753 {
754 ts = traffic_selector_create_from_subnet(net, intbits,
755 end->protocol, end->port);
756 child_cfg->add_traffic_selector(child_cfg, local, ts);
757 }
758 else
759 {
760 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
761 }
762 start = del + 1;
763 }
764 while (del);
765 }
766 }
767 }
768
769 /**
770 * map starter magic values to our action type
771 */
772 static action_t map_action(int starter_action)
773 {
774 switch (starter_action)
775 {
776 case 2: /* =hold */
777 return ACTION_ROUTE;
778 case 3: /* =restart */
779 return ACTION_RESTART;
780 default:
781 return ACTION_NONE;
782 }
783 }
784
785 /**
786 * build a child config from the stroke message
787 */
788 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
789 stroke_msg_t *msg)
790 {
791 child_cfg_t *child_cfg;
792 lifetime_cfg_t lifetime = {
793 .time = {
794 .life = msg->add_conn.rekey.ipsec_lifetime,
795 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
796 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
797 },
798 .bytes = {
799 .life = msg->add_conn.rekey.life_bytes,
800 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
801 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
802 },
803 .packets = {
804 .life = msg->add_conn.rekey.life_packets,
805 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
806 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
807 }
808 };
809 mark_t mark_in = {
810 .value = msg->add_conn.mark_in.value,
811 .mask = msg->add_conn.mark_in.mask
812 };
813 mark_t mark_out = {
814 .value = msg->add_conn.mark_out.value,
815 .mask = msg->add_conn.mark_out.mask
816 };
817
818 child_cfg = child_cfg_create(
819 msg->add_conn.name, &lifetime, msg->add_conn.me.updown,
820 msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE,
821 map_action(msg->add_conn.dpd.action),
822 map_action(msg->add_conn.close_action), msg->add_conn.ipcomp,
823 msg->add_conn.inactivity, msg->add_conn.reqid,
824 &mark_in, &mark_out, msg->add_conn.tfc);
825 child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
826 msg->add_conn.install_policy);
827 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
828 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
829
830 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
831
832 return child_cfg;
833 }
834
835 METHOD(stroke_config_t, add, void,
836 private_stroke_config_t *this, stroke_msg_t *msg)
837 {
838 ike_cfg_t *ike_cfg, *existing_ike;
839 peer_cfg_t *peer_cfg, *existing;
840 child_cfg_t *child_cfg;
841 enumerator_t *enumerator;
842 bool use_existing = FALSE;
843
844 ike_cfg = build_ike_cfg(this, msg);
845 if (!ike_cfg)
846 {
847 return;
848 }
849 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
850 if (!peer_cfg)
851 {
852 ike_cfg->destroy(ike_cfg);
853 return;
854 }
855
856 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
857 while (enumerator->enumerate(enumerator, &existing))
858 {
859 existing_ike = existing->get_ike_cfg(existing);
860 if (existing->equals(existing, peer_cfg) &&
861 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
862 {
863 use_existing = TRUE;
864 peer_cfg->destroy(peer_cfg);
865 peer_cfg = existing;
866 peer_cfg->get_ref(peer_cfg);
867 DBG1(DBG_CFG, "added child to existing configuration '%s'",
868 peer_cfg->get_name(peer_cfg));
869 break;
870 }
871 }
872 enumerator->destroy(enumerator);
873
874 child_cfg = build_child_cfg(this, msg);
875 if (!child_cfg)
876 {
877 peer_cfg->destroy(peer_cfg);
878 return;
879 }
880 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
881
882 if (use_existing)
883 {
884 peer_cfg->destroy(peer_cfg);
885 }
886 else
887 {
888 /* add config to backend */
889 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
890 this->mutex->lock(this->mutex);
891 this->list->insert_last(this->list, peer_cfg);
892 this->mutex->unlock(this->mutex);
893 }
894 }
895
896 METHOD(stroke_config_t, del, void,
897 private_stroke_config_t *this, stroke_msg_t *msg)
898 {
899 enumerator_t *enumerator, *children;
900 peer_cfg_t *peer;
901 child_cfg_t *child;
902 bool deleted = FALSE;
903
904 this->mutex->lock(this->mutex);
905 enumerator = this->list->create_enumerator(this->list);
906 while (enumerator->enumerate(enumerator, (void**)&peer))
907 {
908 bool keep = FALSE;
909
910 /* remove any child with such a name */
911 children = peer->create_child_cfg_enumerator(peer);
912 while (children->enumerate(children, &child))
913 {
914 if (streq(child->get_name(child), msg->del_conn.name))
915 {
916 peer->remove_child_cfg(peer, children);
917 child->destroy(child);
918 deleted = TRUE;
919 }
920 else
921 {
922 keep = TRUE;
923 }
924 }
925 children->destroy(children);
926
927 /* if peer config matches, or has no children anymore, remove it */
928 if (!keep || streq(peer->get_name(peer), msg->del_conn.name))
929 {
930 this->list->remove_at(this->list, enumerator);
931 peer->destroy(peer);
932 deleted = TRUE;
933 }
934 }
935 enumerator->destroy(enumerator);
936 this->mutex->unlock(this->mutex);
937
938 if (deleted)
939 {
940 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
941 }
942 else
943 {
944 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
945 }
946 }
947
948 METHOD(stroke_config_t, set_user_credentials, void,
949 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
950 {
951 enumerator_t *enumerator, *children, *remote_auth;
952 peer_cfg_t *peer, *found = NULL;
953 auth_cfg_t *auth_cfg, *remote_cfg;
954 auth_class_t auth_class;
955 child_cfg_t *child;
956 identification_t *id, *identity, *gw = NULL;
957 shared_key_type_t type = SHARED_ANY;
958 chunk_t password = chunk_empty;
959
960 this->mutex->lock(this->mutex);
961 enumerator = this->list->create_enumerator(this->list);
962 while (enumerator->enumerate(enumerator, (void**)&peer))
963 { /* find the peer (or child) config with the given name */
964 if (streq(peer->get_name(peer), msg->user_creds.name))
965 {
966 found = peer;
967 }
968 else
969 {
970 children = peer->create_child_cfg_enumerator(peer);
971 while (children->enumerate(children, &child))
972 {
973 if (streq(child->get_name(child), msg->user_creds.name))
974 {
975 found = peer;
976 break;
977 }
978 }
979 children->destroy(children);
980 }
981
982 if (found)
983 {
984 break;
985 }
986 }
987 enumerator->destroy(enumerator);
988
989 if (!found)
990 {
991 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
992 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
993 this->mutex->unlock(this->mutex);
994 return;
995 }
996
997 id = identification_create_from_string(msg->user_creds.username);
998 if (strlen(msg->user_creds.username) == 0 ||
999 !id || id->get_type(id) == ID_ANY)
1000 {
1001 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1002 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1003 this->mutex->unlock(this->mutex);
1004 DESTROY_IF(id);
1005 return;
1006 }
1007
1008 /* replace/set the username in the first EAP auth_cfg, also look for a
1009 * suitable remote ID.
1010 * note that adding the identity here is not fully thread-safe as the
1011 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1012 * case (setting user credentials before upping the connection) this will
1013 * not be a problem, though. */
1014 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1015 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1016 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1017 {
1018 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1019 { /* fall back on rightid, in case aaa_identity is not specified */
1020 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1021 if (identity && identity->get_type(identity) != ID_ANY)
1022 {
1023 gw = identity;
1024 }
1025 }
1026
1027 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1028 if (auth_class == AUTH_CLASS_EAP)
1029 {
1030 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1031 /* if aaa_identity is specified use that as remote ID */
1032 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1033 if (identity && identity->get_type(identity) != ID_ANY)
1034 {
1035 gw = identity;
1036 }
1037 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1038 type = SHARED_EAP;
1039 break;
1040 }
1041 }
1042 enumerator->destroy(enumerator);
1043 remote_auth->destroy(remote_auth);
1044 /* clone the gw ID before unlocking the mutex */
1045 if (gw)
1046 {
1047 gw = gw->clone(gw);
1048 }
1049 this->mutex->unlock(this->mutex);
1050
1051 if (type == SHARED_ANY)
1052 {
1053 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1054 msg->user_creds.name);
1055 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1056 msg->user_creds.name);
1057 id->destroy(id);
1058 DESTROY_IF(gw);
1059 return;
1060 }
1061
1062 if (msg->user_creds.password)
1063 {
1064 char *pass;
1065
1066 pass = msg->user_creds.password;
1067 password = chunk_clone(chunk_create(pass, strlen(pass)));
1068 memwipe(pass, strlen(pass));
1069 }
1070 else
1071 { /* prompt the user for the password */
1072 char buf[256];
1073
1074 fprintf(prompt, "Password:\n");
1075 if (fgets(buf, sizeof(buf), prompt))
1076 {
1077 password = chunk_clone(chunk_create(buf, strlen(buf)));
1078 if (password.len > 0)
1079 { /* trim trailing \n */
1080 password.len--;
1081 }
1082 memwipe(buf, sizeof(buf));
1083 }
1084 }
1085
1086 if (password.len)
1087 {
1088 shared_key_t *shared;
1089 linked_list_t *owners;
1090
1091 shared = shared_key_create(type, password);
1092
1093 owners = linked_list_create();
1094 owners->insert_last(owners, id->clone(id));
1095 if (gw && gw->get_type(gw) != ID_ANY)
1096 {
1097 owners->insert_last(owners, gw->clone(gw));
1098 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1099 type, id, gw);
1100 }
1101 else
1102 {
1103 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1104 type, id);
1105 }
1106 this->cred->add_shared(this->cred, shared, owners);
1107 DBG4(DBG_CFG, " secret: %#B", &password);
1108 }
1109 else
1110 { /* in case a user answers the password prompt by just pressing enter */
1111 chunk_clear(&password);
1112 }
1113 id->destroy(id);
1114 DESTROY_IF(gw);
1115 }
1116
1117 METHOD(stroke_config_t, destroy, void,
1118 private_stroke_config_t *this)
1119 {
1120 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1121 this->mutex->destroy(this->mutex);
1122 free(this);
1123 }
1124
1125 /*
1126 * see header file
1127 */
1128 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
1129 {
1130 private_stroke_config_t *this;
1131
1132 INIT(this,
1133 .public = {
1134 .backend = {
1135 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1136 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1137 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1138 },
1139 .add = _add,
1140 .del = _del,
1141 .set_user_credentials = _set_user_credentials,
1142 .destroy = _destroy,
1143 },
1144 .list = linked_list_create(),
1145 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1146 .ca = ca,
1147 .cred = cred,
1148 );
1149
1150 return &this->public;
1151 }
1152