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