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