Support multiple virtual IPs on peer_cfg and ike_sa classes
[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 u_int16_t ikeport;
192
193 host = host_create_from_dns(msg->add_conn.other.address, 0, 0);
194 if (host)
195 {
196 interface = hydra->kernel_interface->get_interface(
197 hydra->kernel_interface, host);
198 host->destroy(host);
199 if (interface)
200 {
201 DBG2(DBG_CFG, "left is other host, swapping ends");
202 tmp_end = msg->add_conn.me;
203 msg->add_conn.me = msg->add_conn.other;
204 msg->add_conn.other = tmp_end;
205 free(interface);
206 }
207 else
208 {
209 host = host_create_from_dns(msg->add_conn.me.address, 0, 0);
210 if (host)
211 {
212 interface = hydra->kernel_interface->get_interface(
213 hydra->kernel_interface, host);
214 host->destroy(host);
215 if (!interface)
216 {
217 DBG1(DBG_CFG, "left nor right host is our side, "
218 "assuming left=local");
219 }
220 else
221 {
222 free(interface);
223 }
224
225 }
226 }
227 }
228 ikeport = msg->add_conn.me.ikeport;
229 ikeport = (ikeport == IKEV2_UDP_PORT) ?
230 charon->socket->get_port(charon->socket, FALSE) : ikeport;
231 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
232 msg->add_conn.force_encap,
233 msg->add_conn.me.address,
234 msg->add_conn.me.allow_any,
235 ikeport,
236 msg->add_conn.other.address,
237 msg->add_conn.other.allow_any,
238 msg->add_conn.other.ikeport);
239 add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
240 return ike_cfg;
241 }
242
243 /**
244 * Add CRL constraint to config
245 */
246 static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
247 {
248 /* CRL/OCSP policy, for remote config only */
249 if (!local)
250 {
251 switch (policy)
252 {
253 case CRL_STRICT_YES:
254 /* if yes, we require a GOOD validation */
255 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
256 break;
257 case CRL_STRICT_IFURI:
258 /* for ifuri, a SKIPPED validation is sufficient */
259 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
260 break;
261 default:
262 break;
263 }
264 }
265 }
266
267 /**
268 * Parse public key / signature strength constraints
269 */
270 static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg)
271 {
272 enumerator_t *enumerator;
273 bool rsa = FALSE, ecdsa = FALSE, rsa_len = FALSE, ecdsa_len = FALSE;
274 int strength;
275 char *token;
276
277 enumerator = enumerator_create_token(auth, "-", "");
278 while (enumerator->enumerate(enumerator, &token))
279 {
280 bool found = FALSE;
281 int i;
282 struct {
283 char *name;
284 signature_scheme_t scheme;
285 key_type_t key;
286 } schemes[] = {
287 { "md5", SIGN_RSA_EMSA_PKCS1_MD5, KEY_RSA, },
288 { "sha1", SIGN_RSA_EMSA_PKCS1_SHA1, KEY_RSA, },
289 { "sha224", SIGN_RSA_EMSA_PKCS1_SHA224, KEY_RSA, },
290 { "sha256", SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, },
291 { "sha384", SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, },
292 { "sha512", SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, },
293 { "sha1", SIGN_ECDSA_WITH_SHA1_DER, KEY_ECDSA, },
294 { "sha256", SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, },
295 { "sha384", SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, },
296 { "sha512", SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, },
297 { "sha256", SIGN_ECDSA_256, KEY_ECDSA, },
298 { "sha384", SIGN_ECDSA_384, KEY_ECDSA, },
299 { "sha512", SIGN_ECDSA_521, KEY_ECDSA, },
300 };
301
302 if (rsa_len || ecdsa_len)
303 { /* expecting a key strength token */
304 strength = atoi(token);
305 if (strength)
306 {
307 if (rsa_len)
308 {
309 cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
310 }
311 else if (ecdsa_len)
312 {
313 cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
314 }
315 }
316 rsa_len = ecdsa_len = FALSE;
317 if (strength)
318 {
319 continue;
320 }
321 }
322 if (streq(token, "rsa"))
323 {
324 rsa = rsa_len = TRUE;
325 continue;
326 }
327 if (streq(token, "ecdsa"))
328 {
329 ecdsa = ecdsa_len = TRUE;
330 continue;
331 }
332 if (streq(token, "pubkey"))
333 {
334 continue;
335 }
336
337 for (i = 0; i < countof(schemes); i++)
338 {
339 if (streq(schemes[i].name, token))
340 {
341 /* for each matching string, allow the scheme, if:
342 * - it is an RSA scheme, and we enforced RSA
343 * - it is an ECDSA scheme, and we enforced ECDSA
344 * - it is not a key type specific scheme
345 */
346 if ((rsa && schemes[i].key == KEY_RSA) ||
347 (ecdsa && schemes[i].key == KEY_ECDSA) ||
348 (!rsa && !ecdsa))
349 {
350 cfg->add(cfg, AUTH_RULE_SIGNATURE_SCHEME,
351 (uintptr_t)schemes[i].scheme);
352 }
353 found = TRUE;
354 }
355 }
356 if (!found)
357 {
358 DBG1(DBG_CFG, "ignoring invalid auth token: '%s'", token);
359 }
360 }
361 enumerator->destroy(enumerator);
362 }
363
364 /**
365 * build authentication config
366 */
367 static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
368 stroke_msg_t *msg, bool local, bool primary)
369 {
370 identification_t *identity;
371 certificate_t *certificate;
372 char *auth, *id, *pubkey, *cert, *ca, *groups;
373 stroke_end_t *end, *other_end;
374 auth_cfg_t *cfg;
375
376 /* select strings */
377 if (local)
378 {
379 end = &msg->add_conn.me;
380 other_end = &msg->add_conn.other;
381 }
382 else
383 {
384 end = &msg->add_conn.other;
385 other_end = &msg->add_conn.me;
386 }
387 if (primary)
388 {
389 auth = end->auth;
390 id = end->id;
391 if (!id)
392 { /* leftid/rightid fallback to address */
393 id = end->address;
394 }
395 cert = end->cert;
396 ca = end->ca;
397 if (ca && streq(ca, "%same"))
398 {
399 ca = other_end->ca;
400 }
401 }
402 else
403 {
404 auth = end->auth2;
405 id = end->id2;
406 if (local && !id)
407 { /* leftid2 falls back to leftid */
408 id = end->id;
409 }
410 cert = end->cert2;
411 ca = end->ca2;
412 if (ca && streq(ca, "%same"))
413 {
414 ca = other_end->ca2;
415 }
416 }
417
418 if (!auth)
419 {
420 if (primary)
421 {
422 auth = "pubkey";
423 }
424 else
425 { /* no second authentication round, fine. But load certificates
426 * for other purposes (EAP-TLS) */
427 if (cert)
428 {
429 certificate = this->cred->load_peer(this->cred, cert);
430 if (certificate)
431 {
432 certificate->destroy(certificate);
433 }
434 }
435 return NULL;
436 }
437 }
438
439 cfg = auth_cfg_create();
440
441 /* add identity and peer certifcate */
442 identity = identification_create_from_string(id);
443 if (cert)
444 {
445 certificate = this->cred->load_peer(this->cred, cert);
446 if (certificate)
447 {
448 if (local)
449 {
450 this->ca->check_for_hash_and_url(this->ca, certificate);
451 }
452 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
453 if (identity->get_type(identity) == ID_ANY ||
454 !certificate->has_subject(certificate, identity))
455 {
456 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
457 "defaulting to '%Y'", identity,
458 certificate->get_subject(certificate));
459 identity->destroy(identity);
460 identity = certificate->get_subject(certificate);
461 identity = identity->clone(identity);
462 }
463 }
464 }
465 if (identity->get_type(identity) != ID_ANY)
466 {
467 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
468 }
469 else
470 {
471 identity->destroy(identity);
472 }
473
474 /* add raw RSA public key */
475 pubkey = end->rsakey;
476 if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
477 {
478 certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey,
479 identity);
480 if (certificate)
481 {
482 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
483 }
484 }
485
486 /* CA constraint */
487 if (ca)
488 {
489 identity = identification_create_from_string(ca);
490 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
491 KEY_ANY, identity, TRUE);
492 identity->destroy(identity);
493 if (certificate)
494 {
495 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
496 }
497 else
498 {
499 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
500 "constraint", ca);
501 }
502 }
503
504 /* groups */
505 groups = primary ? end->groups : end->groups2;
506 if (groups)
507 {
508 enumerator_t *enumerator;
509 char *group;
510
511 enumerator = enumerator_create_token(groups, ",", " ");
512 while (enumerator->enumerate(enumerator, &group))
513 {
514 cfg->add(cfg, AUTH_RULE_GROUP,
515 identification_create_from_string(group));
516 }
517 enumerator->destroy(enumerator);
518 }
519
520 /* certificatePolicies */
521 if (end->cert_policy)
522 {
523 enumerator_t *enumerator;
524 char *policy;
525
526 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
527 while (enumerator->enumerate(enumerator, &policy))
528 {
529 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
530 }
531 enumerator->destroy(enumerator);
532 }
533
534 /* authentication metod (class, actually) */
535 if (strneq(auth, "pubkey", strlen("pubkey")) ||
536 strneq(auth, "rsa", strlen("rsa")) ||
537 strneq(auth, "ecdsa", strlen("ecdsa")))
538 {
539 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
540 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
541
542 parse_pubkey_constraints(auth, cfg);
543 }
544 else if (streq(auth, "psk") || streq(auth, "secret"))
545 {
546 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
547 }
548 else if (strneq(auth, "xauth", 5))
549 {
550 char *pos;
551
552 pos = strchr(auth, '-');
553 if (pos)
554 {
555 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
556 }
557 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
558 if (msg->add_conn.xauth_identity)
559 {
560 cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
561 identification_create_from_string(msg->add_conn.xauth_identity));
562 }
563 }
564 else if (strneq(auth, "eap", 3))
565 {
566 enumerator_t *enumerator;
567 char *str;
568 int i = 0, type = 0, vendor;
569
570 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
571
572 /* parse EAP string, format: eap[-type[-vendor]] */
573 enumerator = enumerator_create_token(auth, "-", " ");
574 while (enumerator->enumerate(enumerator, &str))
575 {
576 switch (i)
577 {
578 case 1:
579 type = eap_type_from_string(str);
580 if (!type)
581 {
582 type = atoi(str);
583 if (!type)
584 {
585 DBG1(DBG_CFG, "unknown EAP method: %s", str);
586 break;
587 }
588 }
589 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
590 break;
591 case 2:
592 if (type)
593 {
594 vendor = atoi(str);
595 if (vendor)
596 {
597 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
598 }
599 else
600 {
601 DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
602 }
603 }
604 break;
605 default:
606 break;
607 }
608 i++;
609 }
610 enumerator->destroy(enumerator);
611
612 if (msg->add_conn.eap_identity)
613 {
614 if (streq(msg->add_conn.eap_identity, "%identity"))
615 {
616 identity = identification_create_from_encoding(ID_ANY,
617 chunk_empty);
618 }
619 else
620 {
621 identity = identification_create_from_string(
622 msg->add_conn.eap_identity);
623 }
624 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
625 }
626 if (msg->add_conn.aaa_identity)
627 {
628 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
629 identification_create_from_string(msg->add_conn.aaa_identity));
630 }
631 }
632 else
633 {
634 if (!streq(auth, "any"))
635 {
636 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
637 auth);
638 }
639 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
640 }
641 return cfg;
642 }
643
644 /**
645 * build a peer_cfg from a stroke msg
646 */
647 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
648 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
649 {
650 identification_t *peer_id = NULL;
651 peer_cfg_t *mediated_by = NULL;
652 host_t *vip = NULL;
653 unique_policy_t unique;
654 u_int32_t rekey = 0, reauth = 0, over, jitter;
655 peer_cfg_t *peer_cfg;
656 auth_cfg_t *auth_cfg;
657
658 #ifdef ME
659 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
660 {
661 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
662 "at the same time, aborting");
663 return NULL;
664 }
665
666 if (msg->add_conn.ikeme.mediation)
667 {
668 /* force unique connections for mediation connections */
669 msg->add_conn.unique = 1;
670 }
671
672 if (msg->add_conn.ikeme.mediated_by)
673 {
674 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
675 msg->add_conn.ikeme.mediated_by);
676 if (!mediated_by)
677 {
678 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
679 msg->add_conn.ikeme.mediated_by);
680 return NULL;
681 }
682 if (!mediated_by->is_mediation(mediated_by))
683 {
684 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
685 "no mediation connection, aborting",
686 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
687 mediated_by->destroy(mediated_by);
688 return NULL;
689 }
690 if (msg->add_conn.ikeme.peerid)
691 {
692 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
693 }
694 else if (msg->add_conn.other.id)
695 {
696 peer_id = identification_create_from_string(msg->add_conn.other.id);
697 }
698 }
699 #endif /* ME */
700
701 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
702 over = msg->add_conn.rekey.margin;
703 if (msg->add_conn.rekey.reauth)
704 {
705 reauth = msg->add_conn.rekey.ike_lifetime - over;
706 }
707 else
708 {
709 rekey = msg->add_conn.rekey.ike_lifetime - over;
710 }
711 if (msg->add_conn.me.sourceip_mask)
712 {
713 if (msg->add_conn.me.sourceip)
714 {
715 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
716 }
717 if (!vip)
718 { /* if it is set to something like %poolname, request an address */
719 if (msg->add_conn.me.subnets)
720 { /* use the same family as in local subnet, if any */
721 if (strchr(msg->add_conn.me.subnets, '.'))
722 {
723 vip = host_create_any(AF_INET);
724 }
725 else
726 {
727 vip = host_create_any(AF_INET6);
728 }
729 }
730 else if (msg->add_conn.other.subnets)
731 { /* use the same family as in remote subnet, if any */
732 if (strchr(msg->add_conn.other.subnets, '.'))
733 {
734 vip = host_create_any(AF_INET);
735 }
736 else
737 {
738 vip = host_create_any(AF_INET6);
739 }
740 }
741 else
742 {
743 if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
744 {
745 vip = host_create_any(AF_INET6);
746 }
747 else
748 {
749 vip = host_create_any(AF_INET);
750 }
751 }
752 }
753 }
754 switch (msg->add_conn.unique)
755 {
756 case 1: /* yes */
757 case 2: /* replace */
758 unique = UNIQUE_REPLACE;
759 break;
760 case 3: /* keep */
761 unique = UNIQUE_KEEP;
762 break;
763 default: /* no */
764 unique = UNIQUE_NO;
765 break;
766 }
767 if (msg->add_conn.dpd.action == 0)
768 { /* dpdaction=none disables DPD */
769 msg->add_conn.dpd.delay = 0;
770 }
771
772 /* other.sourceip is managed in stroke_attributes. If it is set, we define
773 * the pool name as the connection name, which the attribute provider
774 * uses to serve pool addresses. */
775 peer_cfg = peer_cfg_create(msg->add_conn.name,
776 msg->add_conn.version, ike_cfg,
777 msg->add_conn.me.sendcert, unique,
778 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
779 msg->add_conn.mobike, msg->add_conn.aggressive,
780 msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
781 msg->add_conn.other.sourceip_mask ?
782 msg->add_conn.name : msg->add_conn.other.sourceip,
783 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
784 if (vip)
785 {
786 peer_cfg->add_virtual_ip(peer_cfg, vip);
787 }
788
789 /* build leftauth= */
790 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
791 if (auth_cfg)
792 {
793 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
794 }
795 else
796 { /* we require at least one config on our side */
797 peer_cfg->destroy(peer_cfg);
798 return NULL;
799 }
800 /* build leftauth2= */
801 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
802 if (auth_cfg)
803 {
804 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
805 }
806 /* build rightauth= */
807 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
808 if (auth_cfg)
809 {
810 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
811 }
812 /* build rightauth2= */
813 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
814 if (auth_cfg)
815 {
816 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
817 }
818 return peer_cfg;
819 }
820
821 /**
822 * build a traffic selector from a stroke_end
823 */
824 static void add_ts(private_stroke_config_t *this,
825 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
826 {
827 traffic_selector_t *ts;
828
829 if (end->tohost)
830 {
831 ts = traffic_selector_create_dynamic(end->protocol,
832 end->port ? end->port : 0, end->port ? end->port : 65535);
833 child_cfg->add_traffic_selector(child_cfg, local, ts);
834 }
835 else
836 {
837 host_t *net;
838
839 if (!end->subnets)
840 {
841 net = host_create_from_string(end->address, 0);
842 if (net)
843 {
844 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
845 end->port);
846 child_cfg->add_traffic_selector(child_cfg, local, ts);
847 }
848 }
849 else
850 {
851 char *del, *start, *bits;
852
853 start = end->subnets;
854 do
855 {
856 int intbits = 0;
857
858 del = strchr(start, ',');
859 if (del)
860 {
861 *del = '\0';
862 }
863 bits = strchr(start, '/');
864 if (bits)
865 {
866 *bits = '\0';
867 intbits = atoi(bits + 1);
868 }
869
870 net = host_create_from_string(start, 0);
871 if (net)
872 {
873 ts = traffic_selector_create_from_subnet(net, intbits,
874 end->protocol, end->port);
875 child_cfg->add_traffic_selector(child_cfg, local, ts);
876 }
877 else
878 {
879 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
880 }
881 start = del + 1;
882 }
883 while (del);
884 }
885 }
886 }
887
888 /**
889 * map starter magic values to our action type
890 */
891 static action_t map_action(int starter_action)
892 {
893 switch (starter_action)
894 {
895 case 2: /* =hold */
896 return ACTION_ROUTE;
897 case 3: /* =restart */
898 return ACTION_RESTART;
899 default:
900 return ACTION_NONE;
901 }
902 }
903
904 /**
905 * build a child config from the stroke message
906 */
907 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
908 stroke_msg_t *msg)
909 {
910 child_cfg_t *child_cfg;
911 lifetime_cfg_t lifetime = {
912 .time = {
913 .life = msg->add_conn.rekey.ipsec_lifetime,
914 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
915 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
916 },
917 .bytes = {
918 .life = msg->add_conn.rekey.life_bytes,
919 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
920 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
921 },
922 .packets = {
923 .life = msg->add_conn.rekey.life_packets,
924 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
925 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
926 }
927 };
928 mark_t mark_in = {
929 .value = msg->add_conn.mark_in.value,
930 .mask = msg->add_conn.mark_in.mask
931 };
932 mark_t mark_out = {
933 .value = msg->add_conn.mark_out.value,
934 .mask = msg->add_conn.mark_out.mask
935 };
936
937 child_cfg = child_cfg_create(
938 msg->add_conn.name, &lifetime, msg->add_conn.me.updown,
939 msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE,
940 map_action(msg->add_conn.dpd.action),
941 map_action(msg->add_conn.close_action), msg->add_conn.ipcomp,
942 msg->add_conn.inactivity, msg->add_conn.reqid,
943 &mark_in, &mark_out, msg->add_conn.tfc);
944 child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
945 msg->add_conn.install_policy);
946 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
947 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
948
949 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
950
951 return child_cfg;
952 }
953
954 METHOD(stroke_config_t, add, void,
955 private_stroke_config_t *this, stroke_msg_t *msg)
956 {
957 ike_cfg_t *ike_cfg, *existing_ike;
958 peer_cfg_t *peer_cfg, *existing;
959 child_cfg_t *child_cfg;
960 enumerator_t *enumerator;
961 bool use_existing = FALSE;
962
963 ike_cfg = build_ike_cfg(this, msg);
964 if (!ike_cfg)
965 {
966 return;
967 }
968 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
969 if (!peer_cfg)
970 {
971 ike_cfg->destroy(ike_cfg);
972 return;
973 }
974
975 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
976 while (enumerator->enumerate(enumerator, &existing))
977 {
978 existing_ike = existing->get_ike_cfg(existing);
979 if (existing->equals(existing, peer_cfg) &&
980 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
981 {
982 use_existing = TRUE;
983 peer_cfg->destroy(peer_cfg);
984 peer_cfg = existing;
985 peer_cfg->get_ref(peer_cfg);
986 DBG1(DBG_CFG, "added child to existing configuration '%s'",
987 peer_cfg->get_name(peer_cfg));
988 break;
989 }
990 }
991 enumerator->destroy(enumerator);
992
993 child_cfg = build_child_cfg(this, msg);
994 if (!child_cfg)
995 {
996 peer_cfg->destroy(peer_cfg);
997 return;
998 }
999 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
1000
1001 if (use_existing)
1002 {
1003 peer_cfg->destroy(peer_cfg);
1004 }
1005 else
1006 {
1007 /* add config to backend */
1008 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
1009 this->mutex->lock(this->mutex);
1010 this->list->insert_last(this->list, peer_cfg);
1011 this->mutex->unlock(this->mutex);
1012 }
1013 }
1014
1015 METHOD(stroke_config_t, del, void,
1016 private_stroke_config_t *this, stroke_msg_t *msg)
1017 {
1018 enumerator_t *enumerator, *children;
1019 peer_cfg_t *peer;
1020 child_cfg_t *child;
1021 bool deleted = FALSE;
1022
1023 this->mutex->lock(this->mutex);
1024 enumerator = this->list->create_enumerator(this->list);
1025 while (enumerator->enumerate(enumerator, (void**)&peer))
1026 {
1027 bool keep = FALSE;
1028
1029 /* remove any child with such a name */
1030 children = peer->create_child_cfg_enumerator(peer);
1031 while (children->enumerate(children, &child))
1032 {
1033 if (streq(child->get_name(child), msg->del_conn.name))
1034 {
1035 peer->remove_child_cfg(peer, children);
1036 child->destroy(child);
1037 deleted = TRUE;
1038 }
1039 else
1040 {
1041 keep = TRUE;
1042 }
1043 }
1044 children->destroy(children);
1045
1046 /* if peer config matches, or has no children anymore, remove it */
1047 if (!keep || streq(peer->get_name(peer), msg->del_conn.name))
1048 {
1049 this->list->remove_at(this->list, enumerator);
1050 peer->destroy(peer);
1051 deleted = TRUE;
1052 }
1053 }
1054 enumerator->destroy(enumerator);
1055 this->mutex->unlock(this->mutex);
1056
1057 if (deleted)
1058 {
1059 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
1060 }
1061 else
1062 {
1063 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
1064 }
1065 }
1066
1067 METHOD(stroke_config_t, set_user_credentials, void,
1068 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
1069 {
1070 enumerator_t *enumerator, *children, *remote_auth;
1071 peer_cfg_t *peer, *found = NULL;
1072 auth_cfg_t *auth_cfg, *remote_cfg;
1073 auth_class_t auth_class;
1074 child_cfg_t *child;
1075 identification_t *id, *identity, *gw = NULL;
1076 shared_key_type_t type = SHARED_ANY;
1077 chunk_t password = chunk_empty;
1078
1079 this->mutex->lock(this->mutex);
1080 enumerator = this->list->create_enumerator(this->list);
1081 while (enumerator->enumerate(enumerator, (void**)&peer))
1082 { /* find the peer (or child) config with the given name */
1083 if (streq(peer->get_name(peer), msg->user_creds.name))
1084 {
1085 found = peer;
1086 }
1087 else
1088 {
1089 children = peer->create_child_cfg_enumerator(peer);
1090 while (children->enumerate(children, &child))
1091 {
1092 if (streq(child->get_name(child), msg->user_creds.name))
1093 {
1094 found = peer;
1095 break;
1096 }
1097 }
1098 children->destroy(children);
1099 }
1100
1101 if (found)
1102 {
1103 break;
1104 }
1105 }
1106 enumerator->destroy(enumerator);
1107
1108 if (!found)
1109 {
1110 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
1111 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
1112 this->mutex->unlock(this->mutex);
1113 return;
1114 }
1115
1116 id = identification_create_from_string(msg->user_creds.username);
1117 if (strlen(msg->user_creds.username) == 0 ||
1118 !id || id->get_type(id) == ID_ANY)
1119 {
1120 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1121 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1122 this->mutex->unlock(this->mutex);
1123 DESTROY_IF(id);
1124 return;
1125 }
1126
1127 /* replace/set the username in the first EAP auth_cfg, also look for a
1128 * suitable remote ID.
1129 * note that adding the identity here is not fully thread-safe as the
1130 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1131 * case (setting user credentials before upping the connection) this will
1132 * not be a problem, though. */
1133 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1134 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1135 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1136 {
1137 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1138 { /* fall back on rightid, in case aaa_identity is not specified */
1139 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1140 if (identity && identity->get_type(identity) != ID_ANY)
1141 {
1142 gw = identity;
1143 }
1144 }
1145
1146 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1147 if (auth_class == AUTH_CLASS_EAP)
1148 {
1149 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1150 /* if aaa_identity is specified use that as remote ID */
1151 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1152 if (identity && identity->get_type(identity) != ID_ANY)
1153 {
1154 gw = identity;
1155 }
1156 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1157 type = SHARED_EAP;
1158 break;
1159 }
1160 }
1161 enumerator->destroy(enumerator);
1162 remote_auth->destroy(remote_auth);
1163 /* clone the gw ID before unlocking the mutex */
1164 if (gw)
1165 {
1166 gw = gw->clone(gw);
1167 }
1168 this->mutex->unlock(this->mutex);
1169
1170 if (type == SHARED_ANY)
1171 {
1172 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1173 msg->user_creds.name);
1174 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1175 msg->user_creds.name);
1176 id->destroy(id);
1177 DESTROY_IF(gw);
1178 return;
1179 }
1180
1181 if (msg->user_creds.password)
1182 {
1183 char *pass;
1184
1185 pass = msg->user_creds.password;
1186 password = chunk_clone(chunk_create(pass, strlen(pass)));
1187 memwipe(pass, strlen(pass));
1188 }
1189 else
1190 { /* prompt the user for the password */
1191 char buf[256];
1192
1193 fprintf(prompt, "Password:\n");
1194 if (fgets(buf, sizeof(buf), prompt))
1195 {
1196 password = chunk_clone(chunk_create(buf, strlen(buf)));
1197 if (password.len > 0)
1198 { /* trim trailing \n */
1199 password.len--;
1200 }
1201 memwipe(buf, sizeof(buf));
1202 }
1203 }
1204
1205 if (password.len)
1206 {
1207 shared_key_t *shared;
1208 linked_list_t *owners;
1209
1210 shared = shared_key_create(type, password);
1211
1212 owners = linked_list_create();
1213 owners->insert_last(owners, id->clone(id));
1214 if (gw && gw->get_type(gw) != ID_ANY)
1215 {
1216 owners->insert_last(owners, gw->clone(gw));
1217 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1218 type, id, gw);
1219 }
1220 else
1221 {
1222 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1223 type, id);
1224 }
1225 this->cred->add_shared(this->cred, shared, owners);
1226 DBG4(DBG_CFG, " secret: %#B", &password);
1227 }
1228 else
1229 { /* in case a user answers the password prompt by just pressing enter */
1230 chunk_clear(&password);
1231 }
1232 id->destroy(id);
1233 DESTROY_IF(gw);
1234 }
1235
1236 METHOD(stroke_config_t, destroy, void,
1237 private_stroke_config_t *this)
1238 {
1239 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1240 this->mutex->destroy(this->mutex);
1241 free(this);
1242 }
1243
1244 /*
1245 * see header file
1246 */
1247 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
1248 {
1249 private_stroke_config_t *this;
1250
1251 INIT(this,
1252 .public = {
1253 .backend = {
1254 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1255 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1256 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1257 },
1258 .add = _add,
1259 .del = _del,
1260 .set_user_credentials = _set_user_credentials,
1261 .destroy = _destroy,
1262 },
1263 .list = linked_list_create(),
1264 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1265 .ca = ca,
1266 .cred = cred,
1267 );
1268
1269 return &this->public;
1270 }
1271