summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/vici
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/vici')
-rw-r--r--src/libcharon/plugins/vici/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/README.md109
-rw-r--r--src/libcharon/plugins/vici/perl/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/python/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/python/vici/protocol.py13
-rw-r--r--src/libcharon/plugins/vici/python/vici/session.py6
-rw-r--r--src/libcharon/plugins/vici/ruby/Makefile.in2
-rw-r--r--src/libcharon/plugins/vici/ruby/lib/vici.rb4
-rw-r--r--src/libcharon/plugins/vici/vici_attribute.c12
-rw-r--r--src/libcharon/plugins/vici/vici_authority.c107
-rw-r--r--src/libcharon/plugins/vici/vici_config.c326
-rw-r--r--src/libcharon/plugins/vici/vici_config.h2
-rw-r--r--src/libcharon/plugins/vici/vici_control.c141
-rw-r--r--src/libcharon/plugins/vici/vici_cred.c210
-rw-r--r--src/libcharon/plugins/vici/vici_dispatcher.c6
-rw-r--r--src/libcharon/plugins/vici/vici_logger.c7
-rw-r--r--src/libcharon/plugins/vici/vici_query.c96
17 files changed, 948 insertions, 99 deletions
diff --git a/src/libcharon/plugins/vici/Makefile.in b/src/libcharon/plugins/vici/Makefile.in
index ce1520424..cdefbff79 100644
--- a/src/libcharon/plugins/vici/Makefile.in
+++ b/src/libcharon/plugins/vici/Makefile.in
@@ -456,7 +456,6 @@ exec_prefix = @exec_prefix@
fips_mode = @fips_mode@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
-h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -491,6 +490,7 @@ nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
nm_plugins = @nm_plugins@
oldincludedir = @oldincludedir@
+p_plugins = @p_plugins@
pcsclite_CFLAGS = @pcsclite_CFLAGS@
pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index 18a3ef7b5..9bda949d0 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -1,8 +1,8 @@
# The Versatile IKE Control Interface (VICI) protocol #
-The vici plugin implements the server side of an IPC protocol to configure,
-monitor and control the IKE daemon charon. It uses request/response and event
-messages to communicate over a reliable stream based transport.
+The vici _[ˈvitʃi]_ plugin implements the server side of an IPC protocol to
+configure, monitor and control the IKE daemon charon. It uses request/response
+and event messages to communicate over a reliable stream based transport.
## Transport protocol ##
@@ -258,7 +258,7 @@ Initiates an SA while streaming _control-log_ events.
{
child = <CHILD_SA configuration name to initiate>
- ike = <optional IKE_SA configuraiton name to find child under>
+ ike = <optional IKE_SA configuration name to find child under>
timeout = <timeout in ms before returning>
init-limits = <whether limits may prevent initiating the CHILD_SA>
loglevel = <loglevel to issue "control-log" events for>
@@ -283,12 +283,29 @@ Terminates an SA while streaming _control-log_ events.
loglevel = <loglevel to issue "control-log" events for>
} => {
success = <yes or no>
+ matches = <number of matched SAs>
+ terminated = <number of terminated SAs>
errmsg = <error string on failure or timeout>
}
The default timeout of 0 waits indefinitely for a result, and a timeout value
of -1 returns a result immediately.
+### rekey() ###
+
+Initiate the rekeying of an SA.
+
+ {
+ child = <rekey a CHILD_SA by configuration name>
+ ike = <rekey an IKE_SA by configuration name>
+ child-id = <rekey a CHILD_SA by its reqid>
+ ike-id = <rekey an IKE_SA by its unique id>
+ } => {
+ success = <yes or no>
+ matches = <number of matched SAs>
+ errmsg = <error string on failure>
+ }
+
### redirect() ###
Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
@@ -303,6 +320,7 @@ supported by the peer.
wildcards>
} => {
success = <yes or no>
+ matches = <number of matched SAs>
errmsg = <error string on failure>
}
@@ -312,7 +330,7 @@ Install a trap, drop or bypass policy defined by a CHILD_SA config.
{
child = <CHILD_SA configuration name to install>
- ike = <optional IKE_SA configuraiton name to find child under>
+ ike = <optional IKE_SA configuration name to find child under>
} => {
success = <yes or no>
errmsg = <error string on failure>
@@ -324,6 +342,8 @@ Uninstall a trap, drop or bypass policy defined by a CHILD_SA config.
{
child = <CHILD_SA configuration name to install>
+ ike = <optional IKE_SA configuration name to find child under,
+ if not given the first policy matching child is removed>
} => {
success = <yes or no>
errmsg = <error string on failure>
@@ -352,6 +372,7 @@ _list-policy_ events.
pass = <set to yes to list bypass policies>
trap = <set to yes to list trap policies>
child = <filter by CHILD_SA configuration name>
+ ike = <filter by IKE_SA configuration name>
} => {
# completes after streaming list-sa events
}
@@ -466,12 +487,53 @@ Load a private key into the daemon.
errmsg = <error string on failure>
}
+### unload-key() ###
+
+Unload the private key with the given key identifier.
+
+ {
+ id = <hex-encoded SHA-1 key identifier of the private key to unload>
+ } => {
+ success = <yes or no>
+ errmsg = <error string on failure>
+ }
+
+### get-keys() ###
+
+Return a list of identifiers of private keys loaded exclusively over vici, not
+including keys found in other backends.
+
+ {} => {
+ keys = [
+ <list of hex-encoded SHA-1 key identifiers>
+ ]
+ }
+
+### load-token() ###
+
+Load a private key located on a token into the daemon. Such keys may be listed
+and unloaded using the _get-keys_ and _unload-key_ commands, respectively (based
+on the key identifier derived from the public key).
+
+ {
+ handle = <hex-encoded CKA_ID of the private key on token>
+ slot = <optional slot number>
+ module = <optional PKCS#11 module>
+ pin = <optional PIN to access the key, has to be provided via other
+ means if not given>
+ } => {
+ success = <yes or no>
+ errmsg = <error string on failure>
+ id = <hex-encoded SHA-1 key identifier of the public key on success>
+ }
+
### load-shared() ###
Load a shared IKE PSK, EAP or XAuth secret into the daemon.
{
- type = <private key type, IKE|EAP|XAUTH>
+ id = <optional unique identifier of this shared key>
+ type = <shared key type, IKE|EAP|XAUTH>
data = <raw shared key data>
owners = [
<list of shared key owner identities>
@@ -481,6 +543,29 @@ Load a shared IKE PSK, EAP or XAuth secret into the daemon.
errmsg = <error string on failure>
}
+### unload-shared() ###
+
+Unload a previously loaded shared IKE PSK, EAP or XAuth secret by its unique
+identifier.
+
+ {
+ id = <unique identifier of the shared key to unload>
+ } => {
+ success = <yes or no>
+ errmsg = <error string on failure>
+ }
+
+### get-shared() ###
+
+Return a list of unique identifiers of shared keys loaded exclusively over vici,
+not including keys found in other backends.
+
+ {} => {
+ keys = [
+ <list of unique identifiers>
+ ]
+ }
+
### flush-certs() ###
Flushes the certificate cache. The optional type argument allows to flush
@@ -569,6 +654,7 @@ List the currently loaded pools.
{
leases = <set to yes to include leases>
+ name = <optional name of the pool to query>
} => {
<pool name>* = {
base = <virtual IP pool base address>
@@ -678,7 +764,8 @@ command.
<list of tasks currently handling passively>
]
child-sas = {
- <child-sa-name>* = {
+ <unique child-sa-name>* = {
+ name = <name of the CHILD_SA>
uniqueid = <unique CHILD_SA identifier>
reqid = <reqid of CHILD_SA>
state = <state string of CHILD_SA>
@@ -689,6 +776,10 @@ command.
spi-out = <hex encoded outbound SPI>
cpi-in = <hex encoded inbound CPI, if using compression>
cpi-out = <hex encoded outbound CPI, if using compression>
+ mark-in = <hex encoded inbound Netfilter mark value>
+ mark-mask-in = <hex encoded inbound Netfilter mark mask>
+ mark-out = <hex encoded outbound Netfilter mark value>
+ mark-mask-out = <hex encoded outbound Netfilter mark mask>
encr-alg = <ESP encryption algorithm name, if any>
encr-keysize = <ESP encryption key size, if applicable>
integ-alg = <ESP or AH integrity algorithm name, if any>
@@ -722,7 +813,9 @@ The _list-policy_ event is issued to stream installed policies during an active
_list-policies_ command.
{
- <child-sa-config-name> = {
+ <ike-sa-config-name/child-sa-config-name> = {
+ child = <CHILD_SA configuration name>
+ ike = <IKE_SA configuration name or namespace, if available>
mode = <policy mode, tunnel|transport|pass|drop>
local-ts = [
<list of local traffic selectors>
diff --git a/src/libcharon/plugins/vici/perl/Makefile.in b/src/libcharon/plugins/vici/perl/Makefile.in
index 523868c68..385aa9775 100644
--- a/src/libcharon/plugins/vici/perl/Makefile.in
+++ b/src/libcharon/plugins/vici/perl/Makefile.in
@@ -274,7 +274,6 @@ exec_prefix = @exec_prefix@
fips_mode = @fips_mode@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
-h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -309,6 +308,7 @@ nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
nm_plugins = @nm_plugins@
oldincludedir = @oldincludedir@
+p_plugins = @p_plugins@
pcsclite_CFLAGS = @pcsclite_CFLAGS@
pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
diff --git a/src/libcharon/plugins/vici/python/Makefile.in b/src/libcharon/plugins/vici/python/Makefile.in
index 4f1a91703..f783d7068 100644
--- a/src/libcharon/plugins/vici/python/Makefile.in
+++ b/src/libcharon/plugins/vici/python/Makefile.in
@@ -296,7 +296,6 @@ exec_prefix = @exec_prefix@
fips_mode = @fips_mode@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
-h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -331,6 +330,7 @@ nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
nm_plugins = @nm_plugins@
oldincludedir = @oldincludedir@
+p_plugins = @p_plugins@
pcsclite_CFLAGS = @pcsclite_CFLAGS@
pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
diff --git a/src/libcharon/plugins/vici/python/vici/protocol.py b/src/libcharon/plugins/vici/python/vici/protocol.py
index 4951817eb..919231d43 100644
--- a/src/libcharon/plugins/vici/python/vici/protocol.py
+++ b/src/libcharon/plugins/vici/python/vici/protocol.py
@@ -33,7 +33,10 @@ class Transport(object):
"""Ensure to read count bytes from the socket"""
data = b""
while len(data) < count:
- data += self.socket.recv(count - len(data))
+ buf = self.socket.recv(count - len(data))
+ if not buf:
+ raise socket.error('Connection closed')
+ data += buf
return data
@@ -59,7 +62,7 @@ class Packet(object):
@classmethod
def _named_request(cls, request_type, request, message=None):
- request = request.encode()
+ requestdata = request.encode("UTF-8")
payload = struct.pack("!BB", request_type, len(request)) + request
if message is not None:
return payload + message
@@ -102,12 +105,12 @@ class Message(object):
@classmethod
def serialize(cls, message):
def encode_named_type(marker, name):
- name = name.encode()
+ name = name.encode("UTF-8")
return struct.pack("!BB", marker, len(name)) + name
def encode_blob(value):
if not isinstance(value, bytes):
- value = str(value).encode()
+ value = str(value).encode("UTF-8")
return struct.pack("!H", len(value)) + value
def serialize_list(lst):
@@ -144,7 +147,7 @@ class Message(object):
def deserialize(cls, stream):
def decode_named_type(stream):
length, = struct.unpack("!B", stream.read(1))
- return stream.read(length).decode()
+ return stream.read(length).decode("UTF-8")
def decode_blob(stream):
length, = struct.unpack("!H", stream.read(2))
diff --git a/src/libcharon/plugins/vici/python/vici/session.py b/src/libcharon/plugins/vici/python/vici/session.py
index 5bd4b7c40..1383fa778 100644
--- a/src/libcharon/plugins/vici/python/vici/session.py
+++ b/src/libcharon/plugins/vici/python/vici/session.py
@@ -208,13 +208,15 @@ class Session(object):
"""
self.handler.request("unload-pool", pool_name)
- def get_pools(self):
+ def get_pools(self, options):
"""Retrieve loaded pools.
+ :param options: filter by name and/or retrieve leases (optional)
+ :type options: dict
:return: loaded pools
:rtype: dict
"""
- return self.handler.request("get-pools")
+ return self.handler.request("get-pools", options)
def listen(self, event_types):
"""Register and listen for the given events.
diff --git a/src/libcharon/plugins/vici/ruby/Makefile.in b/src/libcharon/plugins/vici/ruby/Makefile.in
index e176285a8..125f44ee1 100644
--- a/src/libcharon/plugins/vici/ruby/Makefile.in
+++ b/src/libcharon/plugins/vici/ruby/Makefile.in
@@ -274,7 +274,6 @@ exec_prefix = @exec_prefix@
fips_mode = @fips_mode@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
-h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -309,6 +308,7 @@ nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
nm_plugins = @nm_plugins@
oldincludedir = @oldincludedir@
+p_plugins = @p_plugins@
pcsclite_CFLAGS = @pcsclite_CFLAGS@
pcsclite_LIBS = @pcsclite_LIBS@
pdfdir = @pdfdir@
diff --git a/src/libcharon/plugins/vici/ruby/lib/vici.rb b/src/libcharon/plugins/vici/ruby/lib/vici.rb
index 1a95fc3dd..bcf1a17be 100644
--- a/src/libcharon/plugins/vici/ruby/lib/vici.rb
+++ b/src/libcharon/plugins/vici/ruby/lib/vici.rb
@@ -492,8 +492,8 @@ module Vici
##
# Get the currently loaded pools.
- def get_pools()
- @transp.request("get-pools").root
+ def get_pools(options)
+ @transp.request("get-pools", Message.new(options)).root
end
##
diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c
index e0d9b4ae8..4e1fa9708 100644
--- a/src/libcharon/plugins/vici/vici_attribute.c
+++ b/src/libcharon/plugins/vici/vici_attribute.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2014-2015 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2014-2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
@@ -668,10 +668,11 @@ CALLBACK(get_pools, vici_message_t*,
identification_t *uid;
host_t *lease;
bool list_leases, on;
- char buf[32];
+ char buf[32], *filter;
int i;
list_leases = message->get_bool(message, FALSE, "leases");
+ filter = message->get_str(message, NULL, "name");
builder = vici_builder_create();
@@ -679,6 +680,11 @@ CALLBACK(get_pools, vici_message_t*,
enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, &name, &pool))
{
+ if (filter && !streq(name, filter))
+ {
+ continue;
+ }
+
vips = pool->vips;
builder->begin_section(builder, name);
diff --git a/src/libcharon/plugins/vici/vici_authority.c b/src/libcharon/plugins/vici/vici_authority.c
index 94a7f68f6..0fa158b32 100644
--- a/src/libcharon/plugins/vici/vici_authority.c
+++ b/src/libcharon/plugins/vici/vici_authority.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2016 Tobias Brunner
* Copyright (C) 2015 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -199,9 +200,28 @@ typedef struct {
typedef struct {
request_data_t *request;
authority_t *authority;
+ char *handle;
+ uint32_t slot;
+ char *module;
+ char *file;
} load_data_t;
/**
+ * Clean up data associated with an authority load
+ */
+static void free_load_data(load_data_t *data)
+{
+ if (data->authority)
+ {
+ authority_destroy(data->authority);
+ }
+ free(data->handle);
+ free(data->module);
+ free(data->file);
+ free(data);
+}
+
+/**
* Parse a string
*/
CALLBACK(parse_string, bool,
@@ -217,6 +237,28 @@ CALLBACK(parse_string, bool,
}
/**
+ * Parse a uint32_t
+ */
+CALLBACK(parse_uint32, bool,
+ uint32_t *out, chunk_t v)
+{
+ char buf[16], *end;
+ u_long l;
+
+ if (!vici_stringify(v, buf, sizeof(buf)))
+ {
+ return FALSE;
+ }
+ l = strtoul(buf, &end, 0);
+ if (*end == 0)
+ {
+ *out = l;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Parse list of URIs
*/
CALLBACK(parse_uris, bool,
@@ -266,8 +308,12 @@ CALLBACK(authority_kv, bool,
load_data_t *data, vici_message_t *message, char *name, chunk_t value)
{
parse_rule_t rules[] = {
- { "cacert", parse_cacert, &data->authority->cert },
- { "cert_uri_base", parse_string, &data->authority->cert_uri_base },
+ { "cacert", parse_cacert, &data->authority->cert },
+ { "file", parse_string, &data->file },
+ { "handle", parse_string, &data->handle },
+ { "slot", parse_uint32, &data->slot },
+ { "module", parse_string, &data->module },
+ { "cert_uri_base", parse_string, &data->authority->cert_uri_base },
};
return parse_rules(rules, countof(rules), name, value,
@@ -341,21 +387,60 @@ CALLBACK(authority_sn, bool,
linked_list_t *authorities;
authority_t *authority;
vici_cred_t *cred;
+ load_data_t *data;
+ chunk_t handle;
- load_data_t data = {
+ INIT(data,
.request = request,
.authority = authority_create(name),
- };
+ .slot = -1,
+ );
DBG2(DBG_CFG, " authority %s:", name);
- if (!message->parse(message, ctx, NULL, authority_kv, authority_li, &data) ||
- !data.authority->cert)
+ if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
+ {
+ free_load_data(data);
+ return FALSE;
+ }
+ if (!data->authority->cert)
+ {
+ if (data->file)
+ {
+ data->authority->cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, data->file, BUILD_END);
+ }
+ else if (data->handle)
+ {
+ handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
+ if (data->slot != -1)
+ {
+ data->authority->cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_PKCS11_KEYID, handle,
+ BUILD_PKCS11_SLOT, data->slot,
+ data->module ? BUILD_PKCS11_MODULE : BUILD_END,
+ data->module, BUILD_END);
+ }
+ else
+ {
+ data->authority->cert = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509,
+ BUILD_PKCS11_KEYID, handle,
+ data->module ? BUILD_PKCS11_MODULE : BUILD_END,
+ data->module, BUILD_END);
+ }
+ chunk_free(&handle);
+ }
+ }
+ if (!data->authority->cert)
{
- authority_destroy(data.authority);
+ request->reply = create_reply("CA certificate missing: %s", name);
+ free_load_data(data);
return FALSE;
}
- log_authority_data(data.authority);
+ log_authority_data(data->authority);
request->this->lock->write_lock(request->this->lock);
@@ -372,12 +457,14 @@ CALLBACK(authority_sn, bool,
}
}
enumerator->destroy(enumerator);
- authorities->insert_last(authorities, data.authority);
+ authorities->insert_last(authorities, data->authority);
cred = request->this->cred;
- data.authority->cert = cred->add_cert(cred, data.authority->cert);
+ data->authority->cert = cred->add_cert(cred, data->authority->cert);
+ data->authority = NULL;
request->this->lock->unlock(request->this->lock);
+ free_load_data(data);
return TRUE;
}
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 2110fd31d..12497ec5e 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -2,7 +2,7 @@
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
- * Copyright (C) 2015-2016 Tobias Brunner
+ * Copyright (C) 2015-2017 Tobias Brunner
* Copyright (C) 2015-2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -247,6 +247,28 @@ typedef struct {
} request_data_t;
/**
+ * Certificate data
+ */
+typedef struct {
+ request_data_t *request;
+ char *handle;
+ uint32_t slot;
+ char *module;
+ char *file;
+} cert_data_t;
+
+/**
+ * Clean up certificate data
+ */
+static void free_cert_data(cert_data_t *data)
+{
+ free(data->handle);
+ free(data->module);
+ free(data->file);
+ free(data);
+}
+
+/**
* Auth config data
*/
typedef struct {
@@ -295,6 +317,12 @@ typedef struct {
uint64_t rekey_time;
uint64_t over_time;
uint64_t rand_time;
+ uint8_t dscp;
+#ifdef ME
+ bool mediation;
+ char *mediated_by;
+ identification_t *peer_id;
+#endif /* ME */
} peer_data_t;
/**
@@ -370,6 +398,7 @@ static void log_peer_data(peer_data_t *data)
DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert);
DBG2(DBG_CFG, " mobike = %u", data->mobike);
DBG2(DBG_CFG, " aggressive = %u", data->aggressive);
+ DBG2(DBG_CFG, " dscp = 0x%.2x", data->dscp);
DBG2(DBG_CFG, " encap = %u", data->encap);
DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay);
DBG2(DBG_CFG, " dpd_timeout = %llu", data->dpd_timeout);
@@ -381,6 +410,14 @@ static void log_peer_data(peer_data_t *data)
DBG2(DBG_CFG, " over_time = %llu", data->over_time);
DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
+#ifdef ME
+ DBG2(DBG_CFG, " mediation = %u", data->mediation);
+ if (data->mediated_by)
+ {
+ DBG2(DBG_CFG, " mediated_by = %s", data->mediated_by);
+ DBG2(DBG_CFG, " mediation_peer = %Y", data->peer_id);
+ }
+#endif /* ME */
if (data->vips->get_count(data->vips))
{
@@ -425,6 +462,10 @@ static void free_peer_data(peer_data_t *data)
free(data->pools);
free(data->local_addrs);
free(data->remote_addrs);
+#ifdef ME
+ free(data->mediated_by);
+ DESTROY_IF(data->peer_id);
+#endif /* ME */
}
/**
@@ -461,7 +502,8 @@ static void log_child_data(child_data_t *data, char *name)
DBG2(DBG_CFG, " updown = %s", cfg->updown);
DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess);
DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp);
- DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, cfg->mode);
+ DBG2(DBG_CFG, " mode = %N%s", ipsec_mode_names, cfg->mode,
+ cfg->proxy_mode ? "_PROXY" : "");
DBG2(DBG_CFG, " policies = %u", data->policies);
DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out);
if (data->replay_window != REPLAY_UNDEFINED)
@@ -770,20 +812,22 @@ CALLBACK(parse_bool, bool,
* Parse a ipsec_mode_t
*/
CALLBACK(parse_mode, bool,
- ipsec_mode_t *out, chunk_t v)
+ child_cfg_create_t *cfg, chunk_t v)
{
enum_map_t map[] = {
- { "tunnel", MODE_TUNNEL },
- { "transport", MODE_TRANSPORT },
- { "beet", MODE_BEET },
- { "drop", MODE_DROP },
- { "pass", MODE_PASS },
+ { "tunnel", MODE_TUNNEL },
+ { "transport", MODE_TRANSPORT },
+ { "transport_proxy", MODE_TRANSPORT },
+ { "beet", MODE_BEET },
+ { "drop", MODE_DROP },
+ { "pass", MODE_PASS },
};
int d;
if (parse_map(map, countof(map), &d, v))
{
- *out = d;
+ cfg->mode = d;
+ cfg->proxy_mode = (d == MODE_TRANSPORT) && (v.len > 9);
return TRUE;
}
return FALSE;
@@ -814,10 +858,9 @@ CALLBACK(parse_action, bool,
}
/**
- * Parse a uint32_t
+ * Parse a uint32_t with the given base
*/
-CALLBACK(parse_uint32, bool,
- uint32_t *out, chunk_t v)
+static bool parse_uint32_base(uint32_t *out, chunk_t v, int base)
{
char buf[16], *end;
u_long l;
@@ -826,7 +869,7 @@ CALLBACK(parse_uint32, bool,
{
return FALSE;
}
- l = strtoul(buf, &end, 0);
+ l = strtoul(buf, &end, base);
if (*end == 0)
{
*out = l;
@@ -836,6 +879,24 @@ CALLBACK(parse_uint32, bool,
}
/**
+ * Parse a uint32_t
+ */
+CALLBACK(parse_uint32, bool,
+ uint32_t *out, chunk_t v)
+{
+ return parse_uint32_base(out, v, 0);
+}
+
+/**
+ * Parse a uint32_t in binary encoding
+ */
+CALLBACK(parse_uint32_bin, bool,
+ uint32_t *out, chunk_t v)
+{
+ return parse_uint32_base(out, v, 2);
+}
+
+/**
* Parse a uint64_t
*/
CALLBACK(parse_uint64, bool,
@@ -984,6 +1045,20 @@ CALLBACK(parse_tfc, bool,
}
/**
+ * Parse 6-bit DSCP value
+ */
+CALLBACK(parse_dscp, bool,
+ uint8_t *out, chunk_t v)
+{
+ if (parse_uint32_bin(out, v))
+ {
+ *out = *out & 0x3f;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Parse authentication config
*/
CALLBACK(parse_auth, bool,
@@ -1109,27 +1184,52 @@ CALLBACK(parse_group, bool,
}
/**
- * Parse a certificate; add as auth rule to config
+ * Parse certificate policy
*/
-static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
+CALLBACK(parse_cert_policy, bool,
+ auth_cfg_t *cfg, chunk_t v)
+{
+ char buf[BUF_LEN];
+
+ if (!vici_stringify(v, buf, sizeof(buf)))
+ {
+ return FALSE;
+ }
+ cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(buf));
+ return TRUE;
+}
+
+/**
+ * Add a certificate as auth rule to config
+ */
+static bool add_cert(auth_data_t *auth, auth_rule_t rule, certificate_t *cert)
{
vici_authority_t *authority;
vici_cred_t *cred;
+
+ if (rule == AUTH_RULE_SUBJECT_CERT)
+ {
+ authority = auth->request->this->authority;
+ authority->check_for_hash_and_url(authority, cert);
+ }
+ cred = auth->request->this->cred;
+ cert = cred->add_cert(cred, cert);
+ auth->cfg->add(auth->cfg, rule, cert);
+ return TRUE;
+}
+
+/**
+ * Parse a certificate; add as auth rule to config
+ */
+static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
+{
certificate_t *cert;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_PEM, v, BUILD_END);
if (cert)
{
- if (rule == AUTH_RULE_SUBJECT_CERT)
- {
- authority = auth->request->this->authority;
- authority->check_for_hash_and_url(authority, cert);
- }
- cred = auth->request->this->cred;
- cert = cred->add_cert(cred, cert);
- auth->cfg->add(auth->cfg, rule, cert);
- return TRUE;
+ return add_cert(auth, rule, cert);
}
return FALSE;
}
@@ -1314,6 +1414,38 @@ CALLBACK(parse_hosts, bool,
return TRUE;
}
+#ifdef ME
+/**
+ * Parse peer ID
+ */
+CALLBACK(parse_peer_id, bool,
+ identification_t **out, chunk_t v)
+{
+ char buf[BUF_LEN];
+
+ if (!vici_stringify(v, buf, sizeof(buf)))
+ {
+ return FALSE;
+ }
+ *out = identification_create_from_string(buf);
+ return TRUE;
+}
+#endif /* ME */
+
+CALLBACK(cert_kv, bool,
+ cert_data_t *cert, vici_message_t *message, char *name, chunk_t value)
+{
+ parse_rule_t rules[] = {
+ { "handle", parse_string, &cert->handle },
+ { "slot", parse_uint32, &cert->slot },
+ { "module", parse_string, &cert->module },
+ { "file", parse_string, &cert->file },
+ };
+
+ return parse_rules(rules, countof(rules), name, value,
+ &cert->request->reply);
+}
+
CALLBACK(child_li, bool,
child_data_t *child, vici_message_t *message, char *name, chunk_t value)
{
@@ -1334,7 +1466,7 @@ CALLBACK(child_kv, bool,
parse_rule_t rules[] = {
{ "updown", parse_string, &child->cfg.updown },
{ "hostaccess", parse_bool, &child->cfg.hostaccess },
- { "mode", parse_mode, &child->cfg.mode },
+ { "mode", parse_mode, &child->cfg },
{ "policies", parse_bool, &child->policies },
{ "policies_fwd_out", parse_bool, &child->policies_fwd_out },
{ "replay_window", parse_uint32, &child->replay_window },
@@ -1369,6 +1501,7 @@ CALLBACK(auth_li, bool,
{
parse_rule_t rules[] = {
{ "groups", parse_group, auth->cfg },
+ { "cert_policy", parse_cert_policy, auth },
{ "certs", parse_certs, auth },
{ "cacerts", parse_cacerts, auth },
{ "pubkeys", parse_pubkeys, auth },
@@ -1417,6 +1550,7 @@ CALLBACK(peer_kv, bool,
{ "version", parse_uint32, &peer->version },
{ "aggressive", parse_bool, &peer->aggressive },
{ "pull", parse_bool, &peer->pull },
+ { "dscp", parse_dscp, &peer->dscp },
{ "encap", parse_bool, &peer->encap },
{ "mobike", parse_bool, &peer->mobike },
{ "dpd_delay", parse_time, &peer->dpd_delay },
@@ -1432,12 +1566,94 @@ CALLBACK(peer_kv, bool,
{ "rekey_time", parse_time, &peer->rekey_time },
{ "over_time", parse_time, &peer->over_time },
{ "rand_time", parse_time, &peer->rand_time },
+#ifdef ME
+ { "mediation", parse_bool, &peer->mediation },
+ { "mediated_by", parse_string, &peer->mediated_by },
+ { "mediation_peer", parse_peer_id, &peer->peer_id },
+#endif /* ME */
};
return parse_rules(rules, countof(rules), name, value,
&peer->request->reply);
}
+CALLBACK(auth_sn, bool,
+ auth_data_t *auth, vici_message_t *message, vici_parse_context_t *ctx,
+ char *name)
+{
+ if (strcasepfx(name, "cert") ||
+ strcasepfx(name, "cacert"))
+ {
+ cert_data_t *data;
+ auth_rule_t rule;
+ certificate_t *cert;
+ chunk_t handle;
+
+ INIT(data,
+ .request = auth->request,
+ .slot = -1,
+ );
+
+ if (!message->parse(message, ctx, NULL, cert_kv, NULL, data))
+ {
+ free_cert_data(data);
+ return FALSE;
+ }
+ if (!data->handle && !data->file)
+ {
+ auth->request->reply = create_reply("handle or file path missing: "
+ "%s", name);
+ free_cert_data(data);
+ return FALSE;
+ }
+ else if (data->handle && data->file)
+ {
+ auth->request->reply = create_reply("handle and file path given: "
+ "%s", name);
+ free_cert_data(data);
+ return FALSE;
+ }
+
+ if (data->file)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, data->file, BUILD_END);
+ }
+ else
+ {
+ handle = chunk_from_hex(chunk_from_str(data->handle), NULL);
+ if (data->slot != -1)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_X509, BUILD_PKCS11_KEYID, handle,
+ BUILD_PKCS11_SLOT, data->slot,
+ data->module ? BUILD_PKCS11_MODULE : BUILD_END,
+ data->module, BUILD_END);
+ }
+ else
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
+ CERT_X509, BUILD_PKCS11_KEYID, handle,
+ data->module ? BUILD_PKCS11_MODULE : BUILD_END,
+ data->module, BUILD_END);
+ }
+ chunk_free(&handle);
+ }
+ free_cert_data(data);
+ if (!cert)
+ {
+ auth->request->reply = create_reply("unable to load certificate: "
+ "%s", name);
+ return FALSE;
+ }
+ rule = strcasepfx(name, "cert") ? AUTH_RULE_SUBJECT_CERT
+ : AUTH_RULE_CA_CERT;
+ return add_cert(auth, rule, cert);
+ }
+ auth->request->reply = create_reply("invalid section: %s", name);
+ return FALSE;
+}
+
/**
* Check and update lifetimes
*/
@@ -1600,7 +1816,7 @@ CALLBACK(peer_sn, bool,
.cfg = auth_cfg_create(),
);
- if (!message->parse(message, ctx, NULL, auth_kv, auth_li, auth))
+ if (!message->parse(message, ctx, auth_sn, auth_kv, auth_li, auth))
{
free_auth_data(auth);
return FALSE;
@@ -1703,7 +1919,8 @@ static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
{
case MODE_PASS:
case MODE_DROP:
- charon->shunts->install(charon->shunts, child_cfg);
+ charon->shunts->install(charon->shunts,
+ peer_cfg->get_name(peer_cfg), child_cfg);
break;
default:
charon->traps->install(charon->traps, peer_cfg, child_cfg,
@@ -1724,6 +1941,7 @@ static void clear_start_action(private_vici_config_t *this, char *peer_name,
{
enumerator_t *enumerator, *children;
child_sa_t *child_sa;
+ peer_cfg_t *peer_cfg;
ike_sa_t *ike_sa;
uint32_t id = 0, others;
array_t *ids = NULL, *ikeids = NULL;
@@ -1811,13 +2029,15 @@ static void clear_start_action(private_vici_config_t *this, char *peer_name,
{
case MODE_PASS:
case MODE_DROP:
- charon->shunts->uninstall(charon->shunts, name);
+ charon->shunts->uninstall(charon->shunts, peer_name, name);
break;
default:
enumerator = charon->traps->create_enumerator(charon->traps);
- while (enumerator->enumerate(enumerator, NULL, &child_sa))
+ while (enumerator->enumerate(enumerator, &peer_cfg,
+ &child_sa))
{
- if (streq(name, child_sa->get_name(child_sa)))
+ if (streq(peer_name, peer_cfg->get_name(peer_cfg)) &&
+ streq(name, child_sa->get_name(child_sa)))
{
id = child_sa->get_reqid(child_sa);
break;
@@ -2080,12 +2300,48 @@ CALLBACK(config_sn, bool,
peer.rand_time = min(peer.over_time, peer.rand_time / 2);
}
+#ifdef ME
+ if (peer.mediation && peer.mediated_by)
+ {
+ DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
+ "at the same time, config discarded");
+ free_peer_data(&peer);
+ return FALSE;
+ }
+ if (peer.mediation)
+ { /* force unique connections for mediation connections */
+ peer.unique = UNIQUE_REPLACE;
+ }
+ else if (peer.mediated_by)
+ { /* fallback to remote identity of first auth round if peer_id is not
+ * given explicitly */
+ auth_cfg_t *cfg;
+
+ if (!peer.peer_id &&
+ peer.remote->get_first(peer.remote, (void**)&cfg) == SUCCESS)
+ {
+ peer.peer_id = cfg->get(cfg, AUTH_RULE_IDENTITY);
+ if (peer.peer_id)
+ {
+ peer.peer_id = peer.peer_id->clone(peer.peer_id);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "mediation peer missing for mediated connection, "
+ "config discarded");
+ free_peer_data(&peer);
+ return FALSE;
+ }
+ }
+ }
+#endif /* ME */
+
log_peer_data(&peer);
ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap,
peer.local_addrs, peer.local_port,
peer.remote_addrs, peer.remote_port,
- peer.fragmentation, 0);
+ peer.fragmentation, peer.dscp);
cfg = (peer_cfg_create_t){
.cert_policy = peer.send_cert,
@@ -2101,6 +2357,14 @@ CALLBACK(config_sn, bool,
.dpd = peer.dpd_delay,
.dpd_timeout = peer.dpd_timeout,
};
+#ifdef ME
+ cfg.mediation = peer.mediation;
+ if (peer.mediated_by)
+ {
+ cfg.mediated_by = peer.mediated_by;
+ cfg.peer_id = peer.peer_id->clone(peer.peer_id);
+ }
+#endif /* ME */
peer_cfg = peer_cfg_create(name, ike_cfg, &cfg);
while (peer.local->remove_first(peer.local,
diff --git a/src/libcharon/plugins/vici/vici_config.h b/src/libcharon/plugins/vici/vici_config.h
index 0c237e7de..6bff41c31 100644
--- a/src/libcharon/plugins/vici/vici_config.h
+++ b/src/libcharon/plugins/vici/vici_config.h
@@ -38,7 +38,7 @@ typedef struct vici_config_t vici_config_t;
struct vici_config_t {
/**
- * Implements a configuraiton backend.
+ * Implements a configuration backend.
*/
backend_t backend;
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 44003819a..afee649f7 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2015 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2015-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
@@ -23,6 +23,8 @@
#include <daemon.h>
#include <collections/array.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/rekey_child_sa_job.h>
#include <processing/jobs/redirect_job.h>
typedef struct private_vici_control_t private_vici_control_t;
@@ -360,6 +362,100 @@ CALLBACK(terminate, vici_message_t*,
return builder->finalize(builder);
}
+CALLBACK(rekey, vici_message_t*,
+ private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
+{
+ enumerator_t *isas, *csas;
+ char *child, *ike, *errmsg = NULL;
+ u_int child_id, ike_id, found = 0;
+ ike_sa_t *ike_sa;
+ child_sa_t *child_sa;
+ vici_builder_t *builder;
+
+ child = request->get_str(request, NULL, "child");
+ ike = request->get_str(request, NULL, "ike");
+ child_id = request->get_int(request, 0, "child-id");
+ ike_id = request->get_int(request, 0, "ike-id");
+
+ if (!child && !ike && !ike_id && !child_id)
+ {
+ return send_reply(this, "missing rekey selector");
+ }
+
+ if (ike_id)
+ {
+ DBG1(DBG_CFG, "vici rekey IKE_SA #%d", ike_id);
+ }
+ if (child_id)
+ {
+ DBG1(DBG_CFG, "vici rekey CHILD_SA #%d", child_id);
+ }
+ if (ike)
+ {
+ DBG1(DBG_CFG, "vici rekey IKE_SA '%s'", ike);
+ }
+ if (child)
+ {
+ DBG1(DBG_CFG, "vici rekey CHILD_SA '%s'", child);
+ }
+
+ isas = charon->controller->create_ike_sa_enumerator(charon->controller, TRUE);
+ while (isas->enumerate(isas, &ike_sa))
+ {
+ if (child || child_id)
+ {
+ if (ike && !streq(ike, ike_sa->get_name(ike_sa)))
+ {
+ continue;
+ }
+ if (ike_id && ike_id != ike_sa->get_unique_id(ike_sa))
+ {
+ continue;
+ }
+ csas = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (csas->enumerate(csas, &child_sa))
+ {
+ if (child && !streq(child, child_sa->get_name(child_sa)))
+ {
+ continue;
+ }
+ if (child_id && child_sa->get_unique_id(child_sa) != child_id)
+ {
+ continue;
+ }
+ lib->processor->queue_job(lib->processor,
+ (job_t*)rekey_child_sa_job_create(
+ child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE),
+ ike_sa->get_my_host(ike_sa)));
+ found++;
+ }
+ csas->destroy(csas);
+ }
+ else if ((ike && streq(ike, ike_sa->get_name(ike_sa))) ||
+ (ike_id && ike_id == ike_sa->get_unique_id(ike_sa)))
+ {
+ lib->processor->queue_job(lib->processor,
+ (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE));
+ found++;
+ }
+ }
+ isas->destroy(isas);
+
+ builder = vici_builder_create();
+ if (!found)
+ {
+ errmsg = "no matching SAs to rekey found";
+ }
+ builder->add_kv(builder, "success", errmsg ? "no" : "yes");
+ builder->add_kv(builder, "matches", "%u", found);
+ if (errmsg)
+ {
+ builder->add_kv(builder, "errmsg", "%s", errmsg);
+ }
+ return builder->finalize(builder);
+}
+
/**
* Parse a peer-ip specified, which can be a subnet in CIDR notation, a range
* or a single IP address.
@@ -494,6 +590,7 @@ CALLBACK(redirect, vici_message_t*,
errmsg = "no matching SAs to redirect found";
}
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
+ builder->add_kv(builder, "matches", "%u", found);
if (errmsg)
{
builder->add_kv(builder, "errmsg", "%s", errmsg);
@@ -565,7 +662,8 @@ CALLBACK(install, vici_message_t*,
{
case MODE_PASS:
case MODE_DROP:
- ok = charon->shunts->install(charon->shunts, child_cfg);
+ ok = charon->shunts->install(charon->shunts,
+ peer_cfg->get_name(peer_cfg), child_cfg);
break;
default:
ok = charon->traps->install(charon->traps, peer_cfg, child_cfg,
@@ -581,12 +679,15 @@ CALLBACK(install, vici_message_t*,
CALLBACK(uninstall, vici_message_t*,
private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
{
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
child_sa_t *child_sa;
enumerator_t *enumerator;
uint32_t reqid = 0;
- char *child;
+ char *child, *ike, *ns;
child = request->get_str(request, NULL, "child");
+ ike = request->get_str(request, NULL, "ike");
if (!child)
{
return send_reply(this, "missing configuration name");
@@ -594,15 +695,39 @@ CALLBACK(uninstall, vici_message_t*,
DBG1(DBG_CFG, "vici uninstall '%s'", child);
- if (charon->shunts->uninstall(charon->shunts, child))
+ if (!ike)
+ {
+ enumerator = charon->shunts->create_enumerator(charon->shunts);
+ while (enumerator->enumerate(enumerator, &ns, &child_cfg))
+ {
+ if (ns && streq(child, child_cfg->get_name(child_cfg)))
+ {
+ ike = strdup(ns);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (ike)
+ {
+ if (charon->shunts->uninstall(charon->shunts, ike, child))
+ {
+ free(ike);
+ return send_reply(this, NULL);
+ }
+ free(ike);
+ return send_reply(this, "uninstalling policy '%s' failed", child);
+ }
+ }
+ else if (charon->shunts->uninstall(charon->shunts, ike, child))
{
return send_reply(this, NULL);
}
enumerator = charon->traps->create_enumerator(charon->traps);
- while (enumerator->enumerate(enumerator, NULL, &child_sa))
+ while (enumerator->enumerate(enumerator, &peer_cfg, &child_sa))
{
- if (streq(child, child_sa->get_name(child_sa)))
+ if ((!ike || streq(ike, peer_cfg->get_name(peer_cfg))) &&
+ streq(child, child_sa->get_name(child_sa)))
{
reqid = child_sa->get_reqid(child_sa);
break;
@@ -626,6 +751,7 @@ CALLBACK(reload_settings, vici_message_t*,
{
if (lib->settings->load_files(lib->settings, lib->conf, FALSE))
{
+ charon->load_loggers(charon);
lib->plugins->reload(lib->plugins, NULL);
return send_reply(this, NULL);
}
@@ -646,6 +772,7 @@ static void manage_commands(private_vici_control_t *this, bool reg)
{
manage_command(this, "initiate", initiate, reg);
manage_command(this, "terminate", terminate, reg);
+ manage_command(this, "rekey", rekey, reg);
manage_command(this, "redirect", redirect, reg);
manage_command(this, "install", install, reg);
manage_command(this, "uninstall", uninstall, reg);
diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c
index baf285fb8..6c7c194c2 100644
--- a/src/libcharon/plugins/vici/vici_cred.c
+++ b/src/libcharon/plugins/vici/vici_cred.c
@@ -1,9 +1,11 @@
/*
+ * Copyright (C) 2015-2016 Andreas Steffen
+ * Copyright (C) 2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
- * Copyright (C) 2015-2016 Andreas Steffen
- * 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
@@ -55,6 +57,11 @@ struct private_vici_cred_t {
mem_cred_t *creds;
/**
+ * separate credential set for token PINs
+ */
+ mem_cred_t *pins;
+
+ /**
* cache CRLs to disk?
*/
bool cachecrl;
@@ -249,6 +256,139 @@ CALLBACK(load_key, vici_message_t*,
return create_reply(NULL);
}
+CALLBACK(unload_key, vici_message_t*,
+ private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
+{
+ chunk_t keyid;
+ char buf[BUF_LEN], *hex, *msg = NULL;
+
+ hex = message->get_str(message, NULL, "id");
+ if (!hex)
+ {
+ return create_reply("key id missing");
+ }
+ keyid = chunk_from_hex(chunk_from_str(hex), NULL);
+ snprintf(buf, sizeof(buf), "%+B", &keyid);
+ DBG1(DBG_CFG, "unloaded private key with id %s", buf);
+ if (this->creds->remove_key(this->creds, keyid))
+ { /* also remove any potential PIN associated with this id */
+ this->pins->remove_shared_unique(this->pins, buf);
+ }
+ else
+ {
+ msg = "key not found";
+ }
+ chunk_free(&keyid);
+ return create_reply(msg);
+}
+
+CALLBACK(get_keys, vici_message_t*,
+ private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
+{
+ vici_builder_t *builder;
+ enumerator_t *enumerator;
+ private_key_t *private;
+ chunk_t keyid;
+
+ builder = vici_builder_create();
+ builder->begin_list(builder, "keys");
+
+ enumerator = this->creds->set.create_private_enumerator(&this->creds->set,
+ KEY_ANY, NULL);
+ while (enumerator->enumerate(enumerator, &private))
+ {
+ if (private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid))
+ {
+ builder->add_li(builder, "%+B", &keyid);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ builder->end_list(builder);
+ return builder->finalize(builder);
+}
+
+CALLBACK(load_token, vici_message_t*,
+ private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
+{
+ vici_builder_t *builder;
+ private_key_t *key;
+ shared_key_t *shared = NULL;
+ identification_t *owner;
+ mem_cred_t *set = NULL;
+ chunk_t handle, fp;
+ char buf[BUF_LEN], *hex, *module, *pin, *unique = NULL;
+ int slot;
+
+ hex = message->get_str(message, NULL, "handle");
+ if (!hex)
+ {
+ return create_reply("keyid missing");
+ }
+ handle = chunk_from_hex(chunk_from_str(hex), NULL);
+ slot = message->get_int(message, -1, "slot");
+ module = message->get_str(message, NULL, "module");
+ pin = message->get_str(message, NULL, "pin");
+
+ if (pin)
+ { /* provide the pin in a temporary credential set to access the key */
+ shared = shared_key_create(SHARED_PIN, chunk_clone(chunk_from_str(pin)));
+ owner = identification_create_from_encoding(ID_KEY_ID, handle);
+ set = mem_cred_create();
+ set->add_shared(set, shared->get_ref(shared), owner, NULL);
+ lib->credmgr->add_local_set(lib->credmgr, &set->set, FALSE);
+ }
+ if (slot >= 0)
+ {
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
+ BUILD_PKCS11_KEYID, handle,
+ BUILD_PKCS11_SLOT, slot,
+ module ? BUILD_PKCS11_MODULE : BUILD_END, module,
+ BUILD_END);
+ }
+ else
+ {
+ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
+ BUILD_PKCS11_KEYID, handle,
+ module ? BUILD_PKCS11_MODULE : BUILD_END, module,
+ BUILD_END);
+ }
+ if (set)
+ {
+ lib->credmgr->remove_local_set(lib->credmgr, &set->set);
+ set->destroy(set);
+ }
+ if (!key)
+ {
+ chunk_free(&handle);
+ DESTROY_IF(shared);
+ return create_reply("loading private key from token failed");
+ }
+ builder = vici_builder_create();
+ builder->add_kv(builder, "success", "yes");
+ if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp))
+ {
+ snprintf(buf, sizeof(buf), "%+B", &fp);
+ builder->add_kv(builder, "id", "%s", buf);
+ unique = buf;
+ }
+ if (shared && unique)
+ { /* use the handle as owner, but the key identifier as unique ID */
+ owner = identification_create_from_encoding(ID_KEY_ID, handle);
+ this->pins->add_shared_unique(this->pins, unique, shared,
+ linked_list_create_with_items(owner, NULL));
+ }
+ else
+ {
+ DESTROY_IF(shared);
+ }
+ DBG1(DBG_CFG, "loaded %N private key from token", key_type_names,
+ key->get_type(key));
+ this->creds->add_key(this->creds, key);
+ chunk_free(&handle);
+ return builder->finalize(builder);
+}
+
CALLBACK(shared_owners, bool,
linked_list_t *owners, vici_message_t *message, char *name, chunk_t value)
{
@@ -271,11 +411,12 @@ CALLBACK(load_shared, vici_message_t*,
shared_key_type_t type;
linked_list_t *owners;
chunk_t data;
- char *str, buf[512] = "";
+ char *unique, *str, buf[512] = "";
enumerator_t *enumerator;
identification_t *owner;
int len;
+ unique = message->get_str(message, NULL, "id");
str = message->get_str(message, NULL, "type");
if (!str)
{
@@ -289,6 +430,10 @@ CALLBACK(load_shared, vici_message_t*,
{
type = SHARED_EAP;
}
+ else if (strcaseeq(str, "ntlm"))
+ {
+ type = SHARED_NT_HASH;
+ }
else
{
return create_reply("invalid shared key type: %s", str);
@@ -322,15 +467,59 @@ CALLBACK(load_shared, vici_message_t*,
}
enumerator->destroy(enumerator);
- DBG1(DBG_CFG, "loaded %N shared key for: %s",
- shared_key_type_names, type, buf);
+ if (unique)
+ {
+ DBG1(DBG_CFG, "loaded %N shared key with id '%s' for: %s",
+ shared_key_type_names, type, unique, buf);
+ }
+ else
+ {
+ DBG1(DBG_CFG, "loaded %N shared key for: %s",
+ shared_key_type_names, type, buf);
+ }
- this->creds->add_shared_list(this->creds,
+ this->creds->add_shared_unique(this->creds, unique,
shared_key_create(type, chunk_clone(data)), owners);
return create_reply(NULL);
}
+CALLBACK(unload_shared, vici_message_t*,
+ private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
+{
+ char *unique;
+
+ unique = message->get_str(message, NULL, "id");
+ if (!unique)
+ {
+ return create_reply("unique identifier missing");
+ }
+ DBG1(DBG_CFG, "unloaded shared key with id '%s'", unique);
+ this->creds->remove_shared_unique(this->creds, unique);
+ return create_reply(NULL);
+}
+
+CALLBACK(get_shared, vici_message_t*,
+ private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
+{
+ vici_builder_t *builder;
+ enumerator_t *enumerator;
+ char *unique;
+
+ builder = vici_builder_create();
+ builder->begin_list(builder, "keys");
+
+ enumerator = this->creds->create_unique_shared_enumerator(this->creds);
+ while (enumerator->enumerate(enumerator, &unique))
+ {
+ builder->add_li(builder, "%s", unique);
+ }
+ enumerator->destroy(enumerator);
+
+ builder->end_list(builder);
+ return builder->finalize(builder);
+}
+
CALLBACK(clear_creds, vici_message_t*,
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
{
@@ -374,7 +563,12 @@ static void manage_commands(private_vici_cred_t *this, bool reg)
manage_command(this, "flush-certs", flush_certs, reg);
manage_command(this, "load-cert", load_cert, reg);
manage_command(this, "load-key", load_key, reg);
+ manage_command(this, "unload-key", unload_key, reg);
+ manage_command(this, "get-keys", get_keys, reg);
+ manage_command(this, "load-token", load_token, reg);
manage_command(this, "load-shared", load_shared, reg);
+ manage_command(this, "unload-shared", unload_shared, reg);
+ manage_command(this, "get-shared", get_shared, reg);
}
METHOD(vici_cred_t, add_cert, certificate_t*,
@@ -390,6 +584,8 @@ METHOD(vici_cred_t, destroy, void,
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
this->creds->destroy(this->creds);
+ lib->credmgr->remove_set(lib->credmgr, &this->pins->set);
+ this->pins->destroy(this->pins);
free(this);
}
@@ -414,6 +610,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
},
.dispatcher = dispatcher,
.creds = mem_cred_create(),
+ .pins = mem_cred_create(),
);
if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns))
@@ -422,6 +619,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
DBG1(DBG_CFG, "crl caching to %s enabled", CRL_DIR);
}
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+ lib->credmgr->add_set(lib->credmgr, &this->pins->set);
manage_commands(this, TRUE);
diff --git a/src/libcharon/plugins/vici/vici_dispatcher.c b/src/libcharon/plugins/vici/vici_dispatcher.c
index ffe0d61e5..596255b91 100644
--- a/src/libcharon/plugins/vici/vici_dispatcher.c
+++ b/src/libcharon/plugins/vici/vici_dispatcher.c
@@ -471,15 +471,17 @@ METHOD(vici_dispatcher_t, manage_event, void,
METHOD(vici_dispatcher_t, has_event_listeners, bool,
private_vici_dispatcher_t *this, char *name)
{
+ event_t *event;
bool retval = FALSE;
this->mutex->lock(this->mutex);
- if (this->events->get(this->events, name))
+ event = this->events->get(this->events, name);
+ if (event)
{
/* the entry might be getting destroyed, but returning
* false positive is not a problem as a later raise_event
* will check things again. */
- retval = TRUE;
+ retval = array_count(event->clients);
}
this->mutex->unlock(this->mutex);
diff --git a/src/libcharon/plugins/vici/vici_logger.c b/src/libcharon/plugins/vici/vici_logger.c
index 6d3584ebd..8e7bcfa1c 100644
--- a/src/libcharon/plugins/vici/vici_logger.c
+++ b/src/libcharon/plugins/vici/vici_logger.c
@@ -95,6 +95,11 @@ METHOD(logger_t, log_, void,
private_vici_logger_t *this, debug_t group, level_t level, int thread,
ike_sa_t* ike_sa, const char *msg)
{
+ if (!this->dispatcher->has_event_listeners(this->dispatcher, "log"))
+ {
+ return;
+ }
+
this->mutex->lock(this->mutex);
/* avoid recursive invocations by the vici subsystem */
@@ -130,6 +135,8 @@ METHOD(logger_t, log_, void,
METHOD(logger_t, get_level, level_t,
private_vici_logger_t *this, debug_t group)
{
+ /* anything higher might produce a loop as sending messages or listening
+ * for clients might cause log messages itself */
return LEVEL_CTRL;
}
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 828b61927..c0f4e2de9 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -79,6 +79,42 @@ struct private_vici_query_t {
time_t uptime;
};
+static void add_mark(vici_builder_t *b, mark_t mark,
+ char *label, char *mask_label)
+{
+ if (mark.value | mark.mask)
+ {
+ b->add_kv(b, label, "%.8x", mark.value);
+ if (~mark.mask)
+ {
+ b->add_kv(b, mask_label, "%.8x", mark.mask);
+ }
+ }
+}
+
+/**
+ * List the mode of a CHILD_SA or config
+ */
+static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg)
+{
+ ipsec_mode_t mode;
+ char *sub_mode = "";
+
+ if (child || cfg)
+ {
+ if (!cfg)
+ {
+ cfg = child->get_config(child);
+ }
+ mode = child ? child->get_mode(child) : cfg->get_mode(cfg);
+ if (mode == MODE_TRANSPORT && cfg->use_proxy_mode(cfg))
+ { /* only report this if the negotiated mode is actually TRANSPORT */
+ sub_mode = "_PROXY";
+ }
+ b->add_kv(b, "mode", "%N%s", ipsec_mode_names, mode, sub_mode);
+ }
+}
+
/**
* List details of a CHILD_SA
*/
@@ -92,10 +128,11 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
enumerator_t *enumerator;
traffic_selector_t *ts;
+ b->add_kv(b, "name", "%s", child->get_name(child));
b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
b->add_kv(b, "reqid", "%u", child->get_reqid(child));
b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
- b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
+ list_mode(b, child, NULL);
if (child->get_state(child) == CHILD_INSTALLED ||
child->get_state(child) == CHILD_REKEYING ||
child->get_state(child) == CHILD_REKEYED)
@@ -114,6 +151,8 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
b->add_kv(b, "cpi-in", "%.4x", ntohs(child->get_cpi(child, TRUE)));
b->add_kv(b, "cpi-out", "%.4x", ntohs(child->get_cpi(child, FALSE)));
}
+ add_mark(b, child->get_mark(child, TRUE), "mark-in", "mark-mask-in");
+ add_mark(b, child->get_mark(child, FALSE), "mark-out", "mark-mask-out");
proposal = child->get_proposal(child);
if (proposal)
{
@@ -382,6 +421,7 @@ CALLBACK(list_sas, vici_message_t*,
char *ike;
u_int ike_id;
bool bl;
+ char buf[BUF_LEN];
bl = request->get_str(request, NULL, "noblock") == NULL;
ike = request->get_str(request, NULL, "ike");
@@ -410,7 +450,9 @@ CALLBACK(list_sas, vici_message_t*,
csas = ike_sa->create_child_sa_enumerator(ike_sa);
while (csas->enumerate(csas, &child_sa))
{
- b->begin_section(b, child_sa->get_name(child_sa));
+ snprintf(buf, sizeof(buf), "%s-%u", child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa));
+ b->begin_section(b, buf);
list_child(this, b, child_sa, now);
b->end_section(b);
}
@@ -431,16 +473,21 @@ CALLBACK(list_sas, vici_message_t*,
/**
* Raise a list-policy event for given CHILD_SA
*/
-static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child)
+static void raise_policy(private_vici_query_t *this, u_int id, char *ike,
+ child_sa_t *child)
{
enumerator_t *enumerator;
traffic_selector_t *ts;
vici_builder_t *b;
+ char buf[BUF_LEN];
b = vici_builder_create();
- b->begin_section(b, child->get_name(child));
+ snprintf(buf, sizeof(buf), "%s/%s", ike, child->get_name(child));
+ b->begin_section(b, buf);
+ b->add_kv(b, "child", "%s", child->get_name(child));
+ b->add_kv(b, "ike", "%s", ike);
- b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
+ list_mode(b, child, NULL);
b->begin_list(b, "local-ts");
enumerator = child->create_ts_enumerator(child, TRUE);
@@ -469,18 +516,26 @@ static void raise_policy(private_vici_query_t *this, u_int id, child_sa_t *child
/**
* Raise a list-policy event for given CHILD_SA config
*/
-static void raise_policy_cfg(private_vici_query_t *this, u_int id,
+static void raise_policy_cfg(private_vici_query_t *this, u_int id, char *ike,
child_cfg_t *cfg)
{
enumerator_t *enumerator;
linked_list_t *list;
traffic_selector_t *ts;
vici_builder_t *b;
+ char buf[BUF_LEN];
b = vici_builder_create();
- b->begin_section(b, cfg->get_name(cfg));
+ snprintf(buf, sizeof(buf), "%s%s%s", ike ? ike : "", ike ? "/" : "",
+ cfg->get_name(cfg));
+ b->begin_section(b, buf);
+ b->add_kv(b, "child", "%s", cfg->get_name(cfg));
+ if (ike)
+ {
+ b->add_kv(b, "ike", "%s", ike);
+ }
- b->add_kv(b, "mode", "%N", ipsec_mode_names, cfg->get_mode(cfg));
+ list_mode(b, NULL, cfg);
b->begin_list(b, "local-ts");
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
@@ -516,25 +571,28 @@ CALLBACK(list_policies, vici_message_t*,
enumerator_t *enumerator;
vici_builder_t *b;
child_sa_t *child_sa;
+ peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
bool drop, pass, trap;
- char *child;
+ char *child, *ike, *ns;
drop = request->get_str(request, NULL, "drop") != NULL;
pass = request->get_str(request, NULL, "pass") != NULL;
trap = request->get_str(request, NULL, "trap") != NULL;
child = request->get_str(request, NULL, "child");
+ ike = request->get_str(request, NULL, "ike");
if (trap)
{
enumerator = charon->traps->create_enumerator(charon->traps);
- while (enumerator->enumerate(enumerator, NULL, &child_sa))
+ while (enumerator->enumerate(enumerator, &peer_cfg, &child_sa))
{
- if (child && !streq(child, child_sa->get_name(child_sa)))
+ if ((ike && !streq(ike, peer_cfg->get_name(peer_cfg))) ||
+ (child && !streq(child, child_sa->get_name(child_sa))))
{
continue;
}
- raise_policy(this, id, child_sa);
+ raise_policy(this, id, peer_cfg->get_name(peer_cfg), child_sa);
}
enumerator->destroy(enumerator);
}
@@ -542,9 +600,10 @@ CALLBACK(list_policies, vici_message_t*,
if (drop || pass)
{
enumerator = charon->shunts->create_enumerator(charon->shunts);
- while (enumerator->enumerate(enumerator, &child_cfg))
+ while (enumerator->enumerate(enumerator, &ns, &child_cfg))
{
- if (child && !streq(child, child_cfg->get_name(child_cfg)))
+ if ((ike && !streq(ike, ns)) ||
+ (child && !streq(child, child_cfg->get_name(child_cfg))))
{
continue;
}
@@ -553,13 +612,13 @@ CALLBACK(list_policies, vici_message_t*,
case MODE_DROP:
if (drop)
{
- raise_policy_cfg(this, id, child_cfg);
+ raise_policy_cfg(this, id, ns, child_cfg);
}
break;
case MODE_PASS:
if (pass)
{
- raise_policy_cfg(this, id, child_cfg);
+ raise_policy_cfg(this, id, ns, child_cfg);
}
break;
default:
@@ -731,6 +790,8 @@ CALLBACK(list_conns, vici_message_t*,
peer_cfg->get_reauth_time(peer_cfg, FALSE));
b->add_kv(b, "rekey_time", "%u",
peer_cfg->get_rekey_time(peer_cfg, FALSE));
+ b->add_kv(b, "unique", "%N", unique_policy_names,
+ peer_cfg->get_unique_policy(peer_cfg));
build_auth_cfgs(peer_cfg, TRUE, b);
build_auth_cfgs(peer_cfg, FALSE, b);
@@ -742,8 +803,7 @@ CALLBACK(list_conns, vici_message_t*,
{
b->begin_section(b, child_cfg->get_name(child_cfg));
- b->add_kv(b, "mode", "%N", ipsec_mode_names,
- child_cfg->get_mode(child_cfg));
+ list_mode(b, NULL, child_cfg);
lft = child_cfg->get_lifetime(child_cfg, FALSE);
b->add_kv(b, "rekey_time", "%"PRIu64, lft->time.rekey);