configurable retransmit tries added
[GitHub/MotorolaMobilityLLC/external-strongswan.git] / src / libcharon / plugins / stroke / stroke_config.c
CommitLineData
b67df8e4
SL
1/*
2 * Copyright (C) 2012-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * HSR 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 <daemon.h>
20#include <threading/mutex.h>
21#include <utils/lexparser.h>
22
23#include <netdb.h>
24
25typedef struct private_stroke_config_t private_stroke_config_t;
26
27/**
28 * private data of stroke_config
29 */
30struct private_stroke_config_t {
31
32 /**
33 * public functions
34 */
35 stroke_config_t public;
36
37 /**
38 * list of peer_cfg_t
39 */
40 linked_list_t *list;
41
42 /**
43 * mutex to lock config list
44 */
45 mutex_t *mutex;
46
47 /**
48 * ca sections
49 */
50 stroke_ca_t *ca;
51
52 /**
53 * credentials
54 */
55 stroke_cred_t *cred;
56
57 /**
58 * Virtual IP pool / DNS backend
59 */
60 stroke_attribute_t *attributes;
61};
62
63METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
64 private_stroke_config_t *this, identification_t *me, identification_t *other)
65{
66 this->mutex->lock(this->mutex);
67 return enumerator_create_cleaner(this->list->create_enumerator(this->list),
68 (void*)this->mutex->unlock, this->mutex);
69}
70
71CALLBACK(ike_filter, bool,
72 void *data, enumerator_t *orig, va_list args)
73{
74 peer_cfg_t *cfg;
75 ike_cfg_t **out;
76
77 VA_ARGS_VGET(args, out);
78
79 if (orig->enumerate(orig, &cfg))
80 {
81 *out = cfg->get_ike_cfg(cfg);
82 return TRUE;
83 }
84 return FALSE;
85}
86
87METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
88 private_stroke_config_t *this, host_t *me, host_t *other)
89{
90 this->mutex->lock(this->mutex);
91 return enumerator_create_filter(this->list->create_enumerator(this->list),
92 ike_filter, this->mutex,
93 (void*)this->mutex->unlock);
94}
95
96METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
97 private_stroke_config_t *this, char *name)
98{
99 enumerator_t *e1, *e2;
100 peer_cfg_t *current, *found = NULL;
101 child_cfg_t *child;
102
103 this->mutex->lock(this->mutex);
104 e1 = this->list->create_enumerator(this->list);
105 while (e1->enumerate(e1, &current))
106 {
107 /* compare peer_cfgs name first */
108 if (streq(current->get_name(current), name))
109 {
110 found = current;
111 found->get_ref(found);
112 break;
113 }
114 /* compare all child_cfg names otherwise */
115 e2 = current->create_child_cfg_enumerator(current);
116 while (e2->enumerate(e2, &child))
117 {
118 if (streq(child->get_name(child), name))
119 {
120 found = current;
121 found->get_ref(found);
122 break;
123 }
124 }
125 e2->destroy(e2);
126 if (found)
127 {
128 break;
129 }
130 }
131 e1->destroy(e1);
132 this->mutex->unlock(this->mutex);
133 return found;
134}
135
136/**
137 * parse a proposal string, either into ike_cfg or child_cfg
138 */
139static bool add_proposals(private_stroke_config_t *this, char *string,
140 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg, protocol_id_t proto)
141{
142 if (string)
143 {
144 char *single;
145 char *strict;
146 proposal_t *proposal;
147
148 strict = string + strlen(string) - 1;
149 if (*strict == '!')
150 {
151 *strict = '\0';
152 }
153 else
154 {
155 strict = NULL;
156 }
157 while ((single = strsep(&string, ",")))
158 {
159 proposal = proposal_create_from_string(proto, single);
160 if (proposal)
161 {
162 if (ike_cfg)
163 {
164 ike_cfg->add_proposal(ike_cfg, proposal);
165 }
166 else
167 {
168 child_cfg->add_proposal(child_cfg, proposal);
169 }
170 continue;
171 }
172 DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
173 return FALSE;
174 }
175 if (strict)
176 {
177 return TRUE;
178 }
179 /* add default porposal to the end if not strict */
180 }
181 if (ike_cfg)
182 {
183 ike_cfg->add_proposal(ike_cfg, proposal_create_default(proto));
184 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(proto));
185 }
186 else
187 {
188 child_cfg->add_proposal(child_cfg, proposal_create_default(proto));
189 child_cfg->add_proposal(child_cfg, proposal_create_default_aead(proto));
190 }
191 return TRUE;
192}
193
194/**
195 * Check if any addresses in the given string are local
196 */
197static bool is_local(char *address, bool any_allowed)
198{
199 enumerator_t *enumerator;
200 host_t *host;
201 char *token;
202 bool found = FALSE;
203
204 enumerator = enumerator_create_token(address, ",", " ");
205 while (enumerator->enumerate(enumerator, &token))
206 {
207 if (!strchr(token, '/'))
208 {
209 host = host_create_from_dns(token, 0, 0);
210 if (host)
211 {
212 if (charon->kernel->get_interface(charon->kernel, host, NULL))
213 {
214 found = TRUE;
215 }
216 else if (any_allowed && host->is_anyaddr(host))
217 {
218 found = TRUE;
219 }
220 host->destroy(host);
221 if (found)
222 {
223 break;
224 }
225 }
226 }
227 }
228 enumerator->destroy(enumerator);
229 return found;
230}
231
232/**
233 * Swap ends if indicated by left|right
234 */
235static void swap_ends(stroke_msg_t *msg)
236{
237 if (!lib->settings->get_bool(lib->settings, "%s.plugins.stroke.allow_swap",
238 TRUE, lib->ns))
239 {
240 return;
241 }
242
243 if (is_local(msg->add_conn.other.address, FALSE))
244 {
245 stroke_end_t tmp_end;
246
247 DBG2(DBG_CFG, "left is other host, swapping ends");
248 tmp_end = msg->add_conn.me;
249 msg->add_conn.me = msg->add_conn.other;
250 msg->add_conn.other = tmp_end;
251 }
252 else if (!is_local(msg->add_conn.me.address, TRUE))
253 {
254 DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
255 }
256}
257
258/**
259 * Build an IKE config from a stroke message
260 */
261static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
262{
263 ike_cfg_create_t ike;
264 ike_cfg_t *ike_cfg;
265 char me[256], other[256];
266
267 swap_ends(msg);
268
269 ike = (ike_cfg_create_t){
270 .version = msg->add_conn.version,
271 .local = msg->add_conn.me.address,
272 .local_port = msg->add_conn.me.ikeport,
273 .remote = msg->add_conn.other.address,
274 .remote_port = msg->add_conn.other.ikeport,
275 .no_certreq = msg->add_conn.other.sendcert == CERT_NEVER_SEND,
276 .force_encap = msg->add_conn.force_encap,
277 .fragmentation = msg->add_conn.fragmentation,
278 .dscp = msg->add_conn.ikedscp,
279 };
280 if (msg->add_conn.me.allow_any)
281 {
282 snprintf(me, sizeof(me), "%s,0.0.0.0/0,::/0",
283 msg->add_conn.me.address);
284 ike.local = me;
285 }
286 if (msg->add_conn.other.allow_any)
287 {
288 snprintf(other, sizeof(other), "%s,0.0.0.0/0,::/0",
289 msg->add_conn.other.address);
290 ike.remote = other;
291 }
292 if (ike.local_port == IKEV2_UDP_PORT)
293 {
294 ike.local_port = charon->socket->get_port(charon->socket, FALSE);
295 }
296 ike_cfg = ike_cfg_create(&ike);
297
298 if (!add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg,
299 NULL, PROTO_IKE))
300 {
301 ike_cfg->destroy(ike_cfg);
302 return NULL;
303 }
304 return ike_cfg;
305}
306
307/**
308 * Add CRL constraint to config
309 */
310static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
311{
312 /* CRL/OCSP policy, for remote config only */
313 if (!local)
314 {
315 switch (policy)
316 {
317 case CRL_STRICT_YES:
318 /* if yes, we require a GOOD validation */
319 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
320 break;
321 case CRL_STRICT_IFURI:
322 /* for ifuri, a SKIPPED validation is sufficient */
323 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
324 break;
325 default:
326 break;
327 }
328 }
329}
330
331/**
332 * build authentication config
333 */
334static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
335 stroke_msg_t *msg, bool local, bool primary)
336{
337 identification_t *identity;
338 certificate_t *certificate;
339 char *auth, *id, *pubkey, *cert, *ca, *groups;
340 stroke_end_t *end, *other_end;
341 auth_cfg_t *cfg;
342 bool loose = FALSE;
343
344 /* select strings */
345 if (local)
346 {
347 end = &msg->add_conn.me;
348 other_end = &msg->add_conn.other;
349 }
350 else
351 {
352 end = &msg->add_conn.other;
353 other_end = &msg->add_conn.me;
354 }
355 if (primary)
356 {
357 auth = end->auth;
358 id = end->id;
359 if (!id)
360 { /* leftid/rightid fallback to address */
361 id = end->address;
362 }
363 cert = end->cert;
364 ca = end->ca;
365 if (ca && streq(ca, "%same"))
366 {
367 ca = other_end->ca;
368 }
369 }
370 else
371 {
372 auth = end->auth2;
373 id = end->id2;
374 if (local && !id)
375 { /* leftid2 falls back to leftid */
376 id = end->id;
377 }
378 cert = end->cert2;
379 ca = end->ca2;
380 if (ca && streq(ca, "%same"))
381 {
382 ca = other_end->ca2;
383 }
384 }
385 if (id && *id == '%' && !streq(id, "%any") && !streq(id, "%any6"))
386 { /* has only an effect on rightid/2 */
387 loose = !local;
388 id++;
389 }
390
391 if (!auth)
392 {
393 if (primary)
394 {
395 auth = "pubkey";
396 }
397 else
398 { /* no second authentication round, fine. But load certificates
399 * for other purposes (EAP-TLS) */
400 if (cert)
401 {
402 certificate = this->cred->load_peer(this->cred, cert);
403 if (certificate)
404 {
405 certificate->destroy(certificate);
406 }
407 }
408 return NULL;
409 }
410 }
411
412 cfg = auth_cfg_create();
413
414 /* add identity and peer certificate */
415 identity = identification_create_from_string(id);
416 if (cert)
417 {
418 enumerator_t *enumerator;
419 bool has_subject = FALSE;
420 certificate_t *first = NULL;
421
422 enumerator = enumerator_create_token(cert, ",", " ");
423 while (enumerator->enumerate(enumerator, &cert))
424 {
425 certificate = this->cred->load_peer(this->cred, cert);
426 if (certificate)
427 {
428 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
429 if (!first)
430 {
431 first = certificate;
432 }
433 if (identity->get_type(identity) != ID_ANY &&
434 certificate->has_subject(certificate, identity))
435 {
436 has_subject = TRUE;
437 }
438 }
439 }
440 enumerator->destroy(enumerator);
441
442 if (first && !has_subject)
443 {
444 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
445 "defaulting to '%Y'", identity, first->get_subject(first));
446 identity->destroy(identity);
447 identity = first->get_subject(first);
448 identity = identity->clone(identity);
449 }
450 }
451 /* add raw RSA public key */
452 pubkey = end->rsakey;
453 if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
454 {
455 certificate = this->cred->load_pubkey(this->cred, pubkey, identity);
456 if (certificate)
457 {
458 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
459 }
460 }
461 if (identity->get_type(identity) != ID_ANY)
462 {
463 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
464 if (loose)
465 {
466 cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE);
467 }
468 }
469 else
470 {
471 identity->destroy(identity);
472 }
473
474 /* CA constraint */
475 if (ca)
476 {
477 identity = identification_create_from_string(ca);
478 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
479 KEY_ANY, identity, TRUE);
480 identity->destroy(identity);
481 if (certificate)
482 {
483 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
484 }
485 else
486 {
487 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
488 "constraint", ca);
489 }
490 }
491
492 /* groups */
493 groups = primary ? end->groups : end->groups2;
494 if (groups)
495 {
496 enumerator_t *enumerator;
497 char *group;
498
499 enumerator = enumerator_create_token(groups, ",", " ");
500 while (enumerator->enumerate(enumerator, &group))
501 {
502 cfg->add(cfg, AUTH_RULE_GROUP,
503 identification_create_from_string(group));
504 }
505 enumerator->destroy(enumerator);
506 }
507
508 /* certificatePolicies */
509 if (end->cert_policy)
510 {
511 enumerator_t *enumerator;
512 char *policy;
513
514 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
515 while (enumerator->enumerate(enumerator, &policy))
516 {
517 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
518 }
519 enumerator->destroy(enumerator);
520 }
521
522 /* authentication method (class, actually) */
523 if (strpfx(auth, "ike:") ||
524 strpfx(auth, "pubkey") ||
525 strpfx(auth, "rsa") ||
526 strpfx(auth, "ecdsa") ||
527 strpfx(auth, "bliss"))
528 {
529 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
530 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
531 cfg->add_pubkey_constraints(cfg, auth, TRUE);
532 }
533 else if (streq(auth, "psk") || streq(auth, "secret"))
534 {
535 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
536 }
537 else if (strpfx(auth, "xauth"))
538 {
539 char *pos;
540
541 pos = strchr(auth, '-');
542 if (pos)
543 {
544 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
545 }
546 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
547 if (msg->add_conn.xauth_identity)
548 {
549 cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
550 identification_create_from_string(msg->add_conn.xauth_identity));
551 }
552 }
553 else if (strpfx(auth, "eap"))
554 {
555 eap_vendor_type_t *type;
556 char *pos;
557
558 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
559 /* check for public key constraints for EAP-TLS etc. */
560 pos = strchr(auth, ':');
561 if (pos)
562 {
563 *pos = 0;
564 cfg->add_pubkey_constraints(cfg, pos + 1, FALSE);
565 }
566 type = eap_vendor_type_from_string(auth);
567 if (type)
568 {
569 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
570 if (type->vendor)
571 {
572 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
573 }
574 free(type);
575 }
576
577 if (msg->add_conn.eap_identity)
578 {
579 if (streq(msg->add_conn.eap_identity, "%identity"))
580 {
581 identity = identification_create_from_encoding(ID_ANY,
582 chunk_empty);
583 }
584 else
585 {
586 identity = identification_create_from_string(
587 msg->add_conn.eap_identity);
588 }
589 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
590 }
591 if (msg->add_conn.aaa_identity)
592 {
593 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
594 identification_create_from_string(msg->add_conn.aaa_identity));
595 }
596 }
597 else
598 {
599 if (!streq(auth, "any"))
600 {
601 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
602 auth);
603 }
604 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
605 }
606 return cfg;
607}
608
609/**
610 * build a mem_pool_t from an address range
611 */
612static mem_pool_t *create_pool_range(char *str)
613{
614 mem_pool_t *pool;
615 host_t *from, *to;
616
617 if (!host_create_from_range(str, &from, &to))
618 {
619 return NULL;
620 }
621 pool = mem_pool_create_range(str, from, to);
622 from->destroy(from);
623 to->destroy(to);
624 return pool;
625}
626
627/**
628 * build a peer_cfg from a stroke msg
629 */
630static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
631 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
632{
633 peer_cfg_t *peer_cfg;
634 auth_cfg_t *auth_cfg;
635 peer_cfg_create_t peer = {
636 .cert_policy = msg->add_conn.me.sendcert,
637 .keyingtries = msg->add_conn.rekey.tries,
638 .no_mobike = !msg->add_conn.mobike,
639 .aggressive = msg->add_conn.aggressive,
640 .push_mode = msg->add_conn.pushmode,
641 .dpd = msg->add_conn.dpd.delay,
642 .dpd_timeout = msg->add_conn.dpd.timeout,
643 };
644
645#ifdef VOWIFI_CFG
646 int handover = FALSE;
647#endif
648
649#ifdef ME
650 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
651 {
652 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
653 "at the same time, aborting");
654 return NULL;
655 }
656
657 if (msg->add_conn.ikeme.mediation)
658 {
659 peer.mediation = TRUE;
660 /* force unique connections for mediation connections */
661 msg->add_conn.unique = 1;
662 }
663 else if (msg->add_conn.ikeme.mediated_by)
664 {
665 peer.mediated_by = msg->add_conn.ikeme.mediated_by;
666 if (msg->add_conn.ikeme.peerid)
667 {
668 peer.peer_id = identification_create_from_string(
669 msg->add_conn.ikeme.peerid);
670 }
671 else if (msg->add_conn.other.id)
672 {
673 peer.peer_id = identification_create_from_string(
674 msg->add_conn.other.id);
675 }
676 }
677#endif /* ME */
678
679 peer.jitter_time = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
680 peer.over_time = msg->add_conn.rekey.margin;
681 if (msg->add_conn.rekey.reauth)
682 {
683 peer.reauth_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
684 }
685 else
686 {
687 peer.rekey_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
688 }
689 switch (msg->add_conn.unique)
690 {
691 case 1: /* yes */
692 case 2: /* replace */
693 peer.unique = UNIQUE_REPLACE;
694 break;
695 case 3: /* keep */
696 peer.unique = UNIQUE_KEEP;
697 break;
698 case 4: /* never */
699 peer.unique = UNIQUE_NEVER;
700 break;
701 default: /* no */
702 peer.unique = UNIQUE_NO;
703 break;
704 }
705 if (msg->add_conn.dpd.action == 0)
706 { /* dpdaction=none disables DPD */
707 peer.dpd = 0;
708 }
709
710 /* other.sourceip is managed in stroke_attributes. If it is set, we define
711 * the pool name as the connection name, which the attribute provider
712 * uses to serve pool addresses. */
713 peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg, &peer);
714
715 if (msg->add_conn.other.sourceip)
716 {
717 enumerator_t *enumerator;
718 char *token;
719
720 enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
721 ",", " ");
722 while (enumerator->enumerate(enumerator, &token))
723 {
724 if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
725 streq(token, "%config") || streq(token, "%cfg") ||
726 streq(token, "%config4") || streq(token, "%config6"))
727 {
728 /* empty pool, uses connection name */
729 this->attributes->add_pool(this->attributes,
730 mem_pool_create(msg->add_conn.name, NULL, 0));
731 peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
732 }
733 else if (*token == '%')
734 {
735 /* external named pool */
736 peer_cfg->add_pool(peer_cfg, token + 1);
737 }
738 else
739 {
740 /* in-memory pool, using range or CIDR notation */
741 mem_pool_t *pool;
742 host_t *base;
743 int bits;
744
745 pool = create_pool_range(token);
746 if (!pool)
747 {
748 base = host_create_from_subnet(token, &bits);
749 if (base)
750 {
751 pool = mem_pool_create(token, base, bits);
752 base->destroy(base);
753 }
754 }
755 if (pool)
756 {
757 this->attributes->add_pool(this->attributes, pool);
758 peer_cfg->add_pool(peer_cfg, token);
759 }
760 else
761 {
762 DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
763 }
764 }
765 }
766 enumerator->destroy(enumerator);
767 }
768
769 if (msg->add_conn.me.sourceip && msg->add_conn.other.sourceip)
770 {
771 DBG1(DBG_CFG, "'%s' has both left- and rightsourceip, but IKE can "
772 "negotiate one virtual IP only, ignoring local virtual IP",
773 msg->add_conn.name);
774 }
775 else if (msg->add_conn.me.sourceip)
776 {
777 enumerator_t *enumerator;
778 char *token;
779
780 enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
781 while (enumerator->enumerate(enumerator, &token))
782 {
783 host_t *vip = NULL;
784
785 if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
786 streq(token, "%config") || streq(token, "%cfg"))
787 { /* try to deduce an address family */
788 if (msg->add_conn.me.subnets)
789 { /* use the same family as in local subnet, if any */
790 if (strchr(msg->add_conn.me.subnets, '.'))
791 {
792 vip = host_create_any(AF_INET);
793 }
794 else
795 {
796 vip = host_create_any(AF_INET6);
797 }
798 }
799 else if (msg->add_conn.other.subnets)
800 { /* use the same family as in remote subnet, if any */
801 if (strchr(msg->add_conn.other.subnets, '.'))
802 {
803 vip = host_create_any(AF_INET);
804 }
805 else
806 {
807 vip = host_create_any(AF_INET6);
808 }
809 }
810 else
811 {
812 char *addr, *next, *hit;
813
814 /* guess virtual IP family based on local address. If
815 * multiple addresses are specified, we look at the first
816 * only, as with leftallowany a ::/0 is always appended. */
817 addr = ike_cfg->get_my_addr(ike_cfg);
818 next = strchr(addr, ',');
819 hit = strchr(addr, ':');
820 if (hit && (!next || hit < next))
821 {
822 vip = host_create_any(AF_INET6);
823 }
824 else
825 {
826 vip = host_create_any(AF_INET);
827 }
828 }
829 }
830 else if (streq(token, "%config4"))
831 {
832 vip = host_create_any(AF_INET);
833 }
834 else if (streq(token, "%config6"))
835 {
836 vip = host_create_any(AF_INET6);
837 }
838 else
839 {
840#ifdef VOWIFI_CFG
841 if (!handover)
842 {
843 DBG1(DBG_CFG, "Handover detected");
844 handover = TRUE;
845 }
846#endif
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
892#ifdef VOWIFI_CFG
893 DBG1(DBG_CFG, "Operator Type : %d \n", msg->add_conn.opr_type);
894 peer_cfg->set_operator(peer_cfg, msg->add_conn.opr_type);
895
896 DBG1(DBG_CFG, "Keepalive interval : %d \n", msg->add_conn.keepalive_interval);
897 peer_cfg->set_keepalive_interval(peer_cfg, msg->add_conn.keepalive_interval);
898
899 peer_cfg->set_interface(peer_cfg, msg->add_conn.interface);
900 peer_cfg->set_handover(peer_cfg, handover);
901 peer_cfg->set_use_original_ts(peer_cfg, msg->add_conn.options & OPT_USE_ORIGINAL_TS);
902 peer_cfg->set_do_rekey_on_roam(peer_cfg, msg->add_conn.options & OPT_DO_REKEY_ON_ROAM);
35cb0d27
DV
903 peer_cfg->set_retransmit_timeout(peer_cfg, msg->add_conn.retransmit.timeout);
904 peer_cfg->set_retransmit_base(peer_cfg, msg->add_conn.retransmit.base);
905 peer_cfg->set_retransmit_retries(peer_cfg, msg->add_conn.retransmit.tries);
906 peer_cfg->set_retransmit_timeout_handover(peer_cfg, msg->add_conn.retransmit_handover.timeout);
907 peer_cfg->set_retransmit_base_handover(peer_cfg, msg->add_conn.retransmit_handover.base);
908 peer_cfg->set_retransmit_retries_handover(peer_cfg, msg->add_conn.retransmit_handover.tries);
b67df8e4
SL
909#endif
910 return peer_cfg;
911}
912
913/**
914 * Parse a protoport specifier
915 */
916static bool parse_protoport(char *token, uint16_t *from_port,
917 uint16_t *to_port, uint8_t *protocol)
918{
919 char *sep, *port = "", *endptr;
920 struct protoent *proto;
921 struct servent *svc;
922 long int p;
923
924 sep = strrchr(token, ']');
925 if (!sep)
926 {
927 return FALSE;
928 }
929 *sep = '\0';
930
931 sep = strchr(token, '/');
932 if (sep)
933 { /* protocol/port */
934 *sep = '\0';
935 port = sep + 1;
936 }
937
938 if (streq(token, "%any"))
939 {
940 *protocol = 0;
941 }
942 else
943 {
944 proto = getprotobyname(token);
945 if (proto)
946 {
947 *protocol = proto->p_proto;
948 }
949 else
950 {
951 p = strtol(token, &endptr, 0);
952 if ((*token && *endptr) || p < 0 || p > 0xff)
953 {
954 return FALSE;
955 }
956 *protocol = (uint8_t)p;
957 }
958 }
959 if (streq(port, "%any"))
960 {
961 *from_port = 0;
962 *to_port = 0xffff;
963 }
964 else if (streq(port, "%opaque"))
965 {
966 *from_port = 0xffff;
967 *to_port = 0;
968 }
969 else if (*port)
970 {
971 svc = getservbyname(port, NULL);
972 if (svc)
973 {
974 *from_port = *to_port = ntohs(svc->s_port);
975 }
976 else
977 {
978 p = strtol(port, &endptr, 0);
979 if (p < 0 || p > 0xffff)
980 {
981 return FALSE;
982 }
983 *from_port = p;
984 if (*endptr == '-')
985 {
986 port = endptr + 1;
987 p = strtol(port, &endptr, 0);
988 if (p < 0 || p > 0xffff)
989 {
990 return FALSE;
991 }
992 }
993 *to_port = p;
994 if (*endptr)
995 {
996 return FALSE;
997 }
998 }
999 }
1000 return TRUE;
1001}
1002
1003/**
1004 * build a traffic selector from a stroke_end
1005 */
1006static void add_ts(private_stroke_config_t *this,
1007 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
1008{
1009 traffic_selector_t *ts;
1010 bool ts_added = FALSE;
1011
1012 if (end->subnets)
1013 {
1014 enumerator_t *enumerator;
1015 char *subnet, *pos;
1016 uint16_t from_port, to_port;
1017 uint8_t proto;
1018
1019 enumerator = enumerator_create_token(end->subnets, ",", " ");
1020 while (enumerator->enumerate(enumerator, &subnet))
1021 {
1022 from_port = end->from_port;
1023 to_port = end->to_port;
1024 proto = end->protocol;
1025
1026 pos = strchr(subnet, '[');
1027 if (pos)
1028 {
1029 *(pos++) = '\0';
1030 if (!parse_protoport(pos, &from_port, &to_port, &proto))
1031 {
1032 DBG1(DBG_CFG, "invalid proto/port: %s, skipped subnet",
1033 pos);
1034 continue;
1035 }
1036 }
1037 if (streq(subnet, "%dynamic"))
1038 {
1039 ts = traffic_selector_create_dynamic(proto,
1040 from_port, to_port);
1041 }
1042 else
1043 {
1044 ts = traffic_selector_create_from_cidr(subnet, proto,
1045 from_port, to_port);
1046 }
1047 if (ts)
1048 {
1049 child_cfg->add_traffic_selector(child_cfg, local, ts);
1050 ts_added = TRUE;
1051 }
1052 else
1053 {
1054 DBG1(DBG_CFG, "invalid subnet: %s, skipped", subnet);
1055 }
1056 }
1057 enumerator->destroy(enumerator);
1058 }
1059 if (!ts_added)
1060 {
1061 ts = traffic_selector_create_dynamic(end->protocol,
1062 end->from_port, end->to_port);
1063 child_cfg->add_traffic_selector(child_cfg, local, ts);
1064 }
1065}
1066
1067/**
1068 * map starter magic values to our action type
1069 */
1070static action_t map_action(int starter_action)
1071{
1072 switch (starter_action)
1073 {
1074 case 2: /* =hold */
1075 return ACTION_ROUTE;
1076 case 3: /* =restart */
1077 return ACTION_RESTART;
1078 default:
1079 return ACTION_NONE;
1080 }
1081}
1082
1083/**
1084 * build a child config from the stroke message
1085 */
1086static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
1087 stroke_msg_t *msg)
1088{
1089 child_cfg_t *child_cfg;
1090 bool success;
1091 child_cfg_create_t child = {
1092 .lifetime = {
1093 .time = {
1094 .life = msg->add_conn.rekey.ipsec_lifetime,
1095 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
1096 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
1097 },
1098 .bytes = {
1099 .life = msg->add_conn.rekey.life_bytes,
1100 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
1101 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
1102 },
1103 .packets = {
1104 .life = msg->add_conn.rekey.life_packets,
1105 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
1106 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
1107 },
1108 },
1109 .mark_in = {
1110 .value = msg->add_conn.mark_in.value,
1111 .mask = msg->add_conn.mark_in.mask
1112 },
1113 .mark_out = {
1114 .value = msg->add_conn.mark_out.value,
1115 .mask = msg->add_conn.mark_out.mask
1116 },
1117 .reqid = msg->add_conn.reqid,
1118 .mode = msg->add_conn.mode,
1119 .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) |
1120 (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) |
1121 (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) |
1122 (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) |
1123 (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0),
1124 .tfc = msg->add_conn.tfc,
1125 .inactivity = msg->add_conn.inactivity,
1126 .dpd_action = map_action(msg->add_conn.dpd.action),
1127 .close_action = map_action(msg->add_conn.close_action),
1128 .updown = msg->add_conn.me.updown,
1129 };
1130
1131 child_cfg = child_cfg_create(msg->add_conn.name, &child);
1132 if (msg->add_conn.replay_window != -1)
1133 {
1134 child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window);
1135 }
1136 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
1137 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
1138
1139 if (msg->add_conn.algorithms.ah)
1140 {
1141 success = add_proposals(this, msg->add_conn.algorithms.ah,
1142 NULL, child_cfg, PROTO_AH);
1143 }
1144 else
1145 {
1146 success = add_proposals(this, msg->add_conn.algorithms.esp,
1147 NULL, child_cfg, PROTO_ESP);
1148 }
1149 if (!success)
1150 {
1151 child_cfg->destroy(child_cfg);
1152 return NULL;
1153 }
1154 return child_cfg;
1155}
1156
1157METHOD(stroke_config_t, add, void,
1158 private_stroke_config_t *this, stroke_msg_t *msg)
1159{
1160 ike_cfg_t *ike_cfg, *existing_ike;
1161 peer_cfg_t *peer_cfg, *existing;
1162 child_cfg_t *child_cfg;
1163 enumerator_t *enumerator;
1164 bool use_existing = FALSE;
1165
1166 ike_cfg = build_ike_cfg(this, msg);
1167 if (!ike_cfg)
1168 {
1169 return;
1170 }
1171 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
1172 if (!peer_cfg)
1173 {
1174 ike_cfg->destroy(ike_cfg);
1175 return;
1176 }
1177
1178 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
1179 while (enumerator->enumerate(enumerator, &existing))
1180 {
1181 existing_ike = existing->get_ike_cfg(existing);
1182 if (existing->equals(existing, peer_cfg) &&
1183 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
1184 {
1185 use_existing = TRUE;
1186 peer_cfg->destroy(peer_cfg);
1187 peer_cfg = existing;
1188 peer_cfg->get_ref(peer_cfg);
1189 DBG1(DBG_CFG, "added child to existing configuration '%s'",
1190 peer_cfg->get_name(peer_cfg));
1191 break;
1192 }
1193 }
1194 enumerator->destroy(enumerator);
1195
1196 child_cfg = build_child_cfg(this, msg);
1197 if (!child_cfg)
1198 {
1199 peer_cfg->destroy(peer_cfg);
1200 return;
1201 }
1202 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
1203
1204 if (use_existing)
1205 {
1206 peer_cfg->destroy(peer_cfg);
1207 }
1208 else
1209 {
1210 /* add config to backend */
1211 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
1212 this->mutex->lock(this->mutex);
1213 this->list->insert_last(this->list, peer_cfg);
1214 this->mutex->unlock(this->mutex);
1215 }
1216}
1217
1218METHOD(stroke_config_t, del, void,
1219 private_stroke_config_t *this, stroke_msg_t *msg)
1220{
1221 enumerator_t *enumerator, *children;
1222 peer_cfg_t *peer;
1223 child_cfg_t *child;
1224 bool deleted = FALSE;
1225
1226 this->mutex->lock(this->mutex);
1227 enumerator = this->list->create_enumerator(this->list);
1228 while (enumerator->enumerate(enumerator, &peer))
1229 {
1230 bool keep = FALSE;
1231
1232 /* remove any child with such a name */
1233 children = peer->create_child_cfg_enumerator(peer);
1234 while (children->enumerate(children, &child))
1235 {
1236 if (streq(child->get_name(child), msg->del_conn.name))
1237 {
1238 peer->remove_child_cfg(peer, children);
1239 child->destroy(child);
1240 deleted = TRUE;
1241 }
1242 else
1243 {
1244 keep = TRUE;
1245 }
1246 }
1247 children->destroy(children);
1248
1249 /* if peer config has no children anymore, remove it */
1250 if (!keep)
1251 {
1252 this->list->remove_at(this->list, enumerator);
1253 peer->destroy(peer);
1254 }
1255 }
1256 enumerator->destroy(enumerator);
1257 this->mutex->unlock(this->mutex);
1258
1259 if (deleted)
1260 {
1261 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
1262 }
1263 else
1264 {
1265 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
1266 }
1267}
1268
1269METHOD(stroke_config_t, set_user_credentials, void,
1270 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
1271{
1272 enumerator_t *enumerator, *children, *remote_auth;
1273 peer_cfg_t *peer, *found = NULL;
1274 auth_cfg_t *auth_cfg, *remote_cfg;
1275 auth_class_t auth_class;
1276 child_cfg_t *child;
1277 identification_t *id, *identity, *gw = NULL;
1278 shared_key_type_t type = SHARED_ANY;
1279 chunk_t password = chunk_empty;
1280
1281 this->mutex->lock(this->mutex);
1282 enumerator = this->list->create_enumerator(this->list);
1283 while (enumerator->enumerate(enumerator, (void**)&peer))
1284 { /* find the peer (or child) config with the given name */
1285 if (streq(peer->get_name(peer), msg->user_creds.name))
1286 {
1287 found = peer;
1288 }
1289 else
1290 {
1291 children = peer->create_child_cfg_enumerator(peer);
1292 while (children->enumerate(children, &child))
1293 {
1294 if (streq(child->get_name(child), msg->user_creds.name))
1295 {
1296 found = peer;
1297 break;
1298 }
1299 }
1300 children->destroy(children);
1301 }
1302
1303 if (found)
1304 {
1305 break;
1306 }
1307 }
1308 enumerator->destroy(enumerator);
1309
1310 if (!found)
1311 {
1312 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
1313 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
1314 this->mutex->unlock(this->mutex);
1315 return;
1316 }
1317
1318 id = identification_create_from_string(msg->user_creds.username);
1319 if (strlen(msg->user_creds.username) == 0 ||
1320 !id || id->get_type(id) == ID_ANY)
1321 {
1322 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1323 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1324 this->mutex->unlock(this->mutex);
1325 DESTROY_IF(id);
1326 return;
1327 }
1328
1329 /* replace/set the username in the first EAP/XAuth auth_cfg, also look for
1330 * a suitable remote ID.
1331 * note that adding the identity here is not fully thread-safe as the
1332 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1333 * case (setting user credentials before upping the connection) this will
1334 * not be a problem, though. */
1335 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1336 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1337 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1338 {
1339 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1340 { /* fall back on rightid, in case aaa_identity is not specified */
1341 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1342 if (identity && identity->get_type(identity) != ID_ANY)
1343 {
1344 gw = identity;
1345 }
1346 }
1347
1348 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1349 if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH)
1350 {
1351 if (auth_class == AUTH_CLASS_EAP)
1352 {
1353 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1354 /* if aaa_identity is specified use that as remote ID */
1355 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1356 if (identity && identity->get_type(identity) != ID_ANY)
1357 {
1358 gw = identity;
1359 }
1360 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1361 }
1362 else
1363 {
1364 auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY,
1365 id->clone(id));
1366 DBG1(DBG_CFG, " configured XAuth username %Y", id);
1367 }
1368 type = SHARED_EAP;
1369 break;
1370 }
1371 }
1372 enumerator->destroy(enumerator);
1373 remote_auth->destroy(remote_auth);
1374 /* clone the gw ID before unlocking the mutex */
1375 if (gw)
1376 {
1377 gw = gw->clone(gw);
1378 }
1379 this->mutex->unlock(this->mutex);
1380
1381 if (type == SHARED_ANY)
1382 {
1383 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1384 msg->user_creds.name);
1385 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1386 msg->user_creds.name);
1387 id->destroy(id);
1388 DESTROY_IF(gw);
1389 return;
1390 }
1391
1392 if (msg->user_creds.password)
1393 {
1394 char *pass;
1395
1396 pass = msg->user_creds.password;
1397 password = chunk_clone(chunk_create(pass, strlen(pass)));
1398 memwipe(pass, strlen(pass));
1399 }
1400 else
1401 { /* prompt the user for the password */
1402 char buf[256];
1403
1404 fprintf(prompt, "Password:\n");
1405 if (fgets(buf, sizeof(buf), prompt))
1406 {
1407 password = chunk_clone(chunk_create(buf, strlen(buf)));
1408 if (password.len > 0)
1409 { /* trim trailing \n */
1410 password.len--;
1411 }
1412 memwipe(buf, sizeof(buf));
1413 }
1414 }
1415
1416 if (password.len)
1417 {
1418 shared_key_t *shared;
1419 linked_list_t *owners;
1420
1421 shared = shared_key_create(type, password);
1422
1423 owners = linked_list_create();
1424 owners->insert_last(owners, id->clone(id));
1425 if (gw && gw->get_type(gw) != ID_ANY)
1426 {
1427 owners->insert_last(owners, gw->clone(gw));
1428 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1429 type, id, gw);
1430 }
1431 else
1432 {
1433 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1434 type, id);
1435 }
1436 this->cred->add_shared(this->cred, shared, owners);
1437 DBG4(DBG_CFG, " secret: %#B", &password);
1438 }
1439 else
1440 { /* in case a user answers the password prompt by just pressing enter */
1441 chunk_clear(&password);
1442 }
1443 id->destroy(id);
1444 DESTROY_IF(gw);
1445}
1446
1447METHOD(stroke_config_t, destroy, void,
1448 private_stroke_config_t *this)
1449{
1450 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1451 this->mutex->destroy(this->mutex);
1452 free(this);
1453}
1454
1455/*
1456 * see header file
1457 */
1458stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
1459 stroke_attribute_t *attributes)
1460{
1461 private_stroke_config_t *this;
1462
1463 INIT(this,
1464 .public = {
1465 .backend = {
1466 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1467 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1468 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1469 },
1470 .add = _add,
1471 .del = _del,
1472 .set_user_credentials = _set_user_credentials,
1473 .destroy = _destroy,
1474 },
1475 .list = linked_list_create(),
1476 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1477 .ca = ca,
1478 .cred = cred,
1479 .attributes = attributes,
1480 );
1481
1482 return &this->public;
1483}