summaryrefslogtreecommitdiff
path: root/src/swanctl/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/swanctl/commands')
-rw-r--r--src/swanctl/commands/initiate.c12
-rw-r--r--src/swanctl/commands/install.c15
-rw-r--r--src/swanctl/commands/list_pools.c14
-rw-r--r--src/swanctl/commands/list_sas.c23
-rw-r--r--src/swanctl/commands/load_authorities.c8
-rw-r--r--src/swanctl/commands/load_conns.c67
-rw-r--r--src/swanctl/commands/load_creds.c377
-rw-r--r--src/swanctl/commands/rekey.c125
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, &section))
{
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, &section))
+ {
+ 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, &section))
{
- 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"},
+ }
+ });
+}