Annotation of embedaddon/strongswan/src/swanctl/commands/load_creds.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2016-2017 Tobias Brunner
! 3: * Copyright (C) 2015 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * Copyright (C) 2014 Martin Willi
! 7: * Copyright (C) 2014 revosec AG
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify it
! 10: * under the terms of the GNU General Public License as published by the
! 11: * Free Software Foundation; either version 2 of the License, or (at your
! 12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 13: *
! 14: * This program is distributed in the hope that it will be useful, but
! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 17: * for more details.
! 18: */
! 19:
! 20: #define _GNU_SOURCE
! 21: #include <stdio.h>
! 22: #include <errno.h>
! 23: #include <unistd.h>
! 24: #include <sys/stat.h>
! 25:
! 26: #include "command.h"
! 27: #include "swanctl.h"
! 28: #include "load_creds.h"
! 29:
! 30: #include <credentials/sets/mem_cred.h>
! 31: #include <credentials/sets/callback_cred.h>
! 32: #include <credentials/containers/pkcs12.h>
! 33: #include <collections/hashtable.h>
! 34:
! 35: #include <vici_cert_info.h>
! 36:
! 37: /**
! 38: * Context used to track loaded secrets
! 39: */
! 40: typedef struct {
! 41: /** vici connection */
! 42: vici_conn_t *conn;
! 43: /** format options */
! 44: command_format_options_t format;
! 45: /** read setting */
! 46: settings_t *cfg;
! 47: /** don't prompt user for password */
! 48: bool noprompt;
! 49: /** list of key ids of loaded private keys */
! 50: hashtable_t *keys;
! 51: /** list of unique ids of loaded shared keys */
! 52: hashtable_t *shared;
! 53: } load_ctx_t;
! 54:
! 55: /**
! 56: * Load a single certificate over vici
! 57: */
! 58: static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type,
! 59: x509_flag_t flag, chunk_t data)
! 60: {
! 61: vici_req_t *req;
! 62: vici_res_t *res;
! 63: bool ret = TRUE;
! 64:
! 65: req = vici_begin("load-cert");
! 66:
! 67: vici_add_key_valuef(req, "type", "%N", certificate_type_names, type);
! 68: if (type == CERT_X509)
! 69: {
! 70: vici_add_key_valuef(req, "flag", "%N", x509_flag_names, flag);
! 71: }
! 72: vici_add_key_value(req, "data", data.ptr, data.len);
! 73:
! 74: res = vici_submit(req, ctx->conn);
! 75: if (!res)
! 76: {
! 77: fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
! 78: return FALSE;
! 79: }
! 80: if (ctx->format & COMMAND_FORMAT_RAW)
! 81: {
! 82: vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 83: stdout);
! 84: }
! 85: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 86: {
! 87: fprintf(stderr, "loading '%s' failed: %s\n",
! 88: dir, vici_find_str(res, "", "errmsg"));
! 89: ret = FALSE;
! 90: }
! 91: else
! 92: {
! 93: printf("loaded certificate from '%s'\n", dir);
! 94: }
! 95: vici_free_res(res);
! 96: return ret;
! 97: }
! 98:
! 99: /**
! 100: * Load certificates from a directory
! 101: */
! 102: static void load_certs(load_ctx_t *ctx, char *type_str, char *dir)
! 103: {
! 104: enumerator_t *enumerator;
! 105: certificate_type_t type;
! 106: x509_flag_t flag;
! 107: struct stat st;
! 108: chunk_t *map;
! 109: char *path, buf[PATH_MAX];
! 110:
! 111: vici_cert_info_from_str(type_str, &type, &flag);
! 112:
! 113: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
! 114: dir = buf;
! 115:
! 116: enumerator = enumerator_create_directory(dir);
! 117: if (enumerator)
! 118: {
! 119: while (enumerator->enumerate(enumerator, NULL, &path, &st))
! 120: {
! 121: if (S_ISREG(st.st_mode))
! 122: {
! 123: map = chunk_map(path, FALSE);
! 124: if (map)
! 125: {
! 126: load_cert(ctx, path, type, flag, *map);
! 127: chunk_unmap(map);
! 128: }
! 129: else
! 130: {
! 131: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
! 132: path, strerror(errno));
! 133: }
! 134: }
! 135: }
! 136: enumerator->destroy(enumerator);
! 137: }
! 138: }
! 139:
! 140: /**
! 141: * Load a single private key over vici
! 142: */
! 143: static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
! 144: {
! 145: vici_req_t *req;
! 146: vici_res_t *res;
! 147: bool ret = TRUE;
! 148: char *id;
! 149:
! 150: req = vici_begin("load-key");
! 151:
! 152: if (streq(type, "private") ||
! 153: streq(type, "pkcs8"))
! 154: { /* as used by vici */
! 155: vici_add_key_valuef(req, "type", "any");
! 156: }
! 157: else
! 158: {
! 159: vici_add_key_valuef(req, "type", "%s", type);
! 160: }
! 161: vici_add_key_value(req, "data", data.ptr, data.len);
! 162:
! 163: res = vici_submit(req, ctx->conn);
! 164: if (!res)
! 165: {
! 166: fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
! 167: return FALSE;
! 168: }
! 169: if (ctx->format & COMMAND_FORMAT_RAW)
! 170: {
! 171: vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 172: stdout);
! 173: }
! 174: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 175: {
! 176: fprintf(stderr, "loading '%s' failed: %s\n",
! 177: dir, vici_find_str(res, "", "errmsg"));
! 178: ret = FALSE;
! 179: }
! 180: else
! 181: {
! 182: printf("loaded %s key from '%s'\n", type, dir);
! 183: id = vici_find_str(res, "", "id");
! 184: free(ctx->keys->remove(ctx->keys, id));
! 185: }
! 186: vici_free_res(res);
! 187: return ret;
! 188: }
! 189:
! 190: /**
! 191: * Load a private key of any type to vici
! 192: */
! 193: static bool load_key_anytype(load_ctx_t *ctx, char *path,
! 194: private_key_t *private)
! 195: {
! 196: bool loaded = FALSE;
! 197: chunk_t encoding;
! 198:
! 199: if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
! 200: {
! 201: fprintf(stderr, "encoding private key from '%s' failed\n", path);
! 202: return FALSE;
! 203: }
! 204: switch (private->get_type(private))
! 205: {
! 206: case KEY_RSA:
! 207: loaded = load_key(ctx, path, "rsa", encoding);
! 208: break;
! 209: case KEY_ECDSA:
! 210: loaded = load_key(ctx, path, "ecdsa", encoding);
! 211: break;
! 212: case KEY_BLISS:
! 213: loaded = load_key(ctx, path, "bliss", encoding);
! 214: break;
! 215: default:
! 216: fprintf(stderr, "unsupported key type in '%s'\n", path);
! 217: break;
! 218: }
! 219: chunk_clear(&encoding);
! 220: return loaded;
! 221: }
! 222:
! 223: /**
! 224: * Data passed to password callback
! 225: */
! 226: typedef struct {
! 227: char prompt[128];
! 228: mem_cred_t *cache;
! 229: } cb_data_t;
! 230:
! 231: /**
! 232: * Callback function to prompt for private key passwords
! 233: */
! 234: CALLBACK(password_cb, shared_key_t*,
! 235: cb_data_t *data, shared_key_type_t type,
! 236: identification_t *me, identification_t *other,
! 237: id_match_t *match_me, id_match_t *match_other)
! 238: {
! 239: shared_key_t *shared;
! 240: char *pwd = NULL;
! 241:
! 242: if (type != SHARED_PRIVATE_KEY_PASS)
! 243: {
! 244: return NULL;
! 245: }
! 246: #ifdef HAVE_GETPASS
! 247: pwd = getpass(data->prompt);
! 248: #endif
! 249: if (!pwd || strlen(pwd) == 0)
! 250: {
! 251: return NULL;
! 252: }
! 253: if (match_me)
! 254: {
! 255: *match_me = ID_MATCH_PERFECT;
! 256: }
! 257: if (match_other)
! 258: {
! 259: *match_other = ID_MATCH_PERFECT;
! 260: }
! 261: shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
! 262: /* cache secret if it is required more than once (PKCS#12) */
! 263: data->cache->add_shared(data->cache, shared, NULL);
! 264: return shared->get_ref(shared);
! 265: }
! 266:
! 267: /**
! 268: * Determine credential type and subtype from a type string
! 269: */
! 270: static bool determine_credtype(char *type, credential_type_t *credtype,
! 271: int *subtype)
! 272: {
! 273: struct {
! 274: char *type;
! 275: credential_type_t credtype;
! 276: int subtype;
! 277: } map[] = {
! 278: { "private", CRED_PRIVATE_KEY, KEY_ANY, },
! 279: { "pkcs8", CRED_PRIVATE_KEY, KEY_ANY, },
! 280: { "rsa", CRED_PRIVATE_KEY, KEY_RSA, },
! 281: { "ecdsa", CRED_PRIVATE_KEY, KEY_ECDSA, },
! 282: { "bliss", CRED_PRIVATE_KEY, KEY_BLISS, },
! 283: { "pkcs12", CRED_CONTAINER, CONTAINER_PKCS12, },
! 284: };
! 285: int i;
! 286:
! 287: for (i = 0; i < countof(map); i++)
! 288: {
! 289: if (streq(map[i].type, type))
! 290: {
! 291: *credtype = map[i].credtype;
! 292: *subtype = map[i].subtype;
! 293: return TRUE;
! 294: }
! 295: }
! 296: return FALSE;
! 297: }
! 298:
! 299: /**
! 300: * Try to parse a potentially encrypted credential using password prompt
! 301: */
! 302: static void* decrypt(char *name, char *type, chunk_t encoding)
! 303: {
! 304: credential_type_t credtype;
! 305: int subtype;
! 306: void *cred;
! 307: callback_cred_t *cb;
! 308: cb_data_t data;
! 309:
! 310: if (!determine_credtype(type, &credtype, &subtype))
! 311: {
! 312: return NULL;
! 313: }
! 314:
! 315: snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
! 316: type, name);
! 317:
! 318: data.cache = mem_cred_create();
! 319: lib->credmgr->add_set(lib->credmgr, &data.cache->set);
! 320: cb = callback_cred_create_shared(password_cb, &data);
! 321: lib->credmgr->add_set(lib->credmgr, &cb->set);
! 322:
! 323: cred = lib->creds->create(lib->creds, credtype, subtype,
! 324: BUILD_BLOB_PEM, encoding, BUILD_END);
! 325:
! 326: lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
! 327: data.cache->destroy(data.cache);
! 328: lib->credmgr->remove_set(lib->credmgr, &cb->set);
! 329: cb->destroy(cb);
! 330:
! 331: return cred;
! 332: }
! 333:
! 334: /**
! 335: * Try to parse a potentially encrypted credential using configured secret
! 336: */
! 337: static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
! 338: chunk_t encoding)
! 339: {
! 340: credential_type_t credtype;
! 341: int subtype;
! 342: enumerator_t *enumerator, *secrets;
! 343: char *section, *key, *value, *file;
! 344: shared_key_t *shared;
! 345: void *cred = NULL;
! 346: mem_cred_t *mem = NULL;
! 347:
! 348: if (!determine_credtype(type, &credtype, &subtype))
! 349: {
! 350: return NULL;
! 351: }
! 352:
! 353: /* load all secrets for this key type */
! 354: enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
! 355: while (enumerator->enumerate(enumerator, §ion))
! 356: {
! 357: if (strpfx(section, type))
! 358: {
! 359: file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section);
! 360: if (file && strcaseeq(file, name))
! 361: {
! 362: secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg,
! 363: "secrets.%s", section);
! 364: while (secrets->enumerate(secrets, &key, &value))
! 365: {
! 366: if (strpfx(key, "secret"))
! 367: {
! 368: if (!mem)
! 369: {
! 370: mem = mem_cred_create();
! 371: }
! 372: shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
! 373: chunk_clone(chunk_from_str(value)));
! 374: mem->add_shared(mem, shared, NULL);
! 375: }
! 376: }
! 377: secrets->destroy(secrets);
! 378: }
! 379: }
! 380: }
! 381: enumerator->destroy(enumerator);
! 382:
! 383: if (mem)
! 384: {
! 385: lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
! 386:
! 387: cred = lib->creds->create(lib->creds, credtype, subtype,
! 388: BUILD_BLOB_PEM, encoding, BUILD_END);
! 389:
! 390: lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
! 391:
! 392: if (!cred)
! 393: {
! 394: fprintf(stderr, "configured decryption secret for '%s' invalid\n",
! 395: name);
! 396: }
! 397:
! 398: mem->destroy(mem);
! 399: }
! 400:
! 401: return cred;
! 402: }
! 403:
! 404: /**
! 405: * Try to decrypt and load a private key
! 406: */
! 407: static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
! 408: char *type, chunk_t data)
! 409: {
! 410: private_key_t *private;
! 411: bool loaded = FALSE;
! 412:
! 413: private = decrypt_with_config(ctx, rel, type, data);
! 414: if (!private && !ctx->noprompt)
! 415: {
! 416: private = decrypt(rel, type, data);
! 417: }
! 418: if (private)
! 419: {
! 420: loaded = load_key_anytype(ctx, path, private);
! 421: private->destroy(private);
! 422: }
! 423: return loaded;
! 424: }
! 425:
! 426: /**
! 427: * Load private keys from a directory
! 428: */
! 429: static void load_keys(load_ctx_t *ctx, char *type, char *dir)
! 430: {
! 431: enumerator_t *enumerator;
! 432: struct stat st;
! 433: chunk_t *map;
! 434: char *path, *rel, buf[PATH_MAX];
! 435:
! 436: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
! 437: dir = buf;
! 438:
! 439: enumerator = enumerator_create_directory(dir);
! 440: if (enumerator)
! 441: {
! 442: while (enumerator->enumerate(enumerator, &rel, &path, &st))
! 443: {
! 444: if (S_ISREG(st.st_mode))
! 445: {
! 446: map = chunk_map(path, FALSE);
! 447: if (map)
! 448: {
! 449: if (!load_encrypted_key(ctx, rel, path, type, *map))
! 450: {
! 451: load_key(ctx, path, type, *map);
! 452: }
! 453: chunk_unmap(map);
! 454: }
! 455: else
! 456: {
! 457: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
! 458: path, strerror(errno));
! 459: }
! 460: }
! 461: }
! 462: enumerator->destroy(enumerator);
! 463: }
! 464: }
! 465:
! 466: /**
! 467: * Load credentials from a PKCS#12 container over vici
! 468: */
! 469: static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
! 470: {
! 471: enumerator_t *enumerator;
! 472: certificate_t *cert;
! 473: private_key_t *private;
! 474: chunk_t encoding;
! 475: bool loaded = TRUE;
! 476:
! 477: enumerator = p12->create_cert_enumerator(p12);
! 478: while (loaded && enumerator->enumerate(enumerator, &cert))
! 479: {
! 480: loaded = FALSE;
! 481: if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
! 482: {
! 483: loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
! 484: if (loaded)
! 485: {
! 486: fprintf(stderr, " %Y\n", cert->get_subject(cert));
! 487: }
! 488: free(encoding.ptr);
! 489: }
! 490: else
! 491: {
! 492: fprintf(stderr, "encoding certificate from '%s' failed\n", path);
! 493: }
! 494: }
! 495: enumerator->destroy(enumerator);
! 496:
! 497: enumerator = p12->create_key_enumerator(p12);
! 498: while (loaded && enumerator->enumerate(enumerator, &private))
! 499: {
! 500: loaded = load_key_anytype(ctx, path, private);
! 501: }
! 502: enumerator->destroy(enumerator);
! 503:
! 504: return loaded;
! 505: }
! 506:
! 507: /**
! 508: * Try to decrypt and load credentials from a container
! 509: */
! 510: static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
! 511: char *type, chunk_t data)
! 512: {
! 513: container_t *container;
! 514: bool loaded = FALSE;
! 515:
! 516: container = decrypt_with_config(ctx, rel, type, data);
! 517: if (!container && !ctx->noprompt)
! 518: {
! 519: container = decrypt(rel, type, data);
! 520: }
! 521: if (container)
! 522: {
! 523: switch (container->get_type(container))
! 524: {
! 525: case CONTAINER_PKCS12:
! 526: loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
! 527: break;
! 528: default:
! 529: break;
! 530: }
! 531: container->destroy(container);
! 532: }
! 533: return loaded;
! 534: }
! 535:
! 536: /**
! 537: * Load credential containers from a directory
! 538: */
! 539: static void load_containers(load_ctx_t *ctx, char *type, char *dir)
! 540: {
! 541: enumerator_t *enumerator;
! 542: struct stat st;
! 543: chunk_t *map;
! 544: char *path, *rel, buf[PATH_MAX];
! 545:
! 546: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
! 547: dir = buf;
! 548:
! 549: enumerator = enumerator_create_directory(dir);
! 550: if (enumerator)
! 551: {
! 552: while (enumerator->enumerate(enumerator, &rel, &path, &st))
! 553: {
! 554: if (S_ISREG(st.st_mode))
! 555: {
! 556: map = chunk_map(path, FALSE);
! 557: if (map)
! 558: {
! 559: load_encrypted_container(ctx, rel, path, type, *map);
! 560: chunk_unmap(map);
! 561: }
! 562: else
! 563: {
! 564: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
! 565: path, strerror(errno));
! 566: }
! 567: }
! 568: }
! 569: enumerator->destroy(enumerator);
! 570: }
! 571: }
! 572:
! 573: /**
! 574: * Load a single private key on a token over vici
! 575: */
! 576: static bool load_token(load_ctx_t *ctx, char *name, char *pin)
! 577: {
! 578: vici_req_t *req;
! 579: vici_res_t *res;
! 580: enumerator_t *enumerator;
! 581: char *key, *value, *id;
! 582: bool ret = TRUE;
! 583:
! 584: req = vici_begin("load-token");
! 585:
! 586: enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
! 587: name);
! 588: while (enumerator->enumerate(enumerator, &key, &value))
! 589: {
! 590: vici_add_key_valuef(req, key, "%s", value);
! 591: }
! 592: enumerator->destroy(enumerator);
! 593:
! 594: if (pin)
! 595: {
! 596: vici_add_key_valuef(req, "pin", "%s", pin);
! 597: }
! 598: res = vici_submit(req, ctx->conn);
! 599: if (!res)
! 600: {
! 601: fprintf(stderr, "load-token request failed: %s\n", strerror(errno));
! 602: return FALSE;
! 603: }
! 604: if (ctx->format & COMMAND_FORMAT_RAW)
! 605: {
! 606: vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 607: stdout);
! 608: }
! 609: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 610: {
! 611: fprintf(stderr, "loading '%s' failed: %s\n",
! 612: name, vici_find_str(res, "", "errmsg"));
! 613: ret = FALSE;
! 614: }
! 615: else
! 616: {
! 617: id = vici_find_str(res, "", "id");
! 618: printf("loaded key %s from token [keyid: %s]\n", name, id);
! 619: free(ctx->keys->remove(ctx->keys, id));
! 620: }
! 621: vici_free_res(res);
! 622: return ret;
! 623: }
! 624:
! 625: /**
! 626: * Load keys from tokens
! 627: */
! 628: static void load_tokens(load_ctx_t *ctx)
! 629: {
! 630: enumerator_t *enumerator;
! 631: char *section, *pin = NULL, prompt[128];
! 632:
! 633: enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
! 634: while (enumerator->enumerate(enumerator, §ion))
! 635: {
! 636: if (strpfx(section, "token"))
! 637: {
! 638: if (!ctx->noprompt &&
! 639: !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section))
! 640: {
! 641: #ifdef HAVE_GETPASS
! 642: snprintf(prompt, sizeof(prompt), "PIN for %s: ", section);
! 643: pin = strdupnull(getpass(prompt));
! 644: #endif
! 645: }
! 646: load_token(ctx, section, pin);
! 647: if (pin)
! 648: {
! 649: memwipe(pin, strlen(pin));
! 650: free(pin);
! 651: pin = NULL;
! 652: }
! 653: }
! 654: }
! 655: enumerator->destroy(enumerator);
! 656: }
! 657:
! 658:
! 659:
! 660: /**
! 661: * Load a single secret over VICI
! 662: */
! 663: static bool load_secret(load_ctx_t *ctx, char *section)
! 664: {
! 665: enumerator_t *enumerator;
! 666: vici_req_t *req;
! 667: vici_res_t *res;
! 668: chunk_t data;
! 669: char *key, *value, *type = NULL;
! 670: bool ret = TRUE;
! 671: int i;
! 672: char *types[] = {
! 673: "eap",
! 674: "xauth",
! 675: "ntlm",
! 676: "ike",
! 677: "ppk",
! 678: "private",
! 679: "rsa",
! 680: "ecdsa",
! 681: "bliss",
! 682: "pkcs8",
! 683: "pkcs12",
! 684: "token",
! 685: };
! 686:
! 687: for (i = 0; i < countof(types); i++)
! 688: {
! 689: if (strpfx(section, types[i]))
! 690: {
! 691: type = types[i];
! 692: break;
! 693: }
! 694: }
! 695: if (!type)
! 696: {
! 697: fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
! 698: return FALSE;
! 699: }
! 700: if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") &&
! 701: !streq(type, "ike") && !streq(type, "ppk"))
! 702: { /* skip non-shared secrets */
! 703: return TRUE;
! 704: }
! 705:
! 706: value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section);
! 707: if (!value)
! 708: {
! 709: fprintf(stderr, "missing secret in '%s', ignored\n", section);
! 710: return FALSE;
! 711: }
! 712: if (strcasepfx(value, "0x"))
! 713: {
! 714: data = chunk_from_hex(chunk_from_str(value + 2), NULL);
! 715: }
! 716: else if (strcasepfx(value, "0s"))
! 717: {
! 718: data = chunk_from_base64(chunk_from_str(value + 2), NULL);
! 719: }
! 720: else
! 721: {
! 722: data = chunk_clone(chunk_from_str(value));
! 723: }
! 724:
! 725: req = vici_begin("load-shared");
! 726:
! 727: vici_add_key_valuef(req, "id", "%s", section);
! 728: vici_add_key_valuef(req, "type", "%s", type);
! 729: vici_add_key_value(req, "data", data.ptr, data.len);
! 730: chunk_clear(&data);
! 731:
! 732: vici_begin_list(req, "owners");
! 733: enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
! 734: section);
! 735: while (enumerator->enumerate(enumerator, &key, &value))
! 736: {
! 737: if (strpfx(key, "id"))
! 738: {
! 739: vici_add_list_itemf(req, "%s", value);
! 740: }
! 741: }
! 742: enumerator->destroy(enumerator);
! 743: vici_end_list(req);
! 744:
! 745: res = vici_submit(req, ctx->conn);
! 746: if (!res)
! 747: {
! 748: fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
! 749: return FALSE;
! 750: }
! 751: if (ctx->format & COMMAND_FORMAT_RAW)
! 752: {
! 753: vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 754: stdout);
! 755: }
! 756: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 757: {
! 758: fprintf(stderr, "loading shared secret failed: %s\n",
! 759: vici_find_str(res, "", "errmsg"));
! 760: ret = FALSE;
! 761: }
! 762: else
! 763: {
! 764: printf("loaded %s secret '%s'\n", type, section);
! 765: }
! 766: if (ret)
! 767: {
! 768: free(ctx->shared->remove(ctx->shared, section));
! 769: }
! 770: vici_free_res(res);
! 771: return ret;
! 772: }
! 773:
! 774: CALLBACK(get_id, int,
! 775: hashtable_t *ht, vici_res_t *res, char *name, void *value, int len)
! 776: {
! 777: if (streq(name, "keys"))
! 778: {
! 779: char *str;
! 780:
! 781: if (asprintf(&str, "%.*s", len, value) != -1)
! 782: {
! 783: free(ht->put(ht, str, str));
! 784: }
! 785: }
! 786: return 0;
! 787: }
! 788:
! 789: /**
! 790: * Get a list of currently loaded private and shared keys
! 791: */
! 792: static void get_creds(load_ctx_t *ctx)
! 793: {
! 794: vici_res_t *res;
! 795:
! 796: res = vici_submit(vici_begin("get-keys"), ctx->conn);
! 797: if (res)
! 798: {
! 799: if (ctx->format & COMMAND_FORMAT_RAW)
! 800: {
! 801: vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 802: stdout);
! 803: }
! 804: vici_parse_cb(res, NULL, NULL, get_id, ctx->keys);
! 805: vici_free_res(res);
! 806: }
! 807: res = vici_submit(vici_begin("get-shared"), ctx->conn);
! 808: if (res)
! 809: {
! 810: if (ctx->format & COMMAND_FORMAT_RAW)
! 811: {
! 812: vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
! 813: stdout);
! 814: }
! 815: vici_parse_cb(res, NULL, NULL, get_id, ctx->shared);
! 816: vici_free_res(res);
! 817: }
! 818: }
! 819:
! 820: /**
! 821: * Remove a given key
! 822: */
! 823: static bool unload_key(load_ctx_t *ctx, char *command, char *id)
! 824: {
! 825: vici_req_t *req;
! 826: vici_res_t *res;
! 827: char buf[BUF_LEN];
! 828: bool ret = TRUE;
! 829:
! 830: req = vici_begin(command);
! 831:
! 832: vici_add_key_valuef(req, "id", "%s", id);
! 833:
! 834: res = vici_submit(req, ctx->conn);
! 835: if (!res)
! 836: {
! 837: fprintf(stderr, "%s request failed: %s\n", command, strerror(errno));
! 838: return FALSE;
! 839: }
! 840: if (ctx->format & COMMAND_FORMAT_RAW)
! 841: {
! 842: snprintf(buf, sizeof(buf), "%s reply", command);
! 843: vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout);
! 844: }
! 845: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
! 846: {
! 847: fprintf(stderr, "unloading key '%s' failed: %s\n",
! 848: id, vici_find_str(res, "", "errmsg"));
! 849: ret = FALSE;
! 850: }
! 851: vici_free_res(res);
! 852: return ret;
! 853: }
! 854:
! 855: /**
! 856: * Remove all keys in the given hashtable using the given command
! 857: */
! 858: static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command)
! 859: {
! 860: enumerator_t *enumerator;
! 861: char *id;
! 862:
! 863: enumerator = ht->create_enumerator(ht);
! 864: while (enumerator->enumerate(enumerator, &id, NULL))
! 865: {
! 866: unload_key(ctx, command, id);
! 867: }
! 868: enumerator->destroy(enumerator);
! 869: }
! 870:
! 871: /**
! 872: * Clear all currently loaded credentials
! 873: */
! 874: static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
! 875: {
! 876: vici_res_t *res;
! 877:
! 878: res = vici_submit(vici_begin("clear-creds"), conn);
! 879: if (!res)
! 880: {
! 881: fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
! 882: return FALSE;
! 883: }
! 884: if (format & COMMAND_FORMAT_RAW)
! 885: {
! 886: vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
! 887: stdout);
! 888: }
! 889: vici_free_res(res);
! 890: return TRUE;
! 891: }
! 892:
! 893: /**
! 894: * See header.
! 895: */
! 896: int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
! 897: settings_t *cfg, bool clear, bool noprompt)
! 898: {
! 899: enumerator_t *enumerator;
! 900: char *section;
! 901: load_ctx_t ctx = {
! 902: .conn = conn,
! 903: .format = format,
! 904: .noprompt = noprompt,
! 905: .cfg = cfg,
! 906: .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
! 907: .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
! 908: };
! 909:
! 910: if (clear)
! 911: {
! 912: if (!clear_creds(conn, format))
! 913: {
! 914: return ECONNREFUSED;
! 915: }
! 916: }
! 917:
! 918: get_creds(&ctx);
! 919:
! 920: load_certs(&ctx, "x509", SWANCTL_X509DIR);
! 921: load_certs(&ctx, "x509ca", SWANCTL_X509CADIR);
! 922: load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
! 923: load_certs(&ctx, "x509aa", SWANCTL_X509AADIR);
! 924: load_certs(&ctx, "x509ac", SWANCTL_X509ACDIR);
! 925: load_certs(&ctx, "x509crl", SWANCTL_X509CRLDIR);
! 926: load_certs(&ctx, "pubkey", SWANCTL_PUBKEYDIR);
! 927:
! 928: load_keys(&ctx, "private", SWANCTL_PRIVATEDIR);
! 929: load_keys(&ctx, "rsa", SWANCTL_RSADIR);
! 930: load_keys(&ctx, "ecdsa", SWANCTL_ECDSADIR);
! 931: load_keys(&ctx, "bliss", SWANCTL_BLISSDIR);
! 932: load_keys(&ctx, "pkcs8", SWANCTL_PKCS8DIR);
! 933:
! 934: load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
! 935:
! 936: load_tokens(&ctx);
! 937:
! 938: enumerator = cfg->create_section_enumerator(cfg, "secrets");
! 939: while (enumerator->enumerate(enumerator, §ion))
! 940: {
! 941: load_secret(&ctx, section);
! 942: }
! 943: enumerator->destroy(enumerator);
! 944:
! 945: unload_keys(&ctx, ctx.keys, "unload-key");
! 946: unload_keys(&ctx, ctx.shared, "unload-shared");
! 947:
! 948: ctx.keys->destroy_function(ctx.keys, (void*)free);
! 949: ctx.shared->destroy_function(ctx.shared, (void*)free);
! 950: return 0;
! 951: }
! 952:
! 953: static int load_creds(vici_conn_t *conn)
! 954: {
! 955: bool clear = FALSE, noprompt = FALSE;
! 956: command_format_options_t format = COMMAND_FORMAT_NONE;
! 957: settings_t *cfg;
! 958: char *arg, *file = NULL;
! 959: int ret;
! 960:
! 961: while (TRUE)
! 962: {
! 963: switch (command_getopt(&arg))
! 964: {
! 965: case 'h':
! 966: return command_usage(NULL);
! 967: case 'c':
! 968: clear = TRUE;
! 969: continue;
! 970: case 'n':
! 971: noprompt = TRUE;
! 972: continue;
! 973: case 'P':
! 974: format |= COMMAND_FORMAT_PRETTY;
! 975: /* fall through to raw */
! 976: case 'r':
! 977: format |= COMMAND_FORMAT_RAW;
! 978: continue;
! 979: case 'f':
! 980: file = arg;
! 981: continue;
! 982: case EOF:
! 983: break;
! 984: default:
! 985: return command_usage("invalid --load-creds option");
! 986: }
! 987: break;
! 988: }
! 989:
! 990: cfg = load_swanctl_conf(file);
! 991: if (!cfg)
! 992: {
! 993: return EINVAL;
! 994: }
! 995:
! 996: ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
! 997:
! 998: cfg->destroy(cfg);
! 999:
! 1000: return ret;
! 1001: }
! 1002:
! 1003: /**
! 1004: * Register the command.
! 1005: */
! 1006: static void __attribute__ ((constructor))reg()
! 1007: {
! 1008: command_register((command_t) {
! 1009: load_creds, 's', "load-creds", "(re-)load credentials",
! 1010: {"[--raw|--pretty] [--clear] [--noprompt]"},
! 1011: {
! 1012: {"help", 'h', 0, "show usage information"},
! 1013: {"clear", 'c', 0, "clear previously loaded credentials"},
! 1014: {"noprompt", 'n', 0, "do not prompt for passwords"},
! 1015: {"raw", 'r', 0, "dump raw response message"},
! 1016: {"pretty", 'P', 0, "dump raw response message in pretty print"},
! 1017: {"file", 'f', 1, "custom path to swanctl.conf"},
! 1018: }
! 1019: });
! 1020: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>