diff options
Diffstat (limited to 'src/swanctl/commands')
-rw-r--r-- | src/swanctl/commands/initiate.c | 12 | ||||
-rw-r--r-- | src/swanctl/commands/install.c | 15 | ||||
-rw-r--r-- | src/swanctl/commands/list_pools.c | 14 | ||||
-rw-r--r-- | src/swanctl/commands/list_sas.c | 23 | ||||
-rw-r--r-- | src/swanctl/commands/load_authorities.c | 8 | ||||
-rw-r--r-- | src/swanctl/commands/load_conns.c | 67 | ||||
-rw-r--r-- | src/swanctl/commands/load_creds.c | 377 | ||||
-rw-r--r-- | src/swanctl/commands/rekey.c | 125 |
8 files changed, 523 insertions, 118 deletions
diff --git a/src/swanctl/commands/initiate.c b/src/swanctl/commands/initiate.c index eb7b6adbd..8e452a6f6 100644 --- a/src/swanctl/commands/initiate.c +++ b/src/swanctl/commands/initiate.c @@ -37,7 +37,7 @@ static int initiate(vici_conn_t *conn) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg, *child = NULL; + char *arg, *child = NULL, *ike = NULL; int ret = 0, timeout = 0, level = 1; while (TRUE) @@ -55,6 +55,9 @@ static int initiate(vici_conn_t *conn) case 'c': child = arg; continue; + case 'i': + ike = arg; + continue; case 't': timeout = atoi(arg); continue; @@ -80,6 +83,10 @@ static int initiate(vici_conn_t *conn) { vici_add_key_valuef(req, "child", "%s", child); } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } if (timeout) { vici_add_key_valuef(req, "timeout", "%d", timeout * 1000); @@ -121,10 +128,11 @@ static void __attribute__ ((constructor))reg() { command_register((command_t) { initiate, 'i', "initiate", "initiate a connection", - {"--child <name> [--timeout <s>] [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--timeout <s>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "initate a CHILD_SA configuration"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"timeout", 't', 1, "timeout in seconds before detaching"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, diff --git a/src/swanctl/commands/install.c b/src/swanctl/commands/install.c index 59c5c24ab..24a397b87 100644 --- a/src/swanctl/commands/install.c +++ b/src/swanctl/commands/install.c @@ -22,7 +22,7 @@ static int manage_policy(vici_conn_t *conn, char *label) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg, *child = NULL; + char *arg, *child = NULL, *ike = NULL; int ret = 0; while (TRUE) @@ -40,6 +40,9 @@ static int manage_policy(vici_conn_t *conn, char *label) case 'c': child = arg; continue; + case 'i': + ike = arg; + continue; case EOF: break; default: @@ -52,6 +55,10 @@ static int manage_policy(vici_conn_t *conn, char *label) { vici_add_key_valuef(req, "child", "%s", child); } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } res = vici_submit(req, conn); if (!res) { @@ -98,10 +105,11 @@ static void __attribute__ ((constructor))reg_uninstall() { command_register((command_t) { uninstall, 'u', "uninstall", "uninstall a trap or shunt policy", - {"--child <name> [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "CHILD_SA configuration to uninstall"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, } @@ -115,10 +123,11 @@ static void __attribute__ ((constructor))reg_install() { command_register((command_t) { install, 'p', "install", "install a trap or shunt policy", - {"--child <name> [--raw|--pretty]"}, + {"--child <name> [--ike <name>] [--raw|--pretty]"}, { {"help", 'h', 0, "show usage information"}, {"child", 'c', 1, "CHILD_SA configuration to install"}, + {"ike", 'i', 1, "name of the connection to which the child belongs"}, {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, } diff --git a/src/swanctl/commands/list_pools.c b/src/swanctl/commands/list_pools.c index 429107e17..a170adeba 100644 --- a/src/swanctl/commands/list_pools.c +++ b/src/swanctl/commands/list_pools.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2015 Tobias Brunner - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2015-2016 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil * * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG @@ -58,7 +58,7 @@ static int list_pools(vici_conn_t *conn) vici_req_t *req; vici_res_t *res; command_format_options_t format = COMMAND_FORMAT_NONE; - char *arg; + char *arg, *name = NULL; int ret = 0; bool leases = FALSE; @@ -77,6 +77,9 @@ static int list_pools(vici_conn_t *conn) case 'l': leases = TRUE; continue; + case 'n': + name = arg; + continue; case EOF: break; default: @@ -90,6 +93,10 @@ static int list_pools(vici_conn_t *conn) { vici_add_key_valuef(req, "leases", "yes"); } + if (name) + { + vici_add_key_valuef(req, "name", "%s", name); + } res = vici_submit(req, conn); if (!res) { @@ -123,6 +130,7 @@ static void __attribute__ ((constructor))reg() {"raw", 'r', 0, "dump raw response message"}, {"pretty", 'P', 0, "dump raw response message in pretty print"}, {"leases", 'l', 0, "list leases of each pool"}, + {"name", 'n', 1, "filter pools by name"}, } }); } diff --git a/src/swanctl/commands/list_sas.c b/src/swanctl/commands/list_sas.c index e5f251d17..28602fc65 100644 --- a/src/swanctl/commands/list_sas.c +++ b/src/swanctl/commands/list_sas.c @@ -112,8 +112,9 @@ CALLBACK(child_sas, int, if (ret == 0) { printf(" %s: #%s, reqid %s, %s, %s%s, %s:", - name, child->get(child, "uniqueid"), child->get(child, "reqid"), - child->get(child, "state"), child->get(child, "mode"), + child->get(child, "name"), child->get(child, "uniqueid"), + child->get(child, "reqid"), child->get(child, "state"), + child->get(child, "mode"), child->get(child, "encap") ? "-in-UDP" : "", child->get(child, "protocol")); @@ -165,6 +166,15 @@ CALLBACK(child_sas, int, printf(" in %s%s%s", child->get(child, "spi-in"), child->get(child, "cpi-in") ? "/" : "", child->get(child, "cpi-in") ?: ""); + if (child->get(child, "mark-in")) + { + printf(" (0x%s", child->get(child, "mark-in")); + if (child->get(child, "mark-mask-in")) + { + printf("/0x%s", child->get(child, "mark-mask-in")); + } + printf(")"); + } printf(", %6s bytes, %5s packets", child->get(child, "bytes-in"), child->get(child, "packets-in")); if (child->get(child, "use-in")) @@ -176,6 +186,15 @@ CALLBACK(child_sas, int, printf(" out %s%s%s", child->get(child, "spi-out"), child->get(child, "cpi-out") ? "/" : "", child->get(child, "cpi-out") ?: ""); + if (child->get(child, "mark-out")) + { + printf(" (0x%s", child->get(child, "mark-out")); + if (child->get(child, "mark-mask-out")) + { + printf("/0x%s", child->get(child, "mark-mask-out")); + } + printf(")"); + } printf(", %6s bytes, %5s packets", child->get(child, "bytes-out"), child->get(child, "packets-out")); if (child->get(child, "use-out")) diff --git a/src/swanctl/commands/load_authorities.c b/src/swanctl/commands/load_authorities.c index 352a185e8..8947866f5 100644 --- a/src/swanctl/commands/load_authorities.c +++ b/src/swanctl/commands/load_authorities.c @@ -86,18 +86,18 @@ static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section) enumerator = cfg->create_key_value_enumerator(cfg, section); while (enumerator->enumerate(enumerator, &key, &value)) { - /* pool subnet is encoded as key/value, all other attributes as list */ if (streq(key, "cacert")) { ret = add_file_key_value(req, key, value); } - else if (streq(key, "cert_uri_base")) + else if (streq(key, "crl_uris") || + streq(key, "ocsp_uris")) { - vici_add_key_valuef(req, key, "%s", value); + add_list_key(req, key, value); } else { - add_list_key(req, key, value); + vici_add_key_valuef(req, key, "%s", value); } if (!ret) { diff --git a/src/swanctl/commands/load_conns.c b/src/swanctl/commands/load_conns.c index 2e443a94a..0518ef54f 100644 --- a/src/swanctl/commands/load_conns.c +++ b/src/swanctl/commands/load_conns.c @@ -38,6 +38,7 @@ static bool is_list_key(char *key) "vips", "pools", "groups", + "cert_policy", }; int i; @@ -97,7 +98,7 @@ static void add_list_key(vici_req_t *req, char *key, char *value) static bool add_file_list_key(vici_req_t *req, char *key, char *value) { enumerator_t *enumerator; - chunk_t *map; + chunk_t *map, blob; char *token, buf[PATH_MAX]; bool ret = TRUE; @@ -105,41 +106,51 @@ static bool add_file_list_key(vici_req_t *req, char *key, char *value) enumerator = enumerator_create_token(value, ",", " "); while (enumerator->enumerate(enumerator, &token)) { - if (!path_absolute(token)) + if (strcasepfx(token, "0x") || strcasepfx(token, "0s")) { - if (streq(key, "certs")) + blob = chunk_from_str(token + 2); + blob = strcasepfx(token, "0x") ? chunk_from_hex(blob, NULL) + : chunk_from_base64(blob, NULL); + vici_add_list_item(req, blob.ptr, blob.len); + chunk_free(&blob); + } + else + { + if (!path_absolute(token)) { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token); - token = buf; + if (streq(key, "certs")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token); + token = buf; + } + else if (streq(key, "cacerts")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, token); + token = buf; + } + else if (streq(key, "pubkeys")) + { + snprintf(buf, sizeof(buf), "%s%s%s", + SWANCTL_PUBKEYDIR, DIRECTORY_SEPARATOR, token); + token = buf; + } } - else if (streq(key, "cacerts")) + map = chunk_map(token, FALSE); + if (map) { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, token); - token = buf; + vici_add_list_item(req, map->ptr, map->len); + chunk_unmap(map); } - else if (streq(key, "pubkeys")) + else { - snprintf(buf, sizeof(buf), "%s%s%s", - SWANCTL_PUBKEYDIR, DIRECTORY_SEPARATOR, token); - token = buf; + fprintf(stderr, "loading %s certificate '%s' failed: %s\n", + key, token, strerror(errno)); + ret = FALSE; + break; } } - - map = chunk_map(token, FALSE); - if (map) - { - vici_add_list_item(req, map->ptr, map->len); - chunk_unmap(map); - } - else - { - fprintf(stderr, "loading %s certificate '%s' failed: %s\n", - key, token, strerror(errno)); - ret = FALSE; - break; - } } enumerator->destroy(enumerator); vici_end_list(req); diff --git a/src/swanctl/commands/load_creds.c b/src/swanctl/commands/load_creds.c index 6278f66b4..848d8512c 100644 --- a/src/swanctl/commands/load_creds.c +++ b/src/swanctl/commands/load_creds.c @@ -1,11 +1,11 @@ /* - * Copyright (C) 2014 Martin Willi - * Copyright (C) 2014 revosec AG - * * Copyright (C) 2016 Tobias Brunner * Copyright (C) 2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * + * Copyright (C) 2014 Martin Willi + * Copyright (C) 2014 revosec AG + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -30,15 +30,35 @@ #include <credentials/sets/mem_cred.h> #include <credentials/sets/callback_cred.h> #include <credentials/containers/pkcs12.h> +#include <collections/hashtable.h> #include <vici_cert_info.h> +#define HASH_SIZE_SHA1_HEX (2 * HASH_SIZE_SHA1) + +/** + * Context used to track loaded secrets + */ +typedef struct { + /** vici connection */ + vici_conn_t *conn; + /** format options */ + command_format_options_t format; + /** read setting */ + settings_t *cfg; + /** don't prompt user for password */ + bool noprompt; + /** list of key ids of loaded private keys */ + hashtable_t *keys; + /** list of unique ids of loaded shared keys */ + hashtable_t *shared; +} load_ctx_t; + /** * Load a single certificate over vici */ -static bool load_cert(vici_conn_t *conn, command_format_options_t format, - char *dir, certificate_type_t type, x509_flag_t flag, - chunk_t data) +static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type, + x509_flag_t flag, chunk_t data) { vici_req_t *req; vici_res_t *res; @@ -53,15 +73,15 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format, } vici_add_key_value(req, "data", data.ptr, data.len); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-cert request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-cert reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -81,8 +101,7 @@ static bool load_cert(vici_conn_t *conn, command_format_options_t format, /** * Load certficiates from a directory */ -static void load_certs(vici_conn_t *conn, command_format_options_t format, - char *type_str, char *dir) +static void load_certs(load_ctx_t *ctx, char *type_str, char *dir) { enumerator_t *enumerator; certificate_type_t type; @@ -103,7 +122,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - load_cert(conn, format, path, type, flag, *map); + load_cert(ctx, path, type, flag, *map); chunk_unmap(map); } else @@ -120,8 +139,7 @@ static void load_certs(vici_conn_t *conn, command_format_options_t format, /** * Load a single private key over vici */ -static bool load_key(vici_conn_t *conn, command_format_options_t format, - char *dir, char *type, chunk_t data) +static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data) { vici_req_t *req; vici_res_t *res; @@ -140,15 +158,15 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format, } vici_add_key_value(req, "data", data.ptr, data.len); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-key request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-key reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -168,11 +186,12 @@ static bool load_key(vici_conn_t *conn, command_format_options_t format, /** * Load a private key of any type to vici */ -static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format, - char *path, private_key_t *private) +static bool load_key_anytype(load_ctx_t *ctx, char *path, + private_key_t *private) { bool loaded = FALSE; - chunk_t encoding; + chunk_t encoding, keyid; + char hex[HASH_SIZE_SHA1_HEX + 1]; if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding)) { @@ -182,18 +201,25 @@ static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format, switch (private->get_type(private)) { case KEY_RSA: - loaded = load_key(conn, format, path, "rsa", encoding); + loaded = load_key(ctx, path, "rsa", encoding); break; case KEY_ECDSA: - loaded = load_key(conn, format, path, "ecdsa", encoding); + loaded = load_key(ctx, path, "ecdsa", encoding); break; case KEY_BLISS: - loaded = load_key(conn, format, path, "bliss", encoding); + loaded = load_key(ctx, path, "bliss", encoding); break; default: fprintf(stderr, "unsupported key type in '%s'\n", path); break; } + + if (loaded && + private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid) && + snprintf(hex, sizeof(hex), "%+B", &keyid) == HASH_SIZE_SHA1_HEX) + { + free(ctx->keys->remove(ctx->keys, hex)); + } chunk_clear(&encoding); return loaded; } @@ -312,7 +338,7 @@ static void* decrypt(char *name, char *type, chunk_t encoding) /** * Try to parse a potentially encrypted credential using configured secret */ -static void* decrypt_with_config(settings_t *cfg, char *name, char *type, +static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type, chunk_t encoding) { credential_type_t credtype; @@ -329,16 +355,16 @@ static void* decrypt_with_config(settings_t *cfg, char *name, char *type, } /* load all secrets for this key type */ - enumerator = cfg->create_section_enumerator(cfg, "secrets"); + enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets"); while (enumerator->enumerate(enumerator, §ion)) { if (strpfx(section, type)) { - file = cfg->get_str(cfg, "secrets.%s.file", NULL, section); + file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section); if (file && strcaseeq(file, name)) { snprintf(buf, sizeof(buf), "secrets.%s", section); - secrets = cfg->create_key_value_enumerator(cfg, buf); + secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf); while (secrets->enumerate(secrets, &key, &value)) { if (strpfx(key, "secret")) @@ -382,22 +408,20 @@ static void* decrypt_with_config(settings_t *cfg, char *name, char *type, /** * Try to decrypt and load a private key */ -static bool load_encrypted_key(vici_conn_t *conn, - command_format_options_t format, settings_t *cfg, - char *rel, char *path, char *type, bool noprompt, - chunk_t data) +static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path, + char *type, chunk_t data) { private_key_t *private; bool loaded = FALSE; - private = decrypt_with_config(cfg, rel, type, data); - if (!private && !noprompt) + private = decrypt_with_config(ctx, rel, type, data); + if (!private && !ctx->noprompt) { private = decrypt(rel, type, data); } if (private) { - loaded = load_key_anytype(conn, format, path, private); + loaded = load_key_anytype(ctx, path, private); private->destroy(private); } return loaded; @@ -406,8 +430,7 @@ static bool load_encrypted_key(vici_conn_t *conn, /** * Load private keys from a directory */ -static void load_keys(vici_conn_t *conn, command_format_options_t format, - bool noprompt, settings_t *cfg, char *type, char *dir) +static void load_keys(load_ctx_t *ctx, char *type, char *dir) { enumerator_t *enumerator; struct stat st; @@ -424,10 +447,9 @@ static void load_keys(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - if (!load_encrypted_key(conn, format, cfg, rel, path, type, - noprompt, *map)) + if (!load_encrypted_key(ctx, rel, path, type, *map)) { - load_key(conn, format, path, type, *map); + load_key(ctx, path, type, *map); } chunk_unmap(map); } @@ -445,8 +467,7 @@ static void load_keys(vici_conn_t *conn, command_format_options_t format, /** * Load credentials from a PKCS#12 container over vici */ -static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, - char *path, pkcs12_t *p12) +static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12) { enumerator_t *enumerator; certificate_t *cert; @@ -460,8 +481,7 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, loaded = FALSE; if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding)) { - loaded = load_cert(conn, format, path, CERT_X509, X509_NONE, - encoding); + loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding); if (loaded) { fprintf(stderr, " %Y\n", cert->get_subject(cert)); @@ -478,7 +498,7 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, enumerator = p12->create_key_enumerator(p12); while (loaded && enumerator->enumerate(enumerator, &private)) { - loaded = load_key_anytype(conn, format, path, private); + loaded = load_key_anytype(ctx, path, private); } enumerator->destroy(enumerator); @@ -488,15 +508,14 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format, /** * Try to decrypt and load credentials from a container */ -static bool load_encrypted_container(vici_conn_t *conn, - command_format_options_t format, settings_t *cfg, char *rel, - char *path, char *type, bool noprompt, chunk_t data) +static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path, + char *type, chunk_t data) { container_t *container; bool loaded = FALSE; - container = decrypt_with_config(cfg, rel, type, data); - if (!container && !noprompt) + container = decrypt_with_config(ctx, rel, type, data); + if (!container && !ctx->noprompt) { container = decrypt(rel, type, data); } @@ -505,7 +524,7 @@ static bool load_encrypted_container(vici_conn_t *conn, switch (container->get_type(container)) { case CONTAINER_PKCS12: - loaded = load_pkcs12(conn, format, path, (pkcs12_t*)container); + loaded = load_pkcs12(ctx, path, (pkcs12_t*)container); break; default: break; @@ -518,8 +537,7 @@ static bool load_encrypted_container(vici_conn_t *conn, /** * Load credential containers from a directory */ -static void load_containers(vici_conn_t *conn, command_format_options_t format, - bool noprompt, settings_t *cfg, char *type, char *dir) +static void load_containers(load_ctx_t *ctx, char *type, char *dir) { enumerator_t *enumerator; struct stat st; @@ -536,8 +554,7 @@ static void load_containers(vici_conn_t *conn, command_format_options_t format, map = chunk_map(path, FALSE); if (map) { - load_encrypted_container(conn, format, cfg, rel, path, - type, noprompt, *map); + load_encrypted_container(ctx, rel, path, type, *map); chunk_unmap(map); } else @@ -552,10 +569,96 @@ static void load_containers(vici_conn_t *conn, command_format_options_t format, } /** + * Load a single private key on a token over vici + */ +static bool load_token(load_ctx_t *ctx, char *name, char *pin) +{ + vici_req_t *req; + vici_res_t *res; + enumerator_t *enumerator; + char *key, *value, *id; + bool ret = TRUE; + + req = vici_begin("load-token"); + + enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s", + name); + while (enumerator->enumerate(enumerator, &key, &value)) + { + vici_add_key_valuef(req, key, "%s", value); + } + enumerator->destroy(enumerator); + + if (pin) + { + vici_add_key_valuef(req, "pin", "%s", pin); + } + res = vici_submit(req, ctx->conn); + if (!res) + { + fprintf(stderr, "load-token request failed: %s\n", strerror(errno)); + return FALSE; + } + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + else if (!streq(vici_find_str(res, "no", "success"), "yes")) + { + fprintf(stderr, "loading '%s' failed: %s\n", + name, vici_find_str(res, "", "errmsg")); + ret = FALSE; + } + else + { + id = vici_find_str(res, "", "id"); + printf("loaded key %s from token [keyid: %s]\n", name, id); + free(ctx->keys->remove(ctx->keys, id)); + } + vici_free_res(res); + return ret; +} + +/** + * Load keys from tokens + */ +static void load_tokens(load_ctx_t *ctx) +{ + enumerator_t *enumerator; + char *section, *pin = NULL, prompt[128]; + + enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets"); + while (enumerator->enumerate(enumerator, §ion)) + { + if (strpfx(section, "token")) + { + if (!ctx->noprompt && + !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section)) + { +#ifdef HAVE_GETPASS + snprintf(prompt, sizeof(prompt), "PIN for %s: ", section); + pin = strdupnull(getpass(prompt)); +#endif + } + load_token(ctx, section, pin); + if (pin) + { + memwipe(pin, strlen(pin)); + free(pin); + pin = NULL; + } + } + } + enumerator->destroy(enumerator); +} + + + +/** * Load a single secret over VICI */ -static bool load_secret(vici_conn_t *conn, settings_t *cfg, - char *section, command_format_options_t format) +static bool load_secret(load_ctx_t *ctx, char *section) { enumerator_t *enumerator; vici_req_t *req; @@ -567,6 +670,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, char *types[] = { "eap", "xauth", + "ntlm", "ike", "private", "rsa", @@ -574,6 +678,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, "bliss", "pkcs8", "pkcs12", + "token", }; for (i = 0; i < countof(types); i++) @@ -589,12 +694,13 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, fprintf(stderr, "ignoring unsupported secret '%s'\n", section); return FALSE; } - if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ike")) + if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") && + !streq(type, "ike")) { /* skip non-shared secrets */ return TRUE; } - value = cfg->get_str(cfg, "secrets.%s.secret", NULL, section); + value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section); if (!value) { fprintf(stderr, "missing secret in '%s', ignored\n", section); @@ -615,13 +721,14 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, req = vici_begin("load-shared"); + vici_add_key_valuef(req, "id", "%s", section); vici_add_key_valuef(req, "type", "%s", type); vici_add_key_value(req, "data", data.ptr, data.len); chunk_clear(&data); vici_begin_list(req, "owners"); snprintf(buf, sizeof(buf), "secrets.%s", section); - enumerator = cfg->create_key_value_enumerator(cfg, buf); + enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf); while (enumerator->enumerate(enumerator, &key, &value)) { if (strpfx(key, "id")) @@ -632,15 +739,15 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, enumerator->destroy(enumerator); vici_end_list(req); - res = vici_submit(req, conn); + res = vici_submit(req, ctx->conn); if (!res) { fprintf(stderr, "load-shared request failed: %s\n", strerror(errno)); return FALSE; } - if (format & COMMAND_FORMAT_RAW) + if (ctx->format & COMMAND_FORMAT_RAW) { - vici_dump(res, "load-shared reply", format & COMMAND_FORMAT_PRETTY, + vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY, stdout); } else if (!streq(vici_find_str(res, "no", "success"), "yes")) @@ -653,10 +760,111 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg, { printf("loaded %s secret '%s'\n", type, section); } + if (ret) + { + free(ctx->shared->remove(ctx->shared, section)); + } vici_free_res(res); return ret; } +CALLBACK(get_id, int, + hashtable_t *ht, vici_res_t *res, char *name, void *value, int len) +{ + if (streq(name, "keys")) + { + char *str; + + if (asprintf(&str, "%.*s", len, value) != -1) + { + free(ht->put(ht, str, str)); + } + } + return 0; +} + +/** + * Get a list of currently loaded private and shared keys + */ +static void get_creds(load_ctx_t *ctx) +{ + vici_res_t *res; + + res = vici_submit(vici_begin("get-keys"), ctx->conn); + if (res) + { + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + vici_parse_cb(res, NULL, NULL, get_id, ctx->keys); + vici_free_res(res); + } + res = vici_submit(vici_begin("get-shared"), ctx->conn); + if (res) + { + if (ctx->format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY, + stdout); + } + vici_parse_cb(res, NULL, NULL, get_id, ctx->shared); + vici_free_res(res); + } +} + +/** + * Remove a given key + */ +static bool unload_key(load_ctx_t *ctx, char *command, char *id) +{ + vici_req_t *req; + vici_res_t *res; + char buf[BUF_LEN]; + bool ret = TRUE; + + req = vici_begin(command); + + vici_add_key_valuef(req, "id", "%s", id); + + res = vici_submit(req, ctx->conn); + if (!res) + { + fprintf(stderr, "%s request failed: %s\n", command, strerror(errno)); + return FALSE; + } + if (ctx->format & COMMAND_FORMAT_RAW) + { + snprintf(buf, sizeof(buf), "%s reply", command); + vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout); + } + else if (!streq(vici_find_str(res, "no", "success"), "yes")) + { + fprintf(stderr, "unloading key '%s' failed: %s\n", + id, vici_find_str(res, "", "errmsg")); + ret = FALSE; + } + vici_free_res(res); + return ret; +} + +/** + * Remove all keys in the given hashtable using the given command + */ +static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command) +{ + enumerator_t *enumerator; + char *id; + + enumerator = ht->create_enumerator(ht); + while (enumerator->enumerate(enumerator, &id, NULL)) + { + unload_key(ctx, command, id); + } + enumerator->destroy(enumerator); +} + /** * Clear all currently loaded credentials */ @@ -687,6 +895,14 @@ int load_creds_cfg(vici_conn_t *conn, command_format_options_t format, { enumerator_t *enumerator; char *section; + load_ctx_t ctx = { + .conn = conn, + .format = format, + .noprompt = noprompt, + .cfg = cfg, + .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8), + .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8), + }; if (clear) { @@ -696,29 +912,38 @@ int load_creds_cfg(vici_conn_t *conn, command_format_options_t format, } } - load_certs(conn, format, "x509", SWANCTL_X509DIR); - load_certs(conn, format, "x509ca", SWANCTL_X509CADIR); - load_certs(conn, format, "x509ocsp", SWANCTL_X509OCSPDIR); - load_certs(conn, format, "x509aa", SWANCTL_X509AADIR); - load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR); - load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR); - load_certs(conn, format, "pubkey", SWANCTL_PUBKEYDIR); + get_creds(&ctx); + + load_certs(&ctx, "x509", SWANCTL_X509DIR); + load_certs(&ctx, "x509ca", SWANCTL_X509CADIR); + load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR); + load_certs(&ctx, "x509aa", SWANCTL_X509AADIR); + load_certs(&ctx, "x509ac", SWANCTL_X509ACDIR); + load_certs(&ctx, "x509crl", SWANCTL_X509CRLDIR); + load_certs(&ctx, "pubkey", SWANCTL_PUBKEYDIR); - load_keys(conn, format, noprompt, cfg, "private", SWANCTL_PRIVATEDIR); - load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR); - load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR); - load_keys(conn, format, noprompt, cfg, "bliss", SWANCTL_BLISSDIR); - load_keys(conn, format, noprompt, cfg, "pkcs8", SWANCTL_PKCS8DIR); + load_keys(&ctx, "private", SWANCTL_PRIVATEDIR); + load_keys(&ctx, "rsa", SWANCTL_RSADIR); + load_keys(&ctx, "ecdsa", SWANCTL_ECDSADIR); + load_keys(&ctx, "bliss", SWANCTL_BLISSDIR); + load_keys(&ctx, "pkcs8", SWANCTL_PKCS8DIR); - load_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR); + load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR); + + load_tokens(&ctx); enumerator = cfg->create_section_enumerator(cfg, "secrets"); while (enumerator->enumerate(enumerator, §ion)) { - load_secret(conn, cfg, section, format); + load_secret(&ctx, section); } enumerator->destroy(enumerator); + unload_keys(&ctx, ctx.keys, "unload-key"); + unload_keys(&ctx, ctx.shared, "unload-shared"); + + ctx.keys->destroy_function(ctx.keys, (void*)free); + ctx.shared->destroy_function(ctx.shared, (void*)free); return 0; } diff --git a/src/swanctl/commands/rekey.c b/src/swanctl/commands/rekey.c new file mode 100644 index 000000000..47a313657 --- /dev/null +++ b/src/swanctl/commands/rekey.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "command.h" + +#include <errno.h> + +static int rekey(vici_conn_t *conn) +{ + vici_req_t *req; + vici_res_t *res; + command_format_options_t format = COMMAND_FORMAT_NONE; + char *arg, *child = NULL, *ike = NULL; + int ret = 0, child_id = 0, ike_id = 0; + + while (TRUE) + { + switch (command_getopt(&arg)) + { + case 'h': + return command_usage(NULL); + case 'P': + format |= COMMAND_FORMAT_PRETTY; + /* fall through to raw */ + case 'r': + format |= COMMAND_FORMAT_RAW; + continue; + case 'c': + child = arg; + continue; + case 'i': + ike = arg; + continue; + case 'C': + child_id = atoi(arg); + continue; + case 'I': + ike_id = atoi(arg); + continue; + case EOF: + break; + default: + return command_usage("invalid --rekey option"); + } + break; + } + + req = vici_begin("rekey"); + if (child) + { + vici_add_key_valuef(req, "child", "%s", child); + } + if (ike) + { + vici_add_key_valuef(req, "ike", "%s", ike); + } + if (child_id) + { + vici_add_key_valuef(req, "child-id", "%d", child_id); + } + if (ike_id) + { + vici_add_key_valuef(req, "ike-id", "%d", ike_id); + } + res = vici_submit(req, conn); + if (!res) + { + ret = errno; + fprintf(stderr, "rekey request failed: %s\n", strerror(errno)); + return ret; + } + if (format & COMMAND_FORMAT_RAW) + { + vici_dump(res, "rekey reply", format & COMMAND_FORMAT_PRETTY, + stdout); + } + else + { + if (streq(vici_find_str(res, "no", "success"), "yes")) + { + printf("rekey completed successfully\n"); + } + else + { + fprintf(stderr, "rekey failed: %s\n", + vici_find_str(res, "", "errmsg")); + ret = 1; + } + } + vici_free_res(res); + return ret; +} + +/** + * Register the command. + */ +static void __attribute__ ((constructor))reg() +{ + command_register((command_t) { + rekey, 'R', "rekey", "rekey an SA", + {"--child <name> | --ike <name | --child-id <id> | --ike-id <id>", + "[--raw|--pretty]"}, + { + {"help", 'h', 0, "show usage information"}, + {"child", 'c', 1, "rekey by CHILD_SA name"}, + {"ike", 'i', 1, "rekey by IKE_SA name"}, + {"child-id", 'C', 1, "rekey by CHILD_SA unique identifier"}, + {"ike-id", 'I', 1, "rekey by IKE_SA unique identifier"}, + {"raw", 'r', 0, "dump raw response message"}, + {"pretty", 'P', 0, "dump raw response message in pretty print"}, + } + }); +} |