8cdb5ef48412ffe0533319dac2e9e0b05e1a4148
[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_t *ike_cfg;
264 uint16_t ikeport;
265 char me[256], other[256];
266
267 swap_ends(msg);
268
269 if (msg->add_conn.me.allow_any)
270 {
271 snprintf(me, sizeof(me), "%s,0.0.0.0/0,::/0",
272 msg->add_conn.me.address);
273 }
274 if (msg->add_conn.other.allow_any)
275 {
276 snprintf(other, sizeof(other), "%s,0.0.0.0/0,::/0",
277 msg->add_conn.other.address);
278 }
279 ikeport = msg->add_conn.me.ikeport;
280 ikeport = (ikeport == IKEV2_UDP_PORT) ?
281 charon->socket->get_port(charon->socket, FALSE) : ikeport;
282 ike_cfg = ike_cfg_create(msg->add_conn.version,
283 msg->add_conn.other.sendcert != CERT_NEVER_SEND,
284 msg->add_conn.force_encap,
285 msg->add_conn.me.allow_any ?
286 me : msg->add_conn.me.address,
287 ikeport,
288 msg->add_conn.other.allow_any ?
289 other : msg->add_conn.other.address,
290 msg->add_conn.other.ikeport,
291 msg->add_conn.fragmentation,
292 msg->add_conn.ikedscp);
293
294 if (!add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg,
295 NULL, PROTO_IKE))
296 {
297 ike_cfg->destroy(ike_cfg);
298 return NULL;
299 }
300 return ike_cfg;
301 }
302
303 /**
304 * Add CRL constraint to config
305 */
306 static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
307 {
308 /* CRL/OCSP policy, for remote config only */
309 if (!local)
310 {
311 switch (policy)
312 {
313 case CRL_STRICT_YES:
314 /* if yes, we require a GOOD validation */
315 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
316 break;
317 case CRL_STRICT_IFURI:
318 /* for ifuri, a SKIPPED validation is sufficient */
319 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
320 break;
321 default:
322 break;
323 }
324 }
325 }
326
327 /**
328 * build authentication config
329 */
330 static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
331 stroke_msg_t *msg, bool local, bool primary)
332 {
333 identification_t *identity;
334 certificate_t *certificate;
335 char *auth, *id, *pubkey, *cert, *ca, *groups;
336 stroke_end_t *end, *other_end;
337 auth_cfg_t *cfg;
338 bool loose = FALSE;
339
340 /* select strings */
341 if (local)
342 {
343 end = &msg->add_conn.me;
344 other_end = &msg->add_conn.other;
345 }
346 else
347 {
348 end = &msg->add_conn.other;
349 other_end = &msg->add_conn.me;
350 }
351 if (primary)
352 {
353 auth = end->auth;
354 id = end->id;
355 if (!id)
356 { /* leftid/rightid fallback to address */
357 id = end->address;
358 }
359 cert = end->cert;
360 ca = end->ca;
361 if (ca && streq(ca, "%same"))
362 {
363 ca = other_end->ca;
364 }
365 }
366 else
367 {
368 auth = end->auth2;
369 id = end->id2;
370 if (local && !id)
371 { /* leftid2 falls back to leftid */
372 id = end->id;
373 }
374 cert = end->cert2;
375 ca = end->ca2;
376 if (ca && streq(ca, "%same"))
377 {
378 ca = other_end->ca2;
379 }
380 }
381 if (id && *id == '%' && !streq(id, "%any") && !streq(id, "%any6"))
382 { /* has only an effect on rightid/2 */
383 loose = !local;
384 id++;
385 }
386
387 if (!auth)
388 {
389 if (primary)
390 {
391 auth = "pubkey";
392 }
393 else
394 { /* no second authentication round, fine. But load certificates
395 * for other purposes (EAP-TLS) */
396 if (cert)
397 {
398 certificate = this->cred->load_peer(this->cred, cert);
399 if (certificate)
400 {
401 certificate->destroy(certificate);
402 }
403 }
404 return NULL;
405 }
406 }
407
408 cfg = auth_cfg_create();
409
410 /* add identity and peer certificate */
411 identity = identification_create_from_string(id);
412 if (cert)
413 {
414 enumerator_t *enumerator;
415 bool has_subject = FALSE;
416 certificate_t *first = NULL;
417
418 enumerator = enumerator_create_token(cert, ",", " ");
419 while (enumerator->enumerate(enumerator, &cert))
420 {
421 certificate = this->cred->load_peer(this->cred, cert);
422 if (certificate)
423 {
424 if (local)
425 {
426 this->ca->check_for_hash_and_url(this->ca, 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 */
612 static 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 */
630 static 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 ME
646 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
647 {
648 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
649 "at the same time, aborting");
650 return NULL;
651 }
652
653 if (msg->add_conn.ikeme.mediation)
654 {
655 peer.mediation = TRUE;
656 /* force unique connections for mediation connections */
657 msg->add_conn.unique = 1;
658 }
659 else if (msg->add_conn.ikeme.mediated_by)
660 {
661 peer.mediated_by = msg->add_conn.ikeme.mediated_by;
662 if (msg->add_conn.ikeme.peerid)
663 {
664 peer.peer_id = identification_create_from_string(
665 msg->add_conn.ikeme.peerid);
666 }
667 else if (msg->add_conn.other.id)
668 {
669 peer.peer_id = identification_create_from_string(
670 msg->add_conn.other.id);
671 }
672 }
673 #endif /* ME */
674
675 peer.jitter_time = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
676 peer.over_time = msg->add_conn.rekey.margin;
677 if (msg->add_conn.rekey.reauth)
678 {
679 peer.reauth_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
680 }
681 else
682 {
683 peer.rekey_time = msg->add_conn.rekey.ike_lifetime - peer.over_time;
684 }
685 switch (msg->add_conn.unique)
686 {
687 case 1: /* yes */
688 case 2: /* replace */
689 peer.unique = UNIQUE_REPLACE;
690 break;
691 case 3: /* keep */
692 peer.unique = UNIQUE_KEEP;
693 break;
694 case 4: /* never */
695 peer.unique = UNIQUE_NEVER;
696 break;
697 default: /* no */
698 peer.unique = UNIQUE_NO;
699 break;
700 }
701 if (msg->add_conn.dpd.action == 0)
702 { /* dpdaction=none disables DPD */
703 peer.dpd = 0;
704 }
705
706 /* other.sourceip is managed in stroke_attributes. If it is set, we define
707 * the pool name as the connection name, which the attribute provider
708 * uses to serve pool addresses. */
709 peer_cfg = peer_cfg_create(msg->add_conn.name, ike_cfg, &peer);
710
711 if (msg->add_conn.other.sourceip)
712 {
713 enumerator_t *enumerator;
714 char *token;
715
716 enumerator = enumerator_create_token(msg->add_conn.other.sourceip,
717 ",", " ");
718 while (enumerator->enumerate(enumerator, &token))
719 {
720 if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
721 streq(token, "%config") || streq(token, "%cfg") ||
722 streq(token, "%config4") || streq(token, "%config6"))
723 {
724 /* empty pool, uses connection name */
725 this->attributes->add_pool(this->attributes,
726 mem_pool_create(msg->add_conn.name, NULL, 0));
727 peer_cfg->add_pool(peer_cfg, msg->add_conn.name);
728 }
729 else if (*token == '%')
730 {
731 /* external named pool */
732 peer_cfg->add_pool(peer_cfg, token + 1);
733 }
734 else
735 {
736 /* in-memory pool, using range or CIDR notation */
737 mem_pool_t *pool;
738 host_t *base;
739 int bits;
740
741 pool = create_pool_range(token);
742 if (!pool)
743 {
744 base = host_create_from_subnet(token, &bits);
745 if (base)
746 {
747 pool = mem_pool_create(token, base, bits);
748 base->destroy(base);
749 }
750 }
751 if (pool)
752 {
753 this->attributes->add_pool(this->attributes, pool);
754 peer_cfg->add_pool(peer_cfg, token);
755 }
756 else
757 {
758 DBG1(DBG_CFG, "IP pool %s invalid, ignored", token);
759 }
760 }
761 }
762 enumerator->destroy(enumerator);
763 }
764
765 if (msg->add_conn.me.sourceip && msg->add_conn.other.sourceip)
766 {
767 DBG1(DBG_CFG, "'%s' has both left- and rightsourceip, but IKE can "
768 "negotiate one virtual IP only, ignoring local virtual IP",
769 msg->add_conn.name);
770 }
771 else if (msg->add_conn.me.sourceip)
772 {
773 enumerator_t *enumerator;
774 char *token;
775
776 enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " ");
777 while (enumerator->enumerate(enumerator, &token))
778 {
779 host_t *vip = NULL;
780
781 if (streq(token, "%modeconfig") || streq(token, "%modecfg") ||
782 streq(token, "%config") || streq(token, "%cfg"))
783 { /* try to deduce an address family */
784 if (msg->add_conn.me.subnets)
785 { /* use the same family as in local subnet, if any */
786 if (strchr(msg->add_conn.me.subnets, '.'))
787 {
788 vip = host_create_any(AF_INET);
789 }
790 else
791 {
792 vip = host_create_any(AF_INET6);
793 }
794 }
795 else if (msg->add_conn.other.subnets)
796 { /* use the same family as in remote subnet, if any */
797 if (strchr(msg->add_conn.other.subnets, '.'))
798 {
799 vip = host_create_any(AF_INET);
800 }
801 else
802 {
803 vip = host_create_any(AF_INET6);
804 }
805 }
806 else
807 {
808 char *addr, *next, *hit;
809
810 /* guess virtual IP family based on local address. If
811 * multiple addresses are specified, we look at the first
812 * only, as with leftallowany a ::/0 is always appended. */
813 addr = ike_cfg->get_my_addr(ike_cfg);
814 next = strchr(addr, ',');
815 hit = strchr(addr, ':');
816 if (hit && (!next || hit < next))
817 {
818 vip = host_create_any(AF_INET6);
819 }
820 else
821 {
822 vip = host_create_any(AF_INET);
823 }
824 }
825 }
826 else if (streq(token, "%config4"))
827 {
828 vip = host_create_any(AF_INET);
829 }
830 else if (streq(token, "%config6"))
831 {
832 vip = host_create_any(AF_INET6);
833 }
834 else
835 {
836 vip = host_create_from_string(token, 0);
837 if (!vip)
838 {
839 DBG1(DBG_CFG, "ignored invalid subnet token: %s", token);
840 }
841 }
842
843 if (vip)
844 {
845 peer_cfg->add_virtual_ip(peer_cfg, vip);
846 }
847 }
848 enumerator->destroy(enumerator);
849 }
850
851 /* build leftauth= */
852 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
853 if (auth_cfg)
854 {
855 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
856 }
857 else
858 { /* we require at least one config on our side */
859 peer_cfg->destroy(peer_cfg);
860 return NULL;
861 }
862 /* build leftauth2= */
863 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
864 if (auth_cfg)
865 {
866 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
867 }
868 /* build rightauth= */
869 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
870 if (auth_cfg)
871 {
872 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
873 }
874 /* build rightauth2= */
875 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
876 if (auth_cfg)
877 {
878 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
879 }
880 return peer_cfg;
881 }
882
883 /**
884 * Parse a protoport specifier
885 */
886 static bool parse_protoport(char *token, uint16_t *from_port,
887 uint16_t *to_port, uint8_t *protocol)
888 {
889 char *sep, *port = "", *endptr;
890 struct protoent *proto;
891 struct servent *svc;
892 long int p;
893
894 sep = strrchr(token, ']');
895 if (!sep)
896 {
897 return FALSE;
898 }
899 *sep = '\0';
900
901 sep = strchr(token, '/');
902 if (sep)
903 { /* protocol/port */
904 *sep = '\0';
905 port = sep + 1;
906 }
907
908 if (streq(token, "%any"))
909 {
910 *protocol = 0;
911 }
912 else
913 {
914 proto = getprotobyname(token);
915 if (proto)
916 {
917 *protocol = proto->p_proto;
918 }
919 else
920 {
921 p = strtol(token, &endptr, 0);
922 if ((*token && *endptr) || p < 0 || p > 0xff)
923 {
924 return FALSE;
925 }
926 *protocol = (uint8_t)p;
927 }
928 }
929 if (streq(port, "%any"))
930 {
931 *from_port = 0;
932 *to_port = 0xffff;
933 }
934 else if (streq(port, "%opaque"))
935 {
936 *from_port = 0xffff;
937 *to_port = 0;
938 }
939 else if (*port)
940 {
941 svc = getservbyname(port, NULL);
942 if (svc)
943 {
944 *from_port = *to_port = ntohs(svc->s_port);
945 }
946 else
947 {
948 p = strtol(port, &endptr, 0);
949 if (p < 0 || p > 0xffff)
950 {
951 return FALSE;
952 }
953 *from_port = p;
954 if (*endptr == '-')
955 {
956 port = endptr + 1;
957 p = strtol(port, &endptr, 0);
958 if (p < 0 || p > 0xffff)
959 {
960 return FALSE;
961 }
962 }
963 *to_port = p;
964 if (*endptr)
965 {
966 return FALSE;
967 }
968 }
969 }
970 return TRUE;
971 }
972
973 /**
974 * build a traffic selector from a stroke_end
975 */
976 static void add_ts(private_stroke_config_t *this,
977 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
978 {
979 traffic_selector_t *ts;
980 bool ts_added = FALSE;
981
982 if (end->subnets)
983 {
984 enumerator_t *enumerator;
985 char *subnet, *pos;
986 uint16_t from_port, to_port;
987 uint8_t proto;
988
989 enumerator = enumerator_create_token(end->subnets, ",", " ");
990 while (enumerator->enumerate(enumerator, &subnet))
991 {
992 from_port = end->from_port;
993 to_port = end->to_port;
994 proto = end->protocol;
995
996 pos = strchr(subnet, '[');
997 if (pos)
998 {
999 *(pos++) = '\0';
1000 if (!parse_protoport(pos, &from_port, &to_port, &proto))
1001 {
1002 DBG1(DBG_CFG, "invalid proto/port: %s, skipped subnet",
1003 pos);
1004 continue;
1005 }
1006 }
1007 if (streq(subnet, "%dynamic"))
1008 {
1009 ts = traffic_selector_create_dynamic(proto,
1010 from_port, to_port);
1011 }
1012 else
1013 {
1014 ts = traffic_selector_create_from_cidr(subnet, proto,
1015 from_port, to_port);
1016 }
1017 if (ts)
1018 {
1019 child_cfg->add_traffic_selector(child_cfg, local, ts);
1020 ts_added = TRUE;
1021 }
1022 else
1023 {
1024 DBG1(DBG_CFG, "invalid subnet: %s, skipped", subnet);
1025 }
1026 }
1027 enumerator->destroy(enumerator);
1028 }
1029 if (!ts_added)
1030 {
1031 ts = traffic_selector_create_dynamic(end->protocol,
1032 end->from_port, end->to_port);
1033 child_cfg->add_traffic_selector(child_cfg, local, ts);
1034 }
1035 }
1036
1037 /**
1038 * map starter magic values to our action type
1039 */
1040 static action_t map_action(int starter_action)
1041 {
1042 switch (starter_action)
1043 {
1044 case 2: /* =hold */
1045 return ACTION_ROUTE;
1046 case 3: /* =restart */
1047 return ACTION_RESTART;
1048 default:
1049 return ACTION_NONE;
1050 }
1051 }
1052
1053 /**
1054 * build a child config from the stroke message
1055 */
1056 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
1057 stroke_msg_t *msg)
1058 {
1059 child_cfg_t *child_cfg;
1060 bool success;
1061 child_cfg_create_t child = {
1062 .lifetime = {
1063 .time = {
1064 .life = msg->add_conn.rekey.ipsec_lifetime,
1065 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
1066 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
1067 },
1068 .bytes = {
1069 .life = msg->add_conn.rekey.life_bytes,
1070 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
1071 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
1072 },
1073 .packets = {
1074 .life = msg->add_conn.rekey.life_packets,
1075 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
1076 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
1077 },
1078 },
1079 .mark_in = {
1080 .value = msg->add_conn.mark_in.value,
1081 .mask = msg->add_conn.mark_in.mask
1082 },
1083 .mark_out = {
1084 .value = msg->add_conn.mark_out.value,
1085 .mask = msg->add_conn.mark_out.mask
1086 },
1087 .reqid = msg->add_conn.reqid,
1088 .mode = msg->add_conn.mode,
1089 .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) |
1090 (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) |
1091 (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) |
1092 (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES) |
1093 (msg->add_conn.sha256_96 ? OPT_SHA256_96 : 0),
1094 .tfc = msg->add_conn.tfc,
1095 .inactivity = msg->add_conn.inactivity,
1096 .dpd_action = map_action(msg->add_conn.dpd.action),
1097 .close_action = map_action(msg->add_conn.close_action),
1098 .updown = msg->add_conn.me.updown,
1099 };
1100
1101 child_cfg = child_cfg_create(msg->add_conn.name, &child);
1102 if (msg->add_conn.replay_window != -1)
1103 {
1104 child_cfg->set_replay_window(child_cfg, msg->add_conn.replay_window);
1105 }
1106 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
1107 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
1108
1109 if (msg->add_conn.algorithms.ah)
1110 {
1111 success = add_proposals(this, msg->add_conn.algorithms.ah,
1112 NULL, child_cfg, PROTO_AH);
1113 }
1114 else
1115 {
1116 success = add_proposals(this, msg->add_conn.algorithms.esp,
1117 NULL, child_cfg, PROTO_ESP);
1118 }
1119 if (!success)
1120 {
1121 child_cfg->destroy(child_cfg);
1122 return NULL;
1123 }
1124 return child_cfg;
1125 }
1126
1127 METHOD(stroke_config_t, add, void,
1128 private_stroke_config_t *this, stroke_msg_t *msg)
1129 {
1130 ike_cfg_t *ike_cfg, *existing_ike;
1131 peer_cfg_t *peer_cfg, *existing;
1132 child_cfg_t *child_cfg;
1133 enumerator_t *enumerator;
1134 bool use_existing = FALSE;
1135
1136 ike_cfg = build_ike_cfg(this, msg);
1137 if (!ike_cfg)
1138 {
1139 return;
1140 }
1141 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
1142 if (!peer_cfg)
1143 {
1144 ike_cfg->destroy(ike_cfg);
1145 return;
1146 }
1147
1148 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
1149 while (enumerator->enumerate(enumerator, &existing))
1150 {
1151 existing_ike = existing->get_ike_cfg(existing);
1152 if (existing->equals(existing, peer_cfg) &&
1153 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
1154 {
1155 use_existing = TRUE;
1156 peer_cfg->destroy(peer_cfg);
1157 peer_cfg = existing;
1158 peer_cfg->get_ref(peer_cfg);
1159 DBG1(DBG_CFG, "added child to existing configuration '%s'",
1160 peer_cfg->get_name(peer_cfg));
1161 break;
1162 }
1163 }
1164 enumerator->destroy(enumerator);
1165
1166 child_cfg = build_child_cfg(this, msg);
1167 if (!child_cfg)
1168 {
1169 peer_cfg->destroy(peer_cfg);
1170 return;
1171 }
1172 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
1173
1174 if (use_existing)
1175 {
1176 peer_cfg->destroy(peer_cfg);
1177 }
1178 else
1179 {
1180 /* add config to backend */
1181 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
1182 this->mutex->lock(this->mutex);
1183 this->list->insert_last(this->list, peer_cfg);
1184 this->mutex->unlock(this->mutex);
1185 }
1186 }
1187
1188 METHOD(stroke_config_t, del, void,
1189 private_stroke_config_t *this, stroke_msg_t *msg)
1190 {
1191 enumerator_t *enumerator, *children;
1192 peer_cfg_t *peer;
1193 child_cfg_t *child;
1194 bool deleted = FALSE;
1195
1196 this->mutex->lock(this->mutex);
1197 enumerator = this->list->create_enumerator(this->list);
1198 while (enumerator->enumerate(enumerator, &peer))
1199 {
1200 bool keep = FALSE;
1201
1202 /* remove any child with such a name */
1203 children = peer->create_child_cfg_enumerator(peer);
1204 while (children->enumerate(children, &child))
1205 {
1206 if (streq(child->get_name(child), msg->del_conn.name))
1207 {
1208 peer->remove_child_cfg(peer, children);
1209 child->destroy(child);
1210 deleted = TRUE;
1211 }
1212 else
1213 {
1214 keep = TRUE;
1215 }
1216 }
1217 children->destroy(children);
1218
1219 /* if peer config has no children anymore, remove it */
1220 if (!keep)
1221 {
1222 this->list->remove_at(this->list, enumerator);
1223 peer->destroy(peer);
1224 }
1225 }
1226 enumerator->destroy(enumerator);
1227 this->mutex->unlock(this->mutex);
1228
1229 if (deleted)
1230 {
1231 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
1232 }
1233 else
1234 {
1235 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
1236 }
1237 }
1238
1239 METHOD(stroke_config_t, set_user_credentials, void,
1240 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
1241 {
1242 enumerator_t *enumerator, *children, *remote_auth;
1243 peer_cfg_t *peer, *found = NULL;
1244 auth_cfg_t *auth_cfg, *remote_cfg;
1245 auth_class_t auth_class;
1246 child_cfg_t *child;
1247 identification_t *id, *identity, *gw = NULL;
1248 shared_key_type_t type = SHARED_ANY;
1249 chunk_t password = chunk_empty;
1250
1251 this->mutex->lock(this->mutex);
1252 enumerator = this->list->create_enumerator(this->list);
1253 while (enumerator->enumerate(enumerator, (void**)&peer))
1254 { /* find the peer (or child) config with the given name */
1255 if (streq(peer->get_name(peer), msg->user_creds.name))
1256 {
1257 found = peer;
1258 }
1259 else
1260 {
1261 children = peer->create_child_cfg_enumerator(peer);
1262 while (children->enumerate(children, &child))
1263 {
1264 if (streq(child->get_name(child), msg->user_creds.name))
1265 {
1266 found = peer;
1267 break;
1268 }
1269 }
1270 children->destroy(children);
1271 }
1272
1273 if (found)
1274 {
1275 break;
1276 }
1277 }
1278 enumerator->destroy(enumerator);
1279
1280 if (!found)
1281 {
1282 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
1283 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
1284 this->mutex->unlock(this->mutex);
1285 return;
1286 }
1287
1288 id = identification_create_from_string(msg->user_creds.username);
1289 if (strlen(msg->user_creds.username) == 0 ||
1290 !id || id->get_type(id) == ID_ANY)
1291 {
1292 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1293 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1294 this->mutex->unlock(this->mutex);
1295 DESTROY_IF(id);
1296 return;
1297 }
1298
1299 /* replace/set the username in the first EAP/XAuth auth_cfg, also look for
1300 * a suitable remote ID.
1301 * note that adding the identity here is not fully thread-safe as the
1302 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1303 * case (setting user credentials before upping the connection) this will
1304 * not be a problem, though. */
1305 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1306 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1307 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1308 {
1309 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1310 { /* fall back on rightid, in case aaa_identity is not specified */
1311 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1312 if (identity && identity->get_type(identity) != ID_ANY)
1313 {
1314 gw = identity;
1315 }
1316 }
1317
1318 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1319 if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH)
1320 {
1321 if (auth_class == AUTH_CLASS_EAP)
1322 {
1323 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1324 /* if aaa_identity is specified use that as remote ID */
1325 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1326 if (identity && identity->get_type(identity) != ID_ANY)
1327 {
1328 gw = identity;
1329 }
1330 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1331 }
1332 else
1333 {
1334 auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY,
1335 id->clone(id));
1336 DBG1(DBG_CFG, " configured XAuth username %Y", id);
1337 }
1338 type = SHARED_EAP;
1339 break;
1340 }
1341 }
1342 enumerator->destroy(enumerator);
1343 remote_auth->destroy(remote_auth);
1344 /* clone the gw ID before unlocking the mutex */
1345 if (gw)
1346 {
1347 gw = gw->clone(gw);
1348 }
1349 this->mutex->unlock(this->mutex);
1350
1351 if (type == SHARED_ANY)
1352 {
1353 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1354 msg->user_creds.name);
1355 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1356 msg->user_creds.name);
1357 id->destroy(id);
1358 DESTROY_IF(gw);
1359 return;
1360 }
1361
1362 if (msg->user_creds.password)
1363 {
1364 char *pass;
1365
1366 pass = msg->user_creds.password;
1367 password = chunk_clone(chunk_create(pass, strlen(pass)));
1368 memwipe(pass, strlen(pass));
1369 }
1370 else
1371 { /* prompt the user for the password */
1372 char buf[256];
1373
1374 fprintf(prompt, "Password:\n");
1375 if (fgets(buf, sizeof(buf), prompt))
1376 {
1377 password = chunk_clone(chunk_create(buf, strlen(buf)));
1378 if (password.len > 0)
1379 { /* trim trailing \n */
1380 password.len--;
1381 }
1382 memwipe(buf, sizeof(buf));
1383 }
1384 }
1385
1386 if (password.len)
1387 {
1388 shared_key_t *shared;
1389 linked_list_t *owners;
1390
1391 shared = shared_key_create(type, password);
1392
1393 owners = linked_list_create();
1394 owners->insert_last(owners, id->clone(id));
1395 if (gw && gw->get_type(gw) != ID_ANY)
1396 {
1397 owners->insert_last(owners, gw->clone(gw));
1398 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1399 type, id, gw);
1400 }
1401 else
1402 {
1403 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1404 type, id);
1405 }
1406 this->cred->add_shared(this->cred, shared, owners);
1407 DBG4(DBG_CFG, " secret: %#B", &password);
1408 }
1409 else
1410 { /* in case a user answers the password prompt by just pressing enter */
1411 chunk_clear(&password);
1412 }
1413 id->destroy(id);
1414 DESTROY_IF(gw);
1415 }
1416
1417 METHOD(stroke_config_t, destroy, void,
1418 private_stroke_config_t *this)
1419 {
1420 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1421 this->mutex->destroy(this->mutex);
1422 free(this);
1423 }
1424
1425 /*
1426 * see header file
1427 */
1428 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred,
1429 stroke_attribute_t *attributes)
1430 {
1431 private_stroke_config_t *this;
1432
1433 INIT(this,
1434 .public = {
1435 .backend = {
1436 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1437 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1438 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1439 },
1440 .add = _add,
1441 .del = _del,
1442 .set_user_credentials = _set_user_credentials,
1443 .destroy = _destroy,
1444 },
1445 .list = linked_list_create(),
1446 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1447 .ca = ca,
1448 .cred = cred,
1449 .attributes = attributes,
1450 );
1451
1452 return &this->public;
1453 }