implemented the right|leftallowany feature
[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 * build authentication config
265 */
266 static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
267 stroke_msg_t *msg, bool local, bool primary)
268 {
269 identification_t *identity;
270 certificate_t *certificate;
271 char *auth, *id, *pubkey, *cert, *ca;
272 stroke_end_t *end, *other_end;
273 auth_cfg_t *cfg;
274
275 /* select strings */
276 if (local)
277 {
278 end = &msg->add_conn.me;
279 other_end = &msg->add_conn.other;
280 }
281 else
282 {
283 end = &msg->add_conn.other;
284 other_end = &msg->add_conn.me;
285 }
286 if (primary)
287 {
288 auth = end->auth;
289 id = end->id;
290 if (!id)
291 { /* leftid/rightid fallback to address */
292 id = end->address;
293 }
294 cert = end->cert;
295 ca = end->ca;
296 if (ca && streq(ca, "%same"))
297 {
298 ca = other_end->ca;
299 }
300 }
301 else
302 {
303 auth = end->auth2;
304 id = end->id2;
305 if (local && !id)
306 { /* leftid2 falls back to leftid */
307 id = end->id;
308 }
309 cert = end->cert2;
310 ca = end->ca2;
311 if (ca && streq(ca, "%same"))
312 {
313 ca = other_end->ca2;
314 }
315 }
316
317 if (!auth)
318 {
319 if (primary)
320 {
321 auth = "pubkey";
322 }
323 else
324 { /* no second authentication round, fine. But load certificates
325 * for other purposes (EAP-TLS) */
326 if (cert)
327 {
328 certificate = this->cred->load_peer(this->cred, cert);
329 if (certificate)
330 {
331 certificate->destroy(certificate);
332 }
333 }
334 return NULL;
335 }
336 }
337
338 cfg = auth_cfg_create();
339
340 /* add identity and peer certifcate */
341 identity = identification_create_from_string(id);
342 if (cert)
343 {
344 certificate = this->cred->load_peer(this->cred, cert);
345 if (certificate)
346 {
347 if (local)
348 {
349 this->ca->check_for_hash_and_url(this->ca, certificate);
350 }
351 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
352 if (identity->get_type(identity) == ID_ANY ||
353 !certificate->has_subject(certificate, identity))
354 {
355 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
356 "defaulting to '%Y'", identity,
357 certificate->get_subject(certificate));
358 identity->destroy(identity);
359 identity = certificate->get_subject(certificate);
360 identity = identity->clone(identity);
361 }
362 }
363 }
364 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
365
366 /* add raw RSA public key */
367 pubkey = end->rsakey;
368 if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert"))
369 {
370 certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey,
371 identity);
372 if (certificate)
373 {
374 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
375 }
376 }
377
378 /* CA constraint */
379 if (ca)
380 {
381 identity = identification_create_from_string(ca);
382 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
383 KEY_ANY, identity, TRUE);
384 identity->destroy(identity);
385 if (certificate)
386 {
387 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
388 }
389 else
390 {
391 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
392 "constraint", ca);
393 }
394 }
395
396 /* groups */
397 if (end->groups)
398 {
399 enumerator_t *enumerator;
400 char *group;
401
402 enumerator = enumerator_create_token(end->groups, ",", " ");
403 while (enumerator->enumerate(enumerator, &group))
404 {
405 cfg->add(cfg, AUTH_RULE_GROUP,
406 identification_create_from_string(group));
407 }
408 enumerator->destroy(enumerator);
409 }
410
411 /* certificatePolicies */
412 if (end->cert_policy)
413 {
414 enumerator_t *enumerator;
415 char *policy;
416
417 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
418 while (enumerator->enumerate(enumerator, &policy))
419 {
420 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
421 }
422 enumerator->destroy(enumerator);
423 }
424
425 /* authentication metod (class, actually) */
426 if (streq(auth, "pubkey") ||
427 strneq(auth, "rsa", strlen("rsa")) ||
428 strneq(auth, "ecdsa", strlen("ecdsa")))
429 {
430 u_int strength;
431
432 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
433 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
434
435 if (sscanf(auth, "rsa-%d", &strength) == 1)
436 {
437 cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
438 }
439 if (sscanf(auth, "ecdsa-%d", &strength) == 1)
440 {
441 cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
442 }
443 }
444 else if (streq(auth, "psk") || streq(auth, "secret"))
445 {
446 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
447 }
448 else if (strneq(auth, "xauth", 5))
449 {
450 char *pos;
451
452 pos = strchr(auth, '-');
453 if (pos)
454 {
455 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
456 }
457 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
458 if (msg->add_conn.xauth_identity)
459 {
460 cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY,
461 identification_create_from_string(msg->add_conn.xauth_identity));
462 }
463 }
464 else if (strneq(auth, "eap", 3))
465 {
466 enumerator_t *enumerator;
467 char *str;
468 int i = 0, type = 0, vendor;
469
470 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
471
472 /* parse EAP string, format: eap[-type[-vendor]] */
473 enumerator = enumerator_create_token(auth, "-", " ");
474 while (enumerator->enumerate(enumerator, &str))
475 {
476 switch (i)
477 {
478 case 1:
479 type = eap_type_from_string(str);
480 if (!type)
481 {
482 type = atoi(str);
483 if (!type)
484 {
485 DBG1(DBG_CFG, "unknown EAP method: %s", str);
486 break;
487 }
488 }
489 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
490 break;
491 case 2:
492 if (type)
493 {
494 vendor = atoi(str);
495 if (vendor)
496 {
497 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
498 }
499 else
500 {
501 DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
502 }
503 }
504 break;
505 default:
506 break;
507 }
508 i++;
509 }
510 enumerator->destroy(enumerator);
511
512 if (msg->add_conn.eap_identity)
513 {
514 if (streq(msg->add_conn.eap_identity, "%identity"))
515 {
516 identity = identification_create_from_encoding(ID_ANY,
517 chunk_empty);
518 }
519 else
520 {
521 identity = identification_create_from_string(
522 msg->add_conn.eap_identity);
523 }
524 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
525 }
526 if (msg->add_conn.aaa_identity)
527 {
528 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
529 identification_create_from_string(msg->add_conn.aaa_identity));
530 }
531 }
532 else
533 {
534 if (!streq(auth, "any"))
535 {
536 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
537 auth);
538 }
539 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
540 }
541 return cfg;
542 }
543
544 /**
545 * build a peer_cfg from a stroke msg
546 */
547 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
548 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
549 {
550 identification_t *peer_id = NULL;
551 peer_cfg_t *mediated_by = NULL;
552 host_t *vip = NULL;
553 unique_policy_t unique;
554 u_int32_t rekey = 0, reauth = 0, over, jitter;
555 peer_cfg_t *peer_cfg;
556 auth_cfg_t *auth_cfg;
557
558 #ifdef ME
559 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
560 {
561 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
562 "at the same time, aborting");
563 return NULL;
564 }
565
566 if (msg->add_conn.ikeme.mediation)
567 {
568 /* force unique connections for mediation connections */
569 msg->add_conn.unique = 1;
570 }
571
572 if (msg->add_conn.ikeme.mediated_by)
573 {
574 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
575 msg->add_conn.ikeme.mediated_by);
576 if (!mediated_by)
577 {
578 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
579 msg->add_conn.ikeme.mediated_by);
580 return NULL;
581 }
582 if (!mediated_by->is_mediation(mediated_by))
583 {
584 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
585 "no mediation connection, aborting",
586 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
587 mediated_by->destroy(mediated_by);
588 return NULL;
589 }
590 if (msg->add_conn.ikeme.peerid)
591 {
592 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
593 }
594 else if (msg->add_conn.other.id)
595 {
596 peer_id = identification_create_from_string(msg->add_conn.other.id);
597 }
598 }
599 #endif /* ME */
600
601 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
602 over = msg->add_conn.rekey.margin;
603 if (msg->add_conn.rekey.reauth)
604 {
605 reauth = msg->add_conn.rekey.ike_lifetime - over;
606 }
607 else
608 {
609 rekey = msg->add_conn.rekey.ike_lifetime - over;
610 }
611 if (msg->add_conn.me.sourceip_mask)
612 {
613 if (msg->add_conn.me.sourceip)
614 {
615 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
616 }
617 if (!vip)
618 { /* if it is set to something like %poolname, request an address */
619 if (msg->add_conn.me.subnets)
620 { /* use the same address as in subnet, if any */
621 if (strchr(msg->add_conn.me.subnets, '.'))
622 {
623 vip = host_create_any(AF_INET);
624 }
625 else
626 {
627 vip = host_create_any(AF_INET6);
628 }
629 }
630 else
631 {
632 if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':'))
633 {
634 vip = host_create_any(AF_INET6);
635 }
636 else
637 {
638 vip = host_create_any(AF_INET);
639 }
640 }
641 }
642 }
643 switch (msg->add_conn.unique)
644 {
645 case 1: /* yes */
646 case 2: /* replace */
647 unique = UNIQUE_REPLACE;
648 break;
649 case 3: /* keep */
650 unique = UNIQUE_KEEP;
651 break;
652 default: /* no */
653 unique = UNIQUE_NO;
654 break;
655 }
656 if (msg->add_conn.dpd.action == 0)
657 { /* dpdaction=none disables DPD */
658 msg->add_conn.dpd.delay = 0;
659 }
660
661 /* other.sourceip is managed in stroke_attributes. If it is set, we define
662 * the pool name as the connection name, which the attribute provider
663 * uses to serve pool addresses. */
664 peer_cfg = peer_cfg_create(msg->add_conn.name,
665 msg->add_conn.version, ike_cfg,
666 msg->add_conn.me.sendcert, unique,
667 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
668 msg->add_conn.mobike, msg->add_conn.aggressive,
669 msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout,
670 vip, msg->add_conn.other.sourceip_mask ?
671 msg->add_conn.name : msg->add_conn.other.sourceip,
672 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
673
674 /* build leftauth= */
675 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
676 if (auth_cfg)
677 {
678 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
679 }
680 else
681 { /* we require at least one config on our side */
682 peer_cfg->destroy(peer_cfg);
683 return NULL;
684 }
685 /* build leftauth2= */
686 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
687 if (auth_cfg)
688 {
689 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
690 }
691 /* build rightauth= */
692 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
693 if (auth_cfg)
694 {
695 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
696 }
697 /* build rightauth2= */
698 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
699 if (auth_cfg)
700 {
701 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
702 }
703 return peer_cfg;
704 }
705
706 /**
707 * build a traffic selector from a stroke_end
708 */
709 static void add_ts(private_stroke_config_t *this,
710 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
711 {
712 traffic_selector_t *ts;
713
714 if (end->tohost)
715 {
716 ts = traffic_selector_create_dynamic(end->protocol,
717 end->port ? end->port : 0, end->port ? end->port : 65535);
718 child_cfg->add_traffic_selector(child_cfg, local, ts);
719 }
720 else
721 {
722 host_t *net;
723
724 if (!end->subnets)
725 {
726 net = host_create_from_string(end->address, 0);
727 if (net)
728 {
729 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
730 end->port);
731 child_cfg->add_traffic_selector(child_cfg, local, ts);
732 }
733 }
734 else
735 {
736 char *del, *start, *bits;
737
738 start = end->subnets;
739 do
740 {
741 int intbits = 0;
742
743 del = strchr(start, ',');
744 if (del)
745 {
746 *del = '\0';
747 }
748 bits = strchr(start, '/');
749 if (bits)
750 {
751 *bits = '\0';
752 intbits = atoi(bits + 1);
753 }
754
755 net = host_create_from_string(start, 0);
756 if (net)
757 {
758 ts = traffic_selector_create_from_subnet(net, intbits,
759 end->protocol, end->port);
760 child_cfg->add_traffic_selector(child_cfg, local, ts);
761 }
762 else
763 {
764 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
765 }
766 start = del + 1;
767 }
768 while (del);
769 }
770 }
771 }
772
773 /**
774 * map starter magic values to our action type
775 */
776 static action_t map_action(int starter_action)
777 {
778 switch (starter_action)
779 {
780 case 2: /* =hold */
781 return ACTION_ROUTE;
782 case 3: /* =restart */
783 return ACTION_RESTART;
784 default:
785 return ACTION_NONE;
786 }
787 }
788
789 /**
790 * build a child config from the stroke message
791 */
792 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
793 stroke_msg_t *msg)
794 {
795 child_cfg_t *child_cfg;
796 lifetime_cfg_t lifetime = {
797 .time = {
798 .life = msg->add_conn.rekey.ipsec_lifetime,
799 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
800 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
801 },
802 .bytes = {
803 .life = msg->add_conn.rekey.life_bytes,
804 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
805 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
806 },
807 .packets = {
808 .life = msg->add_conn.rekey.life_packets,
809 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
810 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
811 }
812 };
813 mark_t mark_in = {
814 .value = msg->add_conn.mark_in.value,
815 .mask = msg->add_conn.mark_in.mask
816 };
817 mark_t mark_out = {
818 .value = msg->add_conn.mark_out.value,
819 .mask = msg->add_conn.mark_out.mask
820 };
821
822 child_cfg = child_cfg_create(
823 msg->add_conn.name, &lifetime, msg->add_conn.me.updown,
824 msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE,
825 map_action(msg->add_conn.dpd.action),
826 map_action(msg->add_conn.close_action), msg->add_conn.ipcomp,
827 msg->add_conn.inactivity, msg->add_conn.reqid,
828 &mark_in, &mark_out, msg->add_conn.tfc);
829 child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
830 msg->add_conn.install_policy);
831 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
832 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
833
834 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
835
836 return child_cfg;
837 }
838
839 METHOD(stroke_config_t, add, void,
840 private_stroke_config_t *this, stroke_msg_t *msg)
841 {
842 ike_cfg_t *ike_cfg, *existing_ike;
843 peer_cfg_t *peer_cfg, *existing;
844 child_cfg_t *child_cfg;
845 enumerator_t *enumerator;
846 bool use_existing = FALSE;
847
848 ike_cfg = build_ike_cfg(this, msg);
849 if (!ike_cfg)
850 {
851 return;
852 }
853 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
854 if (!peer_cfg)
855 {
856 ike_cfg->destroy(ike_cfg);
857 return;
858 }
859
860 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
861 while (enumerator->enumerate(enumerator, &existing))
862 {
863 existing_ike = existing->get_ike_cfg(existing);
864 if (existing->equals(existing, peer_cfg) &&
865 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
866 {
867 use_existing = TRUE;
868 peer_cfg->destroy(peer_cfg);
869 peer_cfg = existing;
870 peer_cfg->get_ref(peer_cfg);
871 DBG1(DBG_CFG, "added child to existing configuration '%s'",
872 peer_cfg->get_name(peer_cfg));
873 break;
874 }
875 }
876 enumerator->destroy(enumerator);
877
878 child_cfg = build_child_cfg(this, msg);
879 if (!child_cfg)
880 {
881 peer_cfg->destroy(peer_cfg);
882 return;
883 }
884 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
885
886 if (use_existing)
887 {
888 peer_cfg->destroy(peer_cfg);
889 }
890 else
891 {
892 /* add config to backend */
893 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
894 this->mutex->lock(this->mutex);
895 this->list->insert_last(this->list, peer_cfg);
896 this->mutex->unlock(this->mutex);
897 }
898 }
899
900 METHOD(stroke_config_t, del, void,
901 private_stroke_config_t *this, stroke_msg_t *msg)
902 {
903 enumerator_t *enumerator, *children;
904 peer_cfg_t *peer;
905 child_cfg_t *child;
906 bool deleted = FALSE;
907
908 this->mutex->lock(this->mutex);
909 enumerator = this->list->create_enumerator(this->list);
910 while (enumerator->enumerate(enumerator, (void**)&peer))
911 {
912 bool keep = FALSE;
913
914 /* remove any child with such a name */
915 children = peer->create_child_cfg_enumerator(peer);
916 while (children->enumerate(children, &child))
917 {
918 if (streq(child->get_name(child), msg->del_conn.name))
919 {
920 peer->remove_child_cfg(peer, children);
921 child->destroy(child);
922 deleted = TRUE;
923 }
924 else
925 {
926 keep = TRUE;
927 }
928 }
929 children->destroy(children);
930
931 /* if peer config matches, or has no children anymore, remove it */
932 if (!keep || streq(peer->get_name(peer), msg->del_conn.name))
933 {
934 this->list->remove_at(this->list, enumerator);
935 peer->destroy(peer);
936 deleted = TRUE;
937 }
938 }
939 enumerator->destroy(enumerator);
940 this->mutex->unlock(this->mutex);
941
942 if (deleted)
943 {
944 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
945 }
946 else
947 {
948 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
949 }
950 }
951
952 METHOD(stroke_config_t, set_user_credentials, void,
953 private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt)
954 {
955 enumerator_t *enumerator, *children, *remote_auth;
956 peer_cfg_t *peer, *found = NULL;
957 auth_cfg_t *auth_cfg, *remote_cfg;
958 auth_class_t auth_class;
959 child_cfg_t *child;
960 identification_t *id, *identity, *gw = NULL;
961 shared_key_type_t type = SHARED_ANY;
962 chunk_t password = chunk_empty;
963
964 this->mutex->lock(this->mutex);
965 enumerator = this->list->create_enumerator(this->list);
966 while (enumerator->enumerate(enumerator, (void**)&peer))
967 { /* find the peer (or child) config with the given name */
968 if (streq(peer->get_name(peer), msg->user_creds.name))
969 {
970 found = peer;
971 }
972 else
973 {
974 children = peer->create_child_cfg_enumerator(peer);
975 while (children->enumerate(children, &child))
976 {
977 if (streq(child->get_name(child), msg->user_creds.name))
978 {
979 found = peer;
980 break;
981 }
982 }
983 children->destroy(children);
984 }
985
986 if (found)
987 {
988 break;
989 }
990 }
991 enumerator->destroy(enumerator);
992
993 if (!found)
994 {
995 DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name);
996 fprintf(prompt, "no config named '%s'\n", msg->user_creds.name);
997 this->mutex->unlock(this->mutex);
998 return;
999 }
1000
1001 id = identification_create_from_string(msg->user_creds.username);
1002 if (strlen(msg->user_creds.username) == 0 ||
1003 !id || id->get_type(id) == ID_ANY)
1004 {
1005 DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username);
1006 fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username);
1007 this->mutex->unlock(this->mutex);
1008 DESTROY_IF(id);
1009 return;
1010 }
1011
1012 /* replace/set the username in the first EAP auth_cfg, also look for a
1013 * suitable remote ID.
1014 * note that adding the identity here is not fully thread-safe as the
1015 * peer_cfg and in turn the auth_cfg could be in use. for the default use
1016 * case (setting user credentials before upping the connection) this will
1017 * not be a problem, though. */
1018 enumerator = found->create_auth_cfg_enumerator(found, TRUE);
1019 remote_auth = found->create_auth_cfg_enumerator(found, FALSE);
1020 while (enumerator->enumerate(enumerator, (void**)&auth_cfg))
1021 {
1022 if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg))
1023 { /* fall back on rightid, in case aaa_identity is not specified */
1024 identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY);
1025 if (identity && identity->get_type(identity) != ID_ANY)
1026 {
1027 gw = identity;
1028 }
1029 }
1030
1031 auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS);
1032 if (auth_class == AUTH_CLASS_EAP)
1033 {
1034 auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id));
1035 /* if aaa_identity is specified use that as remote ID */
1036 identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY);
1037 if (identity && identity->get_type(identity) != ID_ANY)
1038 {
1039 gw = identity;
1040 }
1041 DBG1(DBG_CFG, " configured EAP-Identity %Y", id);
1042 type = SHARED_EAP;
1043 break;
1044 }
1045 }
1046 enumerator->destroy(enumerator);
1047 remote_auth->destroy(remote_auth);
1048 /* clone the gw ID before unlocking the mutex */
1049 if (gw)
1050 {
1051 gw = gw->clone(gw);
1052 }
1053 this->mutex->unlock(this->mutex);
1054
1055 if (type == SHARED_ANY)
1056 {
1057 DBG1(DBG_CFG, " config '%s' unsuitable for user credentials",
1058 msg->user_creds.name);
1059 fprintf(prompt, "config '%s' unsuitable for user credentials\n",
1060 msg->user_creds.name);
1061 id->destroy(id);
1062 DESTROY_IF(gw);
1063 return;
1064 }
1065
1066 if (msg->user_creds.password)
1067 {
1068 char *pass;
1069
1070 pass = msg->user_creds.password;
1071 password = chunk_clone(chunk_create(pass, strlen(pass)));
1072 memwipe(pass, strlen(pass));
1073 }
1074 else
1075 { /* prompt the user for the password */
1076 char buf[256];
1077
1078 fprintf(prompt, "Password:\n");
1079 if (fgets(buf, sizeof(buf), prompt))
1080 {
1081 password = chunk_clone(chunk_create(buf, strlen(buf)));
1082 if (password.len > 0)
1083 { /* trim trailing \n */
1084 password.len--;
1085 }
1086 memwipe(buf, sizeof(buf));
1087 }
1088 }
1089
1090 if (password.len)
1091 {
1092 shared_key_t *shared;
1093 linked_list_t *owners;
1094
1095 shared = shared_key_create(type, password);
1096
1097 owners = linked_list_create();
1098 owners->insert_last(owners, id->clone(id));
1099 if (gw && gw->get_type(gw) != ID_ANY)
1100 {
1101 owners->insert_last(owners, gw->clone(gw));
1102 DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names,
1103 type, id, gw);
1104 }
1105 else
1106 {
1107 DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names,
1108 type, id);
1109 }
1110 this->cred->add_shared(this->cred, shared, owners);
1111 DBG4(DBG_CFG, " secret: %#B", &password);
1112 }
1113 else
1114 { /* in case a user answers the password prompt by just pressing enter */
1115 chunk_clear(&password);
1116 }
1117 id->destroy(id);
1118 DESTROY_IF(gw);
1119 }
1120
1121 METHOD(stroke_config_t, destroy, void,
1122 private_stroke_config_t *this)
1123 {
1124 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
1125 this->mutex->destroy(this->mutex);
1126 free(this);
1127 }
1128
1129 /*
1130 * see header file
1131 */
1132 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
1133 {
1134 private_stroke_config_t *this;
1135
1136 INIT(this,
1137 .public = {
1138 .backend = {
1139 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
1140 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
1141 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
1142 },
1143 .add = _add,
1144 .del = _del,
1145 .set_user_credentials = _set_user_credentials,
1146 .destroy = _destroy,
1147 },
1148 .list = linked_list_create(),
1149 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1150 .ca = ca,
1151 .cred = cred,
1152 );
1153
1154 return &this->public;
1155 }
1156