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