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