Annotation of embedaddon/strongswan/src/swanctl/commands/load_conns.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2014 Martin Willi
! 3: * Copyright (C) 2014 revosec AG
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE
! 17: #include <stdio.h>
! 18: #include <errno.h>
! 19: #include <limits.h>
! 20:
! 21: #include "command.h"
! 22: #include "swanctl.h"
! 23: #include "load_conns.h"
! 24:
! 25: /**
! 26: * Check if we should handle a key as a list of comma separated values
! 27: */
! 28: static bool is_list_key(char *key)
! 29: {
! 30: char *keys[] = {
! 31: "local_addrs",
! 32: "remote_addrs",
! 33: "proposals",
! 34: "esp_proposals",
! 35: "ah_proposals",
! 36: "local_ts",
! 37: "remote_ts",
! 38: "vips",
! 39: "pools",
! 40: "groups",
! 41: "cert_policy",
! 42: };
! 43: int i;
! 44:
! 45: for (i = 0; i < countof(keys); i++)
! 46: {
! 47: if (strcaseeq(keys[i], key))
! 48: {
! 49: return TRUE;
! 50: }
! 51: }
! 52: return FALSE;
! 53: }
! 54:
! 55: /**
! 56: * Check if we should handle a key as a list of comma separated files
! 57: */
! 58: static bool is_file_list_key(char *key)
! 59: {
! 60: char *keys[] = {
! 61: "certs",
! 62: "cacerts",
! 63: "pubkeys"
! 64: };
! 65: int i;
! 66:
! 67: for (i = 0; i < countof(keys); i++)
! 68: {
! 69: if (strcaseeq(keys[i], key))
! 70: {
! 71: return TRUE;
! 72: }
! 73: }
! 74: return FALSE;
! 75: }
! 76:
! 77: /**
! 78: * Add a vici list from a comma separated string value
! 79: */
! 80: static void add_list_key(vici_req_t *req, char *key, char *value)
! 81: {
! 82: enumerator_t *enumerator;
! 83: char *token;
! 84:
! 85: vici_begin_list(req, key);
! 86: enumerator = enumerator_create_token(value, ",", " ");
! 87: while (enumerator->enumerate(enumerator, &token))
! 88: {
! 89: vici_add_list_itemf(req, "%s", token);
! 90: }
! 91: enumerator->destroy(enumerator);
! 92: vici_end_list(req);
! 93: }
! 94:
! 95: /**
! 96: * Add a vici list of blobs from a comma separated file list
! 97: */
! 98: static bool add_file_list_key(vici_req_t *req, char *key, char *value)
! 99: {
! 100: enumerator_t *enumerator;
! 101: chunk_t *map, blob;
! 102: char *token, buf[PATH_MAX];
! 103: bool ret = TRUE;
! 104:
! 105: vici_begin_list(req, key);
! 106: enumerator = enumerator_create_token(value, ",", " ");
! 107: while (enumerator->enumerate(enumerator, &token))
! 108: {
! 109: if (strcasepfx(token, "0x") || strcasepfx(token, "0s"))
! 110: {
! 111: blob = chunk_from_str(token + 2);
! 112: blob = strcasepfx(token, "0x") ? chunk_from_hex(blob, NULL)
! 113: : chunk_from_base64(blob, NULL);
! 114: vici_add_list_item(req, blob.ptr, blob.len);
! 115: chunk_free(&blob);
! 116: }
! 117: else
! 118: {
! 119: if (!path_absolute(token))
! 120: {
! 121: if (streq(key, "certs"))
! 122: {
! 123: snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
! 124: DIRECTORY_SEPARATOR, SWANCTL_X509DIR,
! 125: DIRECTORY_SEPARATOR, token);
! 126: token = buf;
! 127: }
! 128: else if (streq(key, "cacerts"))
! 129: {
! 130: snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
! 131: DIRECTORY_SEPARATOR, SWANCTL_X509CADIR,
! 132: DIRECTORY_SEPARATOR, token);
! 133: token = buf;
! 134: }
! 135: else if (streq(key, "pubkeys"))
! 136: {
! 137: snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
! 138: DIRECTORY_SEPARATOR, SWANCTL_PUBKEYDIR,
! 139: DIRECTORY_SEPARATOR, token);
! 140: token = buf;
! 141: }
! 142: }
! 143: map = chunk_map(token, FALSE);
! 144: if (map)
! 145: {
! 146: vici_add_list_item(req, map->ptr, map->len);
! 147: chunk_unmap(map);
! 148: }
! 149: else
! 150: {
! 151: fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
! 152: key, token, strerror(errno));
! 153: ret = FALSE;
! 154: break;
! 155: }
! 156: }
! 157: }
! 158: enumerator->destroy(enumerator);
! 159: vici_end_list(req);
! 160:
! 161: return ret;
! 162: }
! 163:
! 164: /**
! 165: * Translate setting key/values from a section into vici key-values/lists
! 166: */
! 167: static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
! 168: {
! 169: enumerator_t *enumerator;
! 170: char *key, *value;
! 171: bool ret = TRUE;
! 172:
! 173: enumerator = cfg->create_key_value_enumerator(cfg, section);
! 174: while (enumerator->enumerate(enumerator, &key, &value))
! 175: {
! 176: if (is_list_key(key))
! 177: {
! 178: add_list_key(req, key, value);
! 179: }
! 180: else if (is_file_list_key(key))
! 181: {
! 182: ret = add_file_list_key(req, key, value);
! 183: }
! 184: else
! 185: {
! 186: vici_add_key_valuef(req, key, "%s", value);
! 187: }
! 188: if (!ret)
! 189: {
! 190: break;
! 191: }
! 192: }
! 193: enumerator->destroy(enumerator);
! 194:
! 195: return ret;
! 196: }
! 197:
! 198: /**
! 199: * Translate a settings section to a vici section
! 200: */
! 201: static bool add_sections(vici_req_t *req, settings_t *cfg, char *section)
! 202: {
! 203: enumerator_t *enumerator;
! 204: char *name, buf[256];
! 205: bool ret = TRUE;
! 206:
! 207: enumerator = cfg->create_section_enumerator(cfg, section);
! 208: while (enumerator->enumerate(enumerator, &name))
! 209: {
! 210: vici_begin_section(req, name);
! 211: snprintf(buf, sizeof(buf), "%s.%s", section, name);
! 212: ret = add_key_values(req, cfg, buf);
! 213: if (!ret)
! 214: {
! 215: break;
! 216: }
! 217: ret = add_sections(req, cfg, buf);
! 218: if (!ret)
! 219: {
! 220: break;
! 221: }
! 222: vici_end_section(req);
! 223: }
! 224: enumerator->destroy(enumerator);
! 225:
! 226: return ret;
! 227: }
! 228:
! 229: /**
! 230: * Load an IKE_SA config with CHILD_SA configs from a section
! 231: */
! 232: static bool load_conn(vici_conn_t *conn, settings_t *cfg,
! 233: char *section, command_format_options_t format)
! 234: {
! 235: vici_req_t *req;
! 236: vici_res_t *res;
! 237: bool ret = TRUE;
! 238: char buf[BUF_LEN];
! 239:
! 240: snprintf(buf, sizeof(buf), "%s.%s", "connections", section);
! 241:
! 242: req = vici_begin("load-conn");
! 243:
! 244: vici_begin_section(req, section);
! 245: if (!add_key_values(req, cfg, buf) ||
! 246: !add_sections(req, cfg, buf))
! 247: {
! 248: vici_free_req(req);
! 249: return FALSE;
! 250: }
! 251: vici_end_section(req);
! 252:
! 253: res = vici_submit(req, conn);
! 254: if (!res)
! 255: {
! 256: fprintf(stderr, "load-conn request failed: %s\n", strerror(errno));
! 257: return FALSE;
! 258: }
! 259: if (format & COMMAND_FORMAT_RAW)
! 260: {
! 261: vici_dump(res, "load-conn reply", format & COMMAND_FORMAT_PRETTY,
! 262: stdout);
! 263: }
! 264: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 265: {
! 266: fprintf(stderr, "loading connection '%s' failed: %s\n",
! 267: section, vici_find_str(res, "", "errmsg"));
! 268: ret = FALSE;
! 269: }
! 270: else
! 271: {
! 272: printf("loaded connection '%s'\n", section);
! 273: }
! 274: vici_free_res(res);
! 275: return ret;
! 276: }
! 277:
! 278: CALLBACK(list_conn, int,
! 279: linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
! 280: {
! 281: if (streq(name, "conns"))
! 282: {
! 283: char *str;
! 284:
! 285: if (asprintf(&str, "%.*s", len, value) != -1)
! 286: {
! 287: list->insert_last(list, str);
! 288: }
! 289: }
! 290: return 0;
! 291: }
! 292:
! 293: /**
! 294: * Create a list of currently loaded connections
! 295: */
! 296: static linked_list_t* list_conns(vici_conn_t *conn,
! 297: command_format_options_t format)
! 298: {
! 299: linked_list_t *list;
! 300: vici_res_t *res;
! 301:
! 302: list = linked_list_create();
! 303:
! 304: res = vici_submit(vici_begin("get-conns"), conn);
! 305: if (res)
! 306: {
! 307: if (format & COMMAND_FORMAT_RAW)
! 308: {
! 309: vici_dump(res, "get-conns reply", format & COMMAND_FORMAT_PRETTY,
! 310: stdout);
! 311: }
! 312: vici_parse_cb(res, NULL, NULL, list_conn, list);
! 313: vici_free_res(res);
! 314: }
! 315: return list;
! 316: }
! 317:
! 318: /**
! 319: * Remove and free a string from a list
! 320: */
! 321: static void remove_from_list(linked_list_t *list, char *str)
! 322: {
! 323: enumerator_t *enumerator;
! 324: char *current;
! 325:
! 326: enumerator = list->create_enumerator(list);
! 327: while (enumerator->enumerate(enumerator, ¤t))
! 328: {
! 329: if (streq(current, str))
! 330: {
! 331: list->remove_at(list, enumerator);
! 332: free(current);
! 333: }
! 334: }
! 335: enumerator->destroy(enumerator);
! 336: }
! 337:
! 338: /**
! 339: * Unload a connection by name
! 340: */
! 341: static bool unload_conn(vici_conn_t *conn, char *name,
! 342: command_format_options_t format)
! 343: {
! 344: vici_req_t *req;
! 345: vici_res_t *res;
! 346: bool ret = TRUE;
! 347:
! 348: req = vici_begin("unload-conn");
! 349: vici_add_key_valuef(req, "name", "%s", name);
! 350: res = vici_submit(req, conn);
! 351: if (!res)
! 352: {
! 353: fprintf(stderr, "unload-conn request failed: %s\n", strerror(errno));
! 354: return FALSE;
! 355: }
! 356: if (format & COMMAND_FORMAT_RAW)
! 357: {
! 358: vici_dump(res, "unload-conn reply", format & COMMAND_FORMAT_PRETTY,
! 359: stdout);
! 360: }
! 361: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 362: {
! 363: fprintf(stderr, "unloading connection '%s' failed: %s\n",
! 364: name, vici_find_str(res, "", "errmsg"));
! 365: ret = FALSE;
! 366: }
! 367: vici_free_res(res);
! 368: return ret;
! 369: }
! 370:
! 371: /**
! 372: * See header.
! 373: */
! 374: int load_conns_cfg(vici_conn_t *conn, command_format_options_t format,
! 375: settings_t *cfg)
! 376: {
! 377: u_int found = 0, loaded = 0, unloaded = 0;
! 378: char *section;
! 379: enumerator_t *enumerator;
! 380: linked_list_t *conns;
! 381:
! 382: conns = list_conns(conn, format);
! 383:
! 384: enumerator = cfg->create_section_enumerator(cfg, "connections");
! 385: while (enumerator->enumerate(enumerator, §ion))
! 386: {
! 387: remove_from_list(conns, section);
! 388: found++;
! 389: if (load_conn(conn, cfg, section, format))
! 390: {
! 391: loaded++;
! 392: }
! 393: }
! 394: enumerator->destroy(enumerator);
! 395:
! 396: /* unload all connection in daemon, but not in file */
! 397: while (conns->remove_first(conns, (void**)§ion) == SUCCESS)
! 398: {
! 399: if (unload_conn(conn, section, format))
! 400: {
! 401: unloaded++;
! 402: }
! 403: free(section);
! 404: }
! 405: conns->destroy(conns);
! 406:
! 407: if (format & COMMAND_FORMAT_RAW)
! 408: {
! 409: return 0;
! 410: }
! 411: if (found == 0)
! 412: {
! 413: fprintf(stderr, "no connections found, %u unloaded\n", unloaded);
! 414: return 0;
! 415: }
! 416: if (loaded == found)
! 417: {
! 418: printf("successfully loaded %u connections, %u unloaded\n",
! 419: loaded, unloaded);
! 420: return 0;
! 421: }
! 422: fprintf(stderr, "loaded %u of %u connections, %u failed to load, "
! 423: "%u unloaded\n", loaded, found, found - loaded, unloaded);
! 424: return EINVAL;
! 425: }
! 426:
! 427: static int load_conns(vici_conn_t *conn)
! 428: {
! 429: command_format_options_t format = COMMAND_FORMAT_NONE;
! 430: settings_t *cfg;
! 431: char *arg, *file = NULL;
! 432: int ret;
! 433:
! 434: while (TRUE)
! 435: {
! 436: switch (command_getopt(&arg))
! 437: {
! 438: case 'h':
! 439: return command_usage(NULL);
! 440: case 'P':
! 441: format |= COMMAND_FORMAT_PRETTY;
! 442: /* fall through to raw */
! 443: case 'r':
! 444: format |= COMMAND_FORMAT_RAW;
! 445: continue;
! 446: case 'f':
! 447: file = arg;
! 448: continue;
! 449: case EOF:
! 450: break;
! 451: default:
! 452: return command_usage("invalid --load-conns option");
! 453: }
! 454: break;
! 455: }
! 456:
! 457: cfg = load_swanctl_conf(file);
! 458: if (!cfg)
! 459: {
! 460: return EINVAL;
! 461: }
! 462:
! 463: ret = load_conns_cfg(conn, format, cfg);
! 464:
! 465: cfg->destroy(cfg);
! 466:
! 467: return ret;
! 468: }
! 469:
! 470: /**
! 471: * Register the command.
! 472: */
! 473: static void __attribute__ ((constructor))reg()
! 474: {
! 475: command_register((command_t) {
! 476: load_conns, 'c', "load-conns", "(re-)load connection configuration",
! 477: {"[--raw|--pretty]"},
! 478: {
! 479: {"help", 'h', 0, "show usage information"},
! 480: {"raw", 'r', 0, "dump raw response message"},
! 481: {"pretty", 'P', 0, "dump raw response message in pretty print"},
! 482: {"file", 'f', 1, "custom path to swanctl.conf"},
! 483: }
! 484: });
! 485: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>