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