Merge branch 'childless'
[strongswan.git] / src / libcharon / plugins / stroke / stroke_config.c
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
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 CALLBACK(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
87 METHOD(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
96 METHOD(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 */
139 static 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 */
197 static 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 */
235 static 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 */
261 static 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 */
310 static 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 */
334 static 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 if (local)
429 {
430 this->ca->check_for_hash_and_url(this->ca, certificate);
431 }
432 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
433 if (!first)
434 {
435 first = certificate;
436 }
437 if (identity->get_type(identity) != ID_ANY &&
438 certificate->has_subject(certificate, identity))
439 {
440 has_subject = TRUE;
441 }
442 }
443 }
444 enumerator->destroy(enumerator);
445
446 if (first && !has_subject)
447 {
448 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
449 "defaulting to '%Y'", identity, first->get_subject(first));
450 identity->destroy(identity);
451 identity = first->get_subject(first);
452 identity = identity->clone(identity);
453 }
454 }
455 /* add raw RSA public key */
456 pubkey = end->rsakey;
457 if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
458 {
459 certificate = this->cred->load_pubkey(this->cred, pubkey, identity);
460 if (certificate)
461 {
462 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
463 }
464 }
465 if (identity->get_type(identity) != ID_ANY)
466 {
467 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
468 if (loose)
469 {
470 cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE);
471 }
472 }
473 else
474 {
475 identity->destroy(identity);
476 }
477
478 /* CA constraint */
479 if (ca)
480 {
481 identity = identification_create_from_string(ca);
482 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
483 KEY_ANY, identity, TRUE);
484 identity->destroy(identity);
485 if (certificate)
486 {
487 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
488 }
489 else
490 {
491 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
492 "constraint", ca);
493 }
494 }
495
496 /* groups */
497 groups = primary ? end->groups : end->groups2;
498 if (groups)
499 {
500 enumerator_t *enumerator;
501 char *group;
502
503 enumerator = enumerator_create_token(groups, ",", " ");
504 while (enumerator->enumerate(enumerator, &group))
505 {
506 cfg->add(cfg, AUTH_RULE_GROUP,
507 identification_create_from_string(group));
508 }
509 enumerator->destroy(enumerator);
510 }
511
512 /* certificatePolicies */
513 if (end->cert_policy)
514 {
515 enumerator_t *enumerator;
516 char *policy;
517
518 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
519 while (enumerator->enumerate(enumerator, &policy))
520 {
521 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
522 }
523 enumerator->destroy(enumerator);
524 }
525
526 /* authentication method (class, actually) */
527 if (strpfx(auth, "ike:") ||
528 strpfx(auth, "pubkey") ||
529 strpfx(auth, "rsa") ||
530 strpfx(auth, "ecdsa") ||
531 strpfx(auth, "bliss"))
532 {
533 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
534 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
535 cfg->add_pubkey_constraints(cfg, auth, TRUE);
536 }
537 else if (streq(auth, "psk") || streq(auth, "secret"))
538 {
539 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
540 }
541 else if (strpfx(auth, "xauth"))
542 {
543 char *pos;
544
545 pos = strchr(auth, '-');
546 if (pos)
547 {
548 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
549 }
550 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
551 if (msg->add_conn.xauth_identity)
552 {
553 cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
554 identification_create_from_string(msg->add_conn.xauth_identity));
555 }
556 }
557 else if (strpfx(auth, "eap"))
558 {
559 eap_vendor_type_t *type;
560 char *pos;
561
562 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
563 /* check for public key constraints for EAP-TLS etc. */
564 pos = strchr(auth, ':');
565 if (pos)
566 {
567 *pos = 0;
568 cfg->add_pubkey_constraints(cfg, pos + 1, FALSE);
569 }
570 type = eap_vendor_type_from_string(auth);
571 if (type)
572 {
573 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
574 if (type->vendor)
575 {
576 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
577 }
578 free(type);
579 }
580
581 if (msg->add_conn.eap_identity)
582 {
583 if (streq(msg->add_conn.eap_identity, "%identity"))
584 {
585 identity = identification_create_from_encoding(ID_ANY,
586 chunk_empty);
587 }
588 else
589 {
590 identity = identification_create_from_string(
591 msg->add_conn.eap_identity);
592 }
593 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
594 }
595 if (msg->add_conn.aaa_identity)
596 {
597 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
598 identification_create_from_string(msg->add_conn.aaa_identity));
599 }
600 }
601 else
602 {
603 if (!streq(auth, "any"))
604 {
605 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
606 auth);
607 }
608 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
609 }
610 return cfg;
611 }
612
613 /**
614 * build a mem_pool_t from an address range
615 */
616 static mem_pool_t *create_pool_range(char *str)
617 {
618 mem_pool_t *pool;
619 host_t *from, *to;
620
621 if (!host_create_from_range(str, &from, &to))
622 {
623 return NULL;
624 }
625 pool = mem_pool_create_range(str, from, to);
626 from->destroy(from);
627 to->destroy(to);
628 return pool;
629 }
630
631 /**
632 * build a peer_cfg from a stroke msg
633 */
634 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
635 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
636 {
637 peer_cfg_t *peer_cfg;
638 auth_cfg_t *auth_cfg;
639 peer_cfg_create_t peer = {
640 .cert_policy = msg->add_conn.me.sendcert,
641 .keyingtries = msg->add_conn.rekey.tries,
642 .no_mobike = !msg->add_conn.mobike,
643 .aggressive = msg->add_conn.aggressive,
644 .push_mode = msg->add_conn.pushmode,
645 .dpd = msg->add_conn.dpd.delay,
646 .dpd_timeout = msg->add_conn.dpd.timeout,
647 };
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 vip = host_create_from_string(token, 0);
841 if (!vip)
842 {
843 DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
844 }
845 }
846
847 if (vip)
848 {
849 peer_cfg->add_virtual_ip(peer_cfg, vip);
850 }
851 }
852 enumerator->destroy(enumerator);
853 }
854
855 /* build leftauth= */
856 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
857 if (auth_cfg)
858 {
859 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
860 }
861 else
862 { /* we require at least one config on our side */
863 peer_cfg->destroy(peer_cfg);
864 return NULL;
865 }
866 /* build leftauth2= */
867 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
868 if (auth_cfg)
869 {
870 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
871 }
872 /* build rightauth= */
873 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
874 if (auth_cfg)
875 {
876 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
877 }
878 /* build rightauth2= */
879 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
880 if (auth_cfg)
881 {
882 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
883 }
884 return peer_cfg;
885 }
886
887 /**
888 * Parse a protoport specifier
889 */
890 static bool parse_protoport(char *token, uint16_t *from_port,
891 uint16_t *to_port, uint8_t *protocol)
892 {
893 char *sep, *port = "", *endptr;
894 struct protoent *proto;
895 struct servent *svc;
896 long int p;
897
898 sep = strrchr(token, ']');
899 if (!sep)
900 {
901 return FALSE;
902 }
903 *sep = '\0';
904
905 sep = strchr(token, '/');
906 if (sep)
907 { /* protocol/port */
908 *sep = '\0';
909 port = sep + 1;
910 }
911
912 if (streq(token, "%any"))
913 {
914 *protocol = 0;
915 }
916 else
917 {
918 proto = getprotobyname(token);
919 if (proto)
920 {
921 *protocol = proto->p_proto;
922 }
923 else
924 {
925 p = strtol(token, &endptr, 0);
926 if ((*token && *endptr) || p < 0 || p > 0xff)
927 {
928 return FALSE;
929 }
930 *protocol = (uint8_t)p;
931 }
932 }
933 if (streq(port, "%any"))
934 {
935 *from_port = 0;
936 *to_port = 0xffff;
937 }
938 else if (streq(port, "%opaque"))
939 {
940 *from_port = 0xffff;
941 *to_port = 0;
942 }
943 else if (*port)
944 {
945 svc = getservbyname(port, NULL);
946 if (svc)
947 {
948 *from_port = *to_port = ntohs(svc->s_port);
949 }
950 else
951 {
952 p = strtol(port, &endptr, 0);
953 if (p < 0 || p > 0xffff)
954 {
955 return FALSE;
956 }
957 *from_port = p;
958 if (*endptr == '-')
959 {
960 port = endptr + 1;
961 p = strtol(port, &endptr, 0);
962 if (p < 0 || p > 0xffff)
963 {
964 return FALSE;
965 }
966 }
967 *to_port = p;
968 if (*endptr)
969 {
970 return FALSE;
971 }
972 }
973 }
974 return TRUE;
975 }
976
977 /**
978 * build a traffic selector from a stroke_end
979 */
980 static void add_ts(private_stroke_config_t *this,
981 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
982 {
983 traffic_selector_t *ts;
984 bool ts_added = FALSE;
985
986 if (end->subnets)
987 {
988 enumerator_t *enumerator;
989 char *subnet, *pos;
990 uint16_t from_port, to_port;
991 uint8_t proto;
992
993 enumerator = enumerator_create_token(end->subnets, ",", " ");
994 while (enumerator->enumerate(enumerator, &subnet))
995 {
996 from_port = end->from_port;
997 to_port = end->to_port;
998 proto = end->protocol;
999
1000 pos = strchr(subnet, '[');
1001 if (pos)
1002 {
1003 *(pos++) = '\0';
1004 if (!parse_protoport(pos, &from_port, &to_port, &proto))
1005 {
1006 DBG1(DBG_CFG, "invalid proto/port: %s, skipped subnet",
1007 pos);
1008 continue;
1009 }
1010 }
1011 if (streq(subnet, "%dynamic"))
1012 {
1013 ts = traffic_selector_create_dynamic(proto,
1014 from_port, to_port);
1015 }
1016 else
1017 {
1018 ts = traffic_selector_create_from_cidr(subnet, proto,
1019 from_port, to_port);
1020 }
1021 if (ts)
1022 {
1023 child_cfg->add_traffic_selector(child_cfg, local, ts);
1024 ts_added = TRUE;
1025 }
1026 else
1027 {
1028 DBG1(DBG_CFG, "invalid subnet: %s, skipped", subnet);
1029 }
1030 }
1031 enumerator->destroy(enumerator);
1032 }
1033 if (!ts_added)
1034 {
1035 ts = traffic_selector_create_dynamic(end->protocol,
1036 end->from_port, end->to_port);
1037 child_cfg->add_traffic_selector(child_cfg, local, ts);
1038 }
1039 }
1040
1041 /**
1042 * map starter magic values to our action type
1043 */
1044 static action_t map_action(int starter_action)
1045 {
1046 switch (starter_action)
1047 {
1048 case 2: /* =hold */
1049 return ACTION_ROUTE;
1050 case 3: /* =restart */
1051 return ACTION_RESTART;
1052 default:
1053 return ACTION_NONE;
1054 }
1055 }
1056
1057 /**
1058 * build a child config from the stroke message
1059 */
1060 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
1061 stroke_msg_t *msg)
1062 {
1063 child_cfg_t *child_cfg;
1064 bool success;
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 .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) |
1094 (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) |
1095 (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) |
1096 (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) |
1097 (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0),
1098 .tfc = msg->add_conn.tfc,
1099 .inactivity = msg->add_conn.inactivity,
1100 .dpd_action = map_action(msg->add_conn.dpd.action),
1101 .close_action = map_action(msg->add_conn.close_action),
1102 .updown = msg->add_conn.me.updown,
1103 };
1104
1105 child_cfg = child_cfg_create(msg->add_conn.name, &child);
1106 if (msg->add_conn.replay_window != -1)
1107 {
1108 child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window);
1109 }
1110 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
1111 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
1112
1113 if (msg->add_conn.algorithms.ah)
1114 {
1115 success = add_proposals(this, msg->add_conn.algorithms.ah,
1116 NULL, child_cfg, PROTO_AH);
1117 }
1118 else
1119 {
1120 success = add_proposals(this, msg->add_conn.algorithms.esp,
1121 NULL, child_cfg, PROTO_ESP);
1122 }
1123 if (!success)
1124 {
1125 child_cfg->destroy(child_cfg);
1126 return NULL;
1127 }
1128 return child_cfg;
1129 }
1130
1131 METHOD(stroke_config_t, add, void,
1132 private_stroke_config_t *this, stroke_msg_t *msg)
1133 {
1134 ike_cfg_t *ike_cfg, *existing_ike;
1135 peer_cfg_t *peer_cfg, *existing;
1136 child_cfg_t *child_cfg;
1137 enumerator_t *enumerator;
1138 bool use_existing = FALSE;
1139
1140 ike_cfg = build_ike_cfg(this, msg);
1141 if (!ike_cfg)
1142 {
1143 return;
1144 }
1145 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
1146 if (!peer_cfg)
1147 {
1148 ike_cfg->destroy(ike_cfg);
1149 return;
1150 }
1151
1152 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
1153 while (enumerator->enumerate(enumerator, &existing))
1154 {
1155 existing_ike = existing->get_ike_cfg(existing);
1156 if (existing->equals(existing, peer_cfg) &&
1157 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
1158 {
1159 use_existing = TRUE;
1160 peer_cfg->destroy(peer_cfg);
1161 peer_cfg = existing;
1162 peer_cfg->get_ref(peer_cfg);
1163 DBG1(DBG_CFG, "added child to existing configuration '%s'",
1164 peer_cfg->get_name(peer_cfg));
1165 break;
1166 }
1167 }
1168 enumerator->destroy(enumerator);
1169
1170 child_cfg = build_child_cfg(this, msg);
1171 if (!child_cfg)
1172 {
1173 peer_cfg->destroy(peer_cfg);
1174 return;
1175 }
1176 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
1177
1178 if (use_existing)
1179 {
1180 peer_cfg->destroy(peer_cfg);
1181 }
1182 else
1183 {
1184 /* add config to backend */
1185 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
1186 this->mutex->lock(this->mutex);
1187 this->list->insert_last(this->list, peer_cfg);
1188 this->mutex->unlock(this->mutex);
1189 }
1190 }
1191
1192 METHOD(stroke_config_t, del, void,
1193 private_stroke_config_t *this, stroke_msg_t *msg)
1194 {
1195 enumerator_t *enumerator, *children;
1196 peer_cfg_t *peer;
1197 child_cfg_t *child;
1198 bool deleted = FALSE;
1199
1200 this->mutex->lock(this->mutex);
1201 enumerator = this->list->create_enumerator(this->list);
1202 while (enumerator->enumerate(enumerator, &peer))
1203 {
1204 bool keep = FALSE;
1205
1206 /* remove any child with such a name */
1207 children = peer->create_child_cfg_enumerator(peer);
1208 while (children->enumerate(children, &child))
1209 {
1210 if (streq(child->get_name(child), msg->del_conn.name))
1211 {
1212 peer->remove_child_cfg(peer, children);
1213 child->destroy(child);
1214 deleted = TRUE;
1215 }
1216 else
1217 {
1218 keep = TRUE;
1219 }
1220 }
1221 children->destroy(children);
1222
1223 /* if peer config has no children anymore, remove it */
1224 if (!keep)
1225 {
1226 this->list->remove_at(this->list, enumerator);
1227 peer->destroy(peer);
1228 }
1229 }
1230 enumerator->destroy(enumerator);
1231 this->mutex->unlock(this->mutex);
1232
1233 if (deleted)
1234 {
1235 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
1236 }
1237 else
1238 {
1239 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
1240 }
1241 }
1242
1243 METHOD(stroke_config_t, set_user_credentials, void,
1244 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
1245 {
1246 enumerator_t *enumerator, *children, *remote_auth;
1247 peer_cfg_t *peer, *found = NULL;
1248 auth_cfg_t *auth_cfg, *remote_cfg;
1249 auth_class_t auth_class;
1250 child_cfg_t *child;
1251 identification_t *id, *identity, *gw = NULL;
1252 shared_key_type_t type = SHARED_ANY;
1253 chunk_t password = chunk_empty;
1254
1255 this->mutex->lock(this->mutex);
1256 enumerator = this->list->create_enumerator(this->list);
1257 while (enumerator->enumerate(enumerator, (void**)&peer))
1258 { /* find the peer (or child) config with the given name */
1259 if (streq(peer->get_name(peer), msg->user_creds.name))
1260 {
1261 found = peer;
1262 }
1263 else
1264 {
1265 children = peer->create_child_cfg_enumerator(peer);
1266 while (children->enumerate(children, &child))
1267 {
1268 if (streq(child->get_name(child), msg->user_creds.name))
1269 {
1270 found = peer;
1271 break;
1272 }
1273 }
1274 children->destroy(children);
1275 }
1276
1277 if (found)
1278 {
1279 break;
1280 }
1281 }
1282 enumerator->destroy(enumerator);
1283
1284 if (!found)
1285 {
1286 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
1287 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
1288 this->mutex->unlock(this->mutex);
1289 return;
1290 }
1291
1292 id = identification_create_from_string(msg->user_creds.username);
1293 if (strlen(msg->user_creds.username) == 0 ||
1294 !id || id->get_type(id) == ID_ANY)
1295 {
1296 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1297 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1298 this->mutex->unlock(this->mutex);
1299 DESTROY_IF(id);
1300 return;
1301 }
1302
1303 /* replace/set the username in the first EAP/XAuth auth_cfg, also look for
1304 * a suitable remote ID.
1305 * note that adding the identity here is not fully thread-safe as the
1306 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1307 * case (setting user credentials before upping the connection) this will
1308 * not be a problem, though. */
1309 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1310 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1311 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1312 {
1313 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1314 { /* fall back on rightid, in case aaa_identity is not specified */
1315 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1316 if (identity && identity->get_type(identity) != ID_ANY)
1317 {
1318 gw = identity;
1319 }
1320 }
1321
1322 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1323 if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH)
1324 {
1325 if (auth_class == AUTH_CLASS_EAP)
1326 {
1327 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1328 /* if aaa_identity is specified use that as remote ID */
1329 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1330 if (identity && identity->get_type(identity) != ID_ANY)
1331 {
1332 gw = identity;
1333 }
1334 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1335 }
1336 else
1337 {
1338 auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY,
1339 id->clone(id));
1340 DBG1(DBG_CFG, " configured XAuth username %Y", id);
1341 }
1342 type = SHARED_EAP;
1343 break;
1344 }
1345 }
1346 enumerator->destroy(enumerator);
1347 remote_auth->destroy(remote_auth);
1348 /* clone the gw ID before unlocking the mutex */
1349 if (gw)
1350 {
1351 gw = gw->clone(gw);
1352 }
1353 this->mutex->unlock(this->mutex);
1354
1355 if (type == SHARED_ANY)
1356 {
1357 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1358 msg->user_creds.name);
1359 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1360 msg->user_creds.name);
1361 id->destroy(id);
1362 DESTROY_IF(gw);
1363 return;
1364 }
1365
1366 if (msg->user_creds.password)
1367 {
1368 char *pass;
1369
1370 pass = msg->user_creds.password;
1371 password = chunk_clone(chunk_create(pass, strlen(pass)));
1372 memwipe(pass, strlen(pass));
1373 }
1374 else
1375 { /* prompt the user for the password */
1376 char buf[256];
1377
1378 fprintf(prompt, "Password:\n");
1379 if (fgets(buf, sizeof(buf), prompt))
1380 {
1381 password = chunk_clone(chunk_create(buf, strlen(buf)));
1382 if (password.len > 0)
1383 { /* trim trailing \n */
1384 password.len--;
1385 }
1386 memwipe(buf, sizeof(buf));
1387 }
1388 }
1389
1390 if (password.len)
1391 {
1392 shared_key_t *shared;
1393 linked_list_t *owners;
1394
1395 shared = shared_key_create(type, password);
1396
1397 owners = linked_list_create();
1398 owners->insert_last(owners, id->clone(id));
1399 if (gw && gw->get_type(gw) != ID_ANY)
1400 {
1401 owners->insert_last(owners, gw->clone(gw));
1402 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1403 type, id, gw);
1404 }
1405 else
1406 {
1407 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1408 type, id);
1409 }
1410 this->cred->add_shared(this->cred, shared, owners);
1411 DBG4(DBG_CFG, " secret: %#B", &password);
1412 }
1413 else
1414 { /* in case a user answers the password prompt by just pressing enter */
1415 chunk_clear(&password);
1416 }
1417 id->destroy(id);
1418 DESTROY_IF(gw);
1419 }
1420
1421 METHOD(stroke_config_t, destroy, void,
1422 private_stroke_config_t *this)
1423 {
1424 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1425 this->mutex->destroy(this->mutex);
1426 free(this);
1427 }
1428
1429 /*
1430 * see header file
1431 */
1432 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
1433 stroke_attribute_t *attributes)
1434 {
1435 private_stroke_config_t *this;
1436
1437 INIT(this,
1438 .public = {
1439 .backend = {
1440 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1441 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1442 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1443 },
1444 .add = _add,
1445 .del = _del,
1446 .set_user_credentials = _set_user_credentials,
1447 .destroy = _destroy,
1448 },
1449 .list = linked_list_create(),
1450 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1451 .ca = ca,
1452 .cred = cred,
1453 .attributes = attributes,
1454 );
1455
1456 return &this->public;
1457 }