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"}, +		} +	}); +}  | 
