Return to vici_control.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / vici |
1.1 misho 1: /* 2: * Copyright (C) 2015-2017 Tobias Brunner 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * Copyright (C) 2014 Martin Willi 6: * Copyright (C) 2014 revosec AG 7: * 8: * This program is free software; you can redistribute it and/or modify it 9: * under the terms of the GNU General Public License as published by the 10: * Free Software Foundation; either version 2 of the License, or (at your 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 12: * 13: * This program is distributed in the hope that it will be useful, but 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16: * for more details. 17: */ 18: 19: #include "vici_control.h" 20: #include "vici_builder.h" 21: 22: #include <inttypes.h> 23: 24: #include <daemon.h> 25: #include <collections/array.h> 26: #include <processing/jobs/rekey_ike_sa_job.h> 27: #include <processing/jobs/rekey_child_sa_job.h> 28: #include <processing/jobs/redirect_job.h> 29: 30: typedef struct private_vici_control_t private_vici_control_t; 31: 32: /** 33: * Private data of an vici_control_t object. 34: */ 35: struct private_vici_control_t { 36: 37: /** 38: * Public vici_control_t interface. 39: */ 40: vici_control_t public; 41: 42: /** 43: * Dispatcher 44: */ 45: vici_dispatcher_t *dispatcher; 46: }; 47: 48: /** 49: * Log callback helper data 50: */ 51: typedef struct { 52: /** dispatcher to send log messages over */ 53: vici_dispatcher_t *dispatcher; 54: /** connection ID to send messages to */ 55: u_int id; 56: /** loglevel */ 57: level_t level; 58: /** prevent recursive log */ 59: u_int recursive; 60: } log_info_t; 61: 62: /** 63: * Log using vici event messages 64: */ 65: static bool log_vici(log_info_t *info, debug_t group, level_t level, 66: ike_sa_t *ike_sa, char *text) 67: { 68: if (level <= info->level) 69: { 70: if (info->recursive++ == 0) 71: { 72: vici_message_t *message; 73: vici_builder_t *builder; 74: 75: builder = vici_builder_create(); 76: builder->add_kv(builder, "group", "%N", debug_names, group); 77: builder->add_kv(builder, "level", "%d", level); 78: if (ike_sa) 79: { 80: builder->add_kv(builder, "ikesa-name", "%s", 81: ike_sa->get_name(ike_sa)); 82: builder->add_kv(builder, "ikesa-uniqueid", "%u", 83: ike_sa->get_unique_id(ike_sa)); 84: } 85: builder->add_kv(builder, "msg", "%s", text); 86: 87: message = builder->finalize(builder); 88: if (message) 89: { 90: info->dispatcher->raise_event(info->dispatcher, "control-log", 91: info->id, message); 92: } 93: } 94: info->recursive--; 95: } 96: return TRUE; 97: } 98: 99: /** 100: * Send a (error) reply message 101: */ 102: static vici_message_t* send_reply(private_vici_control_t *this, char *fmt, ...) 103: { 104: vici_builder_t *builder; 105: va_list args; 106: 107: builder = vici_builder_create(); 108: builder->add_kv(builder, "success", fmt ? "no" : "yes"); 109: if (fmt) 110: { 111: va_start(args, fmt); 112: builder->vadd_kv(builder, "errmsg", fmt, args); 113: va_end(args); 114: } 115: return builder->finalize(builder); 116: } 117: 118: /** 119: * Get the child_cfg having name from peer_cfg 120: */ 121: static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) 122: { 123: child_cfg_t *current, *found = NULL; 124: enumerator_t *enumerator; 125: 126: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); 127: while (enumerator->enumerate(enumerator, ¤t)) 128: { 129: if (streq(current->get_name(current), name)) 130: { 131: found = current; 132: found->get_ref(found); 133: break; 134: } 135: } 136: enumerator->destroy(enumerator); 137: return found; 138: } 139: 140: /** 141: * Find a peer/child config from a config name 142: */ 143: static child_cfg_t* find_child_cfg(char *name, char *pname, peer_cfg_t **out) 144: { 145: enumerator_t *enumerator; 146: peer_cfg_t *peer_cfg; 147: child_cfg_t *child_cfg = NULL; 148: 149: enumerator = charon->backends->create_peer_cfg_enumerator( 150: charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); 151: while (enumerator->enumerate(enumerator, &peer_cfg)) 152: { 153: if (pname && !streq(pname, peer_cfg->get_name(peer_cfg))) 154: { 155: continue; 156: } 157: if (!name) 158: { 159: *out = peer_cfg->get_ref(peer_cfg); 160: break; 161: } 162: child_cfg = get_child_from_peer(peer_cfg, name); 163: if (child_cfg) 164: { 165: *out = peer_cfg->get_ref(peer_cfg); 166: break; 167: } 168: } 169: enumerator->destroy(enumerator); 170: 171: return child_cfg; 172: } 173: 174: CALLBACK(initiate, vici_message_t*, 175: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 176: { 177: peer_cfg_t *peer_cfg = NULL; 178: child_cfg_t *child_cfg; 179: char *child, *ike, *type, *sa; 180: int timeout; 181: bool limits; 182: controller_cb_t log_cb = NULL; 183: log_info_t log = { 184: .dispatcher = this->dispatcher, 185: .id = id, 186: }; 187: 188: child = request->get_str(request, NULL, "child"); 189: ike = request->get_str(request, NULL, "ike"); 190: timeout = request->get_int(request, 0, "timeout"); 191: limits = request->get_bool(request, FALSE, "init-limits"); 192: log.level = request->get_int(request, 1, "loglevel"); 193: 194: if (!child && !ike) 195: { 196: return send_reply(this, "missing configuration name"); 197: } 198: if (timeout >= 0) 199: { 200: log_cb = (controller_cb_t)log_vici; 201: } 202: 203: type = child ? "CHILD_SA" : "IKE_SA"; 204: sa = child ?: ike; 205: 206: child_cfg = find_child_cfg(child, ike, &peer_cfg); 207: 208: DBG1(DBG_CFG, "vici initiate %s '%s'", type, sa); 209: if (!peer_cfg) 210: { 211: return send_reply(this, "%s config '%s' not found", type, sa); 212: } 213: switch (charon->controller->initiate(charon->controller, peer_cfg, 214: child_cfg, log_cb, &log, timeout, limits)) 215: { 216: case SUCCESS: 217: return send_reply(this, NULL); 218: case OUT_OF_RES: 219: return send_reply(this, "%s '%s' not established after %dms", type, 220: sa, timeout); 221: case INVALID_STATE: 222: return send_reply(this, "establishing %s '%s' not possible at the " 223: "moment due to limits", type, sa); 224: case FAILED: 225: default: 226: return send_reply(this, "establishing %s '%s' failed", type, sa); 227: } 228: } 229: 230: CALLBACK(terminate, vici_message_t*, 231: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 232: { 233: enumerator_t *enumerator, *isas, *csas; 234: char *child, *ike, *errmsg = NULL; 235: u_int child_id, ike_id, current, *del, done = 0; 236: bool force; 237: int timeout; 238: ike_sa_t *ike_sa; 239: child_sa_t *child_sa; 240: array_t *ids; 241: vici_builder_t *builder; 242: controller_cb_t log_cb = NULL; 243: log_info_t log = { 244: .dispatcher = this->dispatcher, 245: .id = id, 246: }; 247: 248: child = request->get_str(request, NULL, "child"); 249: ike = request->get_str(request, NULL, "ike"); 250: child_id = request->get_int(request, 0, "child-id"); 251: ike_id = request->get_int(request, 0, "ike-id"); 252: force = request->get_bool(request, FALSE, "force"); 253: timeout = request->get_int(request, 0, "timeout"); 254: log.level = request->get_int(request, 1, "loglevel"); 255: 256: if (!child && !ike && !ike_id && !child_id) 257: { 258: return send_reply(this, "missing terminate selector"); 259: } 260: 261: if (ike_id) 262: { 263: DBG1(DBG_CFG, "vici terminate IKE_SA #%d", ike_id); 264: } 265: if (child_id) 266: { 267: DBG1(DBG_CFG, "vici terminate CHILD_SA #%d", child_id); 268: } 269: if (ike) 270: { 271: DBG1(DBG_CFG, "vici terminate IKE_SA '%s'", ike); 272: } 273: if (child) 274: { 275: DBG1(DBG_CFG, "vici terminate CHILD_SA '%s'", child); 276: } 277: 278: if (timeout >= 0) 279: { 280: log_cb = (controller_cb_t)log_vici; 281: } 282: 283: ids = array_create(sizeof(u_int), 0); 284: 285: isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); 286: while (isas->enumerate(isas, &ike_sa)) 287: { 288: if (child || child_id) 289: { 290: if (ike && !streq(ike, ike_sa->get_name(ike_sa))) 291: { 292: continue; 293: } 294: if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) 295: { 296: continue; 297: } 298: csas = ike_sa->create_child_sa_enumerator(ike_sa); 299: while (csas->enumerate(csas, &child_sa)) 300: { 301: if (child && !streq(child, child_sa->get_name(child_sa))) 302: { 303: continue; 304: } 305: if (child_id && child_sa->get_unique_id(child_sa) != child_id) 306: { 307: continue; 308: } 309: current = child_sa->get_unique_id(child_sa); 310: array_insert(ids, ARRAY_TAIL, ¤t); 311: } 312: csas->destroy(csas); 313: } 314: else if (ike && streq(ike, ike_sa->get_name(ike_sa))) 315: { 316: current = ike_sa->get_unique_id(ike_sa); 317: array_insert(ids, ARRAY_TAIL, ¤t); 318: } 319: else if (ike_id && ike_id == ike_sa->get_unique_id(ike_sa)) 320: { 321: array_insert(ids, ARRAY_TAIL, &ike_id); 322: } 323: } 324: isas->destroy(isas); 325: 326: enumerator = array_create_enumerator(ids); 327: while (enumerator->enumerate(enumerator, &del)) 328: { 329: if (child || child_id) 330: { 331: if (charon->controller->terminate_child(charon->controller, *del, 332: log_cb, &log, timeout) == SUCCESS) 333: { 334: done++; 335: } 336: } 337: else 338: { 339: if (charon->controller->terminate_ike(charon->controller, *del, force, 340: log_cb, &log, timeout) == SUCCESS) 341: { 342: done++; 343: } 344: } 345: } 346: enumerator->destroy(enumerator); 347: 348: builder = vici_builder_create(); 349: if (array_count(ids) == 0) 350: { 351: errmsg = "no matching SAs to terminate found"; 352: } 353: else if (done < array_count(ids)) 354: { 355: if (array_count(ids) == 1) 356: { 357: errmsg = "terminating SA failed"; 358: } 359: else 360: { 361: errmsg = "not all matching SAs could be terminated"; 362: } 363: } 364: builder->add_kv(builder, "success", errmsg ? "no" : "yes"); 365: builder->add_kv(builder, "matches", "%u", array_count(ids)); 366: builder->add_kv(builder, "terminated", "%u", done); 367: if (errmsg) 368: { 369: builder->add_kv(builder, "errmsg", "%s", errmsg); 370: } 371: array_destroy(ids); 372: return builder->finalize(builder); 373: } 374: 375: CALLBACK(rekey, vici_message_t*, 376: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 377: { 378: enumerator_t *isas, *csas; 379: char *child, *ike, *errmsg = NULL; 380: u_int child_id, ike_id, found = 0; 381: ike_sa_t *ike_sa; 382: child_sa_t *child_sa; 383: vici_builder_t *builder; 384: bool reauth; 385: 386: child = request->get_str(request, NULL, "child"); 387: ike = request->get_str(request, NULL, "ike"); 388: child_id = request->get_int(request, 0, "child-id"); 389: ike_id = request->get_int(request, 0, "ike-id"); 390: reauth = request->get_bool(request, FALSE, "reauth"); 391: 392: if (!child && !ike && !ike_id && !child_id) 393: { 394: return send_reply(this, "missing rekey selector"); 395: } 396: 397: if (ike_id) 398: { 399: DBG1(DBG_CFG, "vici rekey IKE_SA #%d", ike_id); 400: } 401: if (child_id) 402: { 403: DBG1(DBG_CFG, "vici rekey CHILD_SA #%d", child_id); 404: } 405: if (ike) 406: { 407: DBG1(DBG_CFG, "vici rekey IKE_SA '%s'", ike); 408: } 409: if (child) 410: { 411: DBG1(DBG_CFG, "vici rekey CHILD_SA '%s'", child); 412: } 413: 414: isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); 415: while (isas->enumerate(isas, &ike_sa)) 416: { 417: if (child || child_id) 418: { 419: if (ike && !streq(ike, ike_sa->get_name(ike_sa))) 420: { 421: continue; 422: } 423: if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa)) 424: { 425: continue; 426: } 427: csas = ike_sa->create_child_sa_enumerator(ike_sa); 428: while (csas->enumerate(csas, &child_sa)) 429: { 430: if (child && !streq(child, child_sa->get_name(child_sa))) 431: { 432: continue; 433: } 434: if (child_id && child_sa->get_unique_id(child_sa) != child_id) 435: { 436: continue; 437: } 438: lib->processor->queue_job(lib->processor, 439: (job_t*)rekey_child_sa_job_create( 440: child_sa->get_protocol(child_sa), 441: child_sa->get_spi(child_sa, TRUE), 442: ike_sa->get_my_host(ike_sa))); 443: found++; 444: } 445: csas->destroy(csas); 446: } 447: else if ((ike && streq(ike, ike_sa->get_name(ike_sa))) || 448: (ike_id && ike_id == ike_sa->get_unique_id(ike_sa))) 449: { 450: lib->processor->queue_job(lib->processor, 451: (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), reauth)); 452: found++; 453: } 454: } 455: isas->destroy(isas); 456: 457: builder = vici_builder_create(); 458: if (!found) 459: { 460: errmsg = "no matching SAs to rekey found"; 461: } 462: builder->add_kv(builder, "success", errmsg ? "no" : "yes"); 463: builder->add_kv(builder, "matches", "%u", found); 464: if (errmsg) 465: { 466: builder->add_kv(builder, "errmsg", "%s", errmsg); 467: } 468: return builder->finalize(builder); 469: } 470: 471: /** 472: * Parse a peer-ip specified, which can be a subnet in CIDR notation, a range 473: * or a single IP address. 474: */ 475: static traffic_selector_t *parse_peer_ip(char *ip) 476: { 477: traffic_selector_t *ts; 478: host_t *from, *to; 479: ts_type_t type; 480: 481: if (host_create_from_range(ip, &from, &to)) 482: { 483: if (to->get_family(to) == AF_INET) 484: { 485: type = TS_IPV4_ADDR_RANGE; 486: } 487: else 488: { 489: type = TS_IPV6_ADDR_RANGE; 490: } 491: ts = traffic_selector_create_from_bytes(0, type, 492: from->get_address(from), 0, 493: to->get_address(to), 0xFFFF); 494: from->destroy(from); 495: to->destroy(to); 496: return ts; 497: } 498: return traffic_selector_create_from_cidr(ip, 0, 0, 0xFFFF); 499: } 500: 501: CALLBACK(redirect, vici_message_t*, 502: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 503: { 504: enumerator_t *sas; 505: char *ike, *peer_ip, *peer_id, *gw, *errmsg = NULL; 506: u_int ike_id, current, found = 0; 507: identification_t *gateway, *identity = NULL, *other_id; 508: traffic_selector_t *ts = NULL; 509: ike_sa_t *ike_sa; 510: vici_builder_t *builder; 511: 512: ike = request->get_str(request, NULL, "ike"); 513: ike_id = request->get_int(request, 0, "ike-id"); 514: peer_ip = request->get_str(request, NULL, "peer-ip"); 515: peer_id = request->get_str(request, NULL, "peer-id"); 516: gw = request->get_str(request, NULL, "gateway"); 517: 518: if (!gw || !(gateway = identification_create_from_string(gw))) 519: { 520: return send_reply(this, "missing target gateway"); 521: } 522: switch (gateway->get_type(gateway)) 523: { 524: case ID_IPV4_ADDR: 525: case ID_IPV6_ADDR: 526: case ID_FQDN: 527: break; 528: default: 529: return send_reply(this, "unsupported gateway identity"); 530: } 531: if (peer_ip) 532: { 533: ts = parse_peer_ip(peer_ip); 534: if (!ts) 535: { 536: return send_reply(this, "invalid peer IP selector"); 537: } 538: DBG1(DBG_CFG, "vici redirect IKE_SAs with src %R to %Y", ts, 539: gateway); 540: } 541: if (peer_id) 542: { 543: identity = identification_create_from_string(peer_id); 544: if (!identity) 545: { 546: DESTROY_IF(ts); 547: return send_reply(this, "invalid peer identity selector"); 548: } 549: DBG1(DBG_CFG, "vici redirect IKE_SAs with ID '%Y' to %Y", identity, 550: gateway); 551: } 552: if (ike_id) 553: { 554: DBG1(DBG_CFG, "vici redirect IKE_SA #%d to '%Y'", ike_id, gateway); 555: } 556: if (ike) 557: { 558: DBG1(DBG_CFG, "vici redirect IKE_SA '%s' to '%Y'", ike, gateway); 559: } 560: if (!peer_ip && !peer_id && !ike && !ike_id) 561: { 562: return send_reply(this, "missing redirect selector"); 563: } 564: 565: sas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE); 566: while (sas->enumerate(sas, &ike_sa)) 567: { 568: if (ike_sa->get_version(ike_sa) != IKEV2) 569: { 570: continue; 571: } 572: current = ike_sa->get_unique_id(ike_sa); 573: if (ike_id && ike_id != current) 574: { 575: continue; 576: } 577: if (ike && !streq(ike, ike_sa->get_name(ike_sa))) 578: { 579: continue; 580: } 581: if (ts && !ts->includes(ts, ike_sa->get_other_host(ike_sa))) 582: { 583: continue; 584: } 585: if (identity) 586: { 587: other_id = ike_sa->get_other_eap_id(ike_sa); 588: if (!other_id->matches(other_id, identity)) 589: { 590: continue; 591: } 592: } 593: lib->processor->queue_job(lib->processor, 594: (job_t*)redirect_job_create(ike_sa->get_id(ike_sa), gateway)); 595: found++; 596: } 597: sas->destroy(sas); 598: 599: builder = vici_builder_create(); 600: if (!found) 601: { 602: errmsg = "no matching SAs to redirect found"; 603: } 604: builder->add_kv(builder, "success", errmsg ? "no" : "yes"); 605: builder->add_kv(builder, "matches", "%u", found); 606: if (errmsg) 607: { 608: builder->add_kv(builder, "errmsg", "%s", errmsg); 609: } 610: gateway->destroy(gateway); 611: DESTROY_IF(identity); 612: DESTROY_IF(ts); 613: return builder->finalize(builder); 614: } 615: 616: CALLBACK(install, vici_message_t*, 617: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 618: { 619: child_cfg_t *child_cfg = NULL; 620: peer_cfg_t *peer_cfg; 621: char *child, *ike; 622: bool ok; 623: 624: child = request->get_str(request, NULL, "child"); 625: ike = request->get_str(request, NULL, "ike"); 626: if (!child) 627: { 628: return send_reply(this, "missing configuration name"); 629: } 630: 631: DBG1(DBG_CFG, "vici install '%s'", child); 632: 633: child_cfg = find_child_cfg(child, ike, &peer_cfg); 634: if (!child_cfg) 635: { 636: return send_reply(this, "configuration name not found"); 637: } 638: switch (child_cfg->get_mode(child_cfg)) 639: { 640: case MODE_PASS: 641: case MODE_DROP: 642: ok = charon->shunts->install(charon->shunts, 643: peer_cfg->get_name(peer_cfg), child_cfg); 644: break; 645: default: 646: ok = charon->traps->install(charon->traps, peer_cfg, child_cfg); 647: break; 648: } 649: peer_cfg->destroy(peer_cfg); 650: child_cfg->destroy(child_cfg); 651: 652: return send_reply(this, ok ? NULL : "installing policy '%s' failed", child); 653: } 654: 655: CALLBACK(uninstall, vici_message_t*, 656: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 657: { 658: char *child, *ike; 659: 660: child = request->get_str(request, NULL, "child"); 661: ike = request->get_str(request, NULL, "ike"); 662: if (!child) 663: { 664: return send_reply(this, "missing configuration name"); 665: } 666: 667: DBG1(DBG_CFG, "vici uninstall '%s'", child); 668: 669: if (charon->shunts->uninstall(charon->shunts, ike, child)) 670: { 671: return send_reply(this, NULL); 672: } 673: else if (charon->traps->uninstall(charon->traps, ike, child)) 674: { 675: return send_reply(this, NULL); 676: } 677: return send_reply(this, "policy '%s' not found", child); 678: } 679: 680: CALLBACK(reload_settings, vici_message_t*, 681: private_vici_control_t *this, char *name, u_int id, vici_message_t *request) 682: { 683: if (lib->settings->load_files(lib->settings, lib->conf, FALSE)) 684: { 685: charon->load_loggers(charon); 686: lib->plugins->reload(lib->plugins, NULL); 687: return send_reply(this, NULL); 688: } 689: return send_reply(this, "reloading '%s' failed", lib->conf); 690: } 691: 692: static void manage_command(private_vici_control_t *this, 693: char *name, vici_command_cb_t cb, bool reg) 694: { 695: this->dispatcher->manage_command(this->dispatcher, name, 696: reg ? cb : NULL, this); 697: } 698: 699: /** 700: * (Un-)register dispatcher functions 701: */ 702: static void manage_commands(private_vici_control_t *this, bool reg) 703: { 704: manage_command(this, "initiate", initiate, reg); 705: manage_command(this, "terminate", terminate, reg); 706: manage_command(this, "rekey", rekey, reg); 707: manage_command(this, "redirect", redirect, reg); 708: manage_command(this, "install", install, reg); 709: manage_command(this, "uninstall", uninstall, reg); 710: manage_command(this, "reload-settings", reload_settings, reg); 711: this->dispatcher->manage_event(this->dispatcher, "control-log", reg); 712: } 713: 714: METHOD(vici_control_t, destroy, void, 715: private_vici_control_t *this) 716: { 717: manage_commands(this, FALSE); 718: free(this); 719: } 720: 721: /** 722: * See header 723: */ 724: vici_control_t *vici_control_create(vici_dispatcher_t *dispatcher) 725: { 726: private_vici_control_t *this; 727: 728: INIT(this, 729: .public = { 730: .destroy = _destroy, 731: }, 732: .dispatcher = dispatcher, 733: ); 734: 735: manage_commands(this, TRUE); 736: 737: return &this->public; 738: }