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