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