Return to stroke_config.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / stroke |
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: }