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