Merge branch 'vici-updates'
Adds several new features for the VICI interface and swanctl.
This commit is contained in:
@@ -8,9 +8,23 @@ strongswan-5.5.2
|
||||
draft-ietf-ipsecme-eddsa. Ed25519-based public key pairs, X.509 certificates
|
||||
and CRLs can be generated and printed by the pki tool.
|
||||
|
||||
- In-place update of cached base and delta CRLs does no leave dozens
|
||||
- In-place update of cached base and delta CRLs does not leave dozens
|
||||
of stale copies in cache memory.
|
||||
|
||||
- Several new features for the VICI interface and the swanctl utility: Querying
|
||||
specific pools, enumerating and unloading keys and shared secrets, loading
|
||||
keys and certificates from PKCS#11 tokens, the ability to initiate, install
|
||||
and uninstall connections and policies by their exact name (if multiple child
|
||||
sections in different connections share the same name), a command to initiate
|
||||
the rekeying of IKE and IPsec SAs, support for settings previously only
|
||||
supported by the old config files (plain pubkeys, dscp, certificate policies,
|
||||
IPv6 Transport Proxy Mode, NT Hash secrets, mediation extension).
|
||||
|
||||
Important: Due to issues with VICI bindings that map sub-sections to
|
||||
dictionaries the CHILD_SA sections returned via list-sas now have a unique
|
||||
name, the original name of a CHILD_SA is returned in the "name" key of its
|
||||
section.
|
||||
|
||||
|
||||
strongswan-5.5.1
|
||||
----------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2016 Tobias Brunner
|
||||
* Copyright (C) 2007-2017 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
@@ -164,7 +164,7 @@ struct private_peer_cfg_t {
|
||||
/**
|
||||
* Name of the mediation connection to mediate through
|
||||
*/
|
||||
peer_cfg_t *mediated_by;
|
||||
char *mediated_by;
|
||||
|
||||
/**
|
||||
* ID of our peer at the mediation server (= leftid of the peer's conn with
|
||||
@@ -580,7 +580,7 @@ METHOD(peer_cfg_t, is_mediation, bool,
|
||||
return this->mediation;
|
||||
}
|
||||
|
||||
METHOD(peer_cfg_t, get_mediated_by, peer_cfg_t*,
|
||||
METHOD(peer_cfg_t, get_mediated_by, char*,
|
||||
private_peer_cfg_t *this)
|
||||
{
|
||||
return this->mediated_by;
|
||||
@@ -683,7 +683,7 @@ METHOD(peer_cfg_t, equals, bool,
|
||||
auth_cfg_equal(this, other)
|
||||
#ifdef ME
|
||||
&& this->mediation == other->mediation &&
|
||||
this->mediated_by == other->mediated_by &&
|
||||
streq(this->mediated_by, other->mediated_by) &&
|
||||
(this->peer_id == other->peer_id ||
|
||||
(this->peer_id && other->peer_id &&
|
||||
this->peer_id->equals(this->peer_id, other->peer_id)))
|
||||
@@ -713,8 +713,8 @@ METHOD(peer_cfg_t, destroy, void,
|
||||
this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
|
||||
this->pools->destroy_function(this->pools, free);
|
||||
#ifdef ME
|
||||
DESTROY_IF(this->mediated_by);
|
||||
DESTROY_IF(this->peer_id);
|
||||
free(this->mediated_by);
|
||||
#endif /* ME */
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this->name);
|
||||
@@ -802,7 +802,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
|
||||
.refcount = 1,
|
||||
#ifdef ME
|
||||
.mediation = data->mediation,
|
||||
.mediated_by = data->mediated_by,
|
||||
.mediated_by = strdupnull(data->mediated_by),
|
||||
.peer_id = data->peer_id,
|
||||
#endif /* ME */
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2016 Tobias Brunner
|
||||
* Copyright (C) 2007-2017 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
@@ -319,14 +319,14 @@ struct peer_cfg_t {
|
||||
*
|
||||
* @return TRUE, if this is a mediation connection
|
||||
*/
|
||||
bool (*is_mediation) (peer_cfg_t *this);
|
||||
bool (*is_mediation)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get peer_cfg of the connection this one is mediated through.
|
||||
* Get name of the connection this one is mediated through.
|
||||
*
|
||||
* @return the peer_cfg of the mediation connection
|
||||
* @return the name of the mediation connection
|
||||
*/
|
||||
peer_cfg_t* (*get_mediated_by) (peer_cfg_t *this);
|
||||
char* (*get_mediated_by)(peer_cfg_t *this);
|
||||
|
||||
/**
|
||||
* Get the id of the other peer at the mediation server.
|
||||
@@ -338,7 +338,7 @@ struct peer_cfg_t {
|
||||
*
|
||||
* @return the id of the other peer
|
||||
*/
|
||||
identification_t* (*get_peer_id) (peer_cfg_t *this);
|
||||
identification_t* (*get_peer_id)(peer_cfg_t *this);
|
||||
#endif /* ME */
|
||||
|
||||
/**
|
||||
@@ -398,8 +398,8 @@ struct peer_cfg_create_t {
|
||||
#ifdef ME
|
||||
/** TRUE if this is a mediation connection */
|
||||
bool mediation;
|
||||
/** peer_cfg_t of the mediation connection to mediate through (adopted) */
|
||||
peer_cfg_t *mediated_by;
|
||||
/** peer_cfg_t of the mediation connection to mediate through (cloned) */
|
||||
char *mediated_by;
|
||||
/** ID that identifies our peer at the mediation server (adopted) */
|
||||
identification_t *peer_id;
|
||||
#endif /* ME */
|
||||
|
||||
@@ -79,7 +79,7 @@ static void bypass_policy_destroy(bypass_policy_t *this)
|
||||
ts = traffic_selector_create_from_subnet(this->net->clone(this->net),
|
||||
this->mask, 0, 0, 65535);
|
||||
DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts);
|
||||
charon->shunts->uninstall(charon->shunts,
|
||||
charon->shunts->uninstall(charon->shunts, "bypass-lan",
|
||||
this->cfg->get_name(this->cfg));
|
||||
this->cfg->destroy(this->cfg);
|
||||
ts->destroy(ts);
|
||||
@@ -173,7 +173,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
|
||||
cfg = child_cfg_create(name, &child);
|
||||
cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
|
||||
cfg->add_traffic_selector(cfg, TRUE, ts);
|
||||
charon->shunts->install(charon->shunts, cfg);
|
||||
charon->shunts->install(charon->shunts, "bypass-lan", cfg);
|
||||
DBG1(DBG_IKE, "installed bypass policy for %R", ts);
|
||||
|
||||
INIT(found,
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
|
||||
typedef struct private_medcli_config_t private_medcli_config_t;
|
||||
|
||||
/**
|
||||
* Name of the mediation connection
|
||||
*/
|
||||
#define MEDIATION_CONN_NAME "medcli-mediation"
|
||||
|
||||
/**
|
||||
* Private data of an medcli_config_t object
|
||||
*/
|
||||
@@ -72,36 +77,19 @@ static traffic_selector_t *ts_from_string(char *str)
|
||||
return traffic_selector_create_dynamic(0, 0, 65535);
|
||||
}
|
||||
|
||||
METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
||||
private_medcli_config_t *this, char *name)
|
||||
/**
|
||||
* Build a mediation config
|
||||
*/
|
||||
static peer_cfg_t *build_mediation_config(private_medcli_config_t *this,
|
||||
peer_cfg_create_t *defaults)
|
||||
{
|
||||
enumerator_t *e;
|
||||
peer_cfg_t *peer_cfg, *med_cfg;
|
||||
auth_cfg_t *auth;
|
||||
ike_cfg_t *ike_cfg;
|
||||
child_cfg_t *child_cfg;
|
||||
peer_cfg_t *med_cfg;
|
||||
peer_cfg_create_t peer = *defaults;
|
||||
chunk_t me, other;
|
||||
char *address, *local_net, *remote_net;
|
||||
peer_cfg_create_t peer = {
|
||||
.cert_policy = CERT_NEVER_SEND,
|
||||
.unique = UNIQUE_REPLACE,
|
||||
.keyingtries = 1,
|
||||
.rekey_time = this->rekey * 60,
|
||||
.jitter_time = this->rekey * 5,
|
||||
.over_time = this->rekey * 3,
|
||||
.dpd = this->dpd,
|
||||
.mediation = TRUE,
|
||||
};
|
||||
child_cfg_create_t child = {
|
||||
.lifetime = {
|
||||
.time = {
|
||||
.life = this->rekey * 60 + this->rekey,
|
||||
.rekey = this->rekey,
|
||||
.jitter = this->rekey
|
||||
},
|
||||
},
|
||||
.mode = MODE_TUNNEL,
|
||||
};
|
||||
char *address;
|
||||
|
||||
/* query mediation server config:
|
||||
* - build ike_cfg/peer_cfg for mediation connection on-the-fly
|
||||
@@ -120,7 +108,9 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
||||
address, IKEV2_UDP_PORT, FRAGMENTATION_NO, 0);
|
||||
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
|
||||
ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
|
||||
med_cfg = peer_cfg_create("mediation", ike_cfg, &peer);
|
||||
|
||||
peer.mediation = TRUE;
|
||||
med_cfg = peer_cfg_create(MEDIATION_CONN_NAME, ike_cfg, &peer);
|
||||
e->destroy(e);
|
||||
|
||||
auth = auth_cfg_create();
|
||||
@@ -133,6 +123,42 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
||||
auth->add(auth, AUTH_RULE_IDENTITY,
|
||||
identification_create_from_encoding(ID_KEY_ID, other));
|
||||
med_cfg->add_auth_cfg(med_cfg, auth, FALSE);
|
||||
return med_cfg;
|
||||
}
|
||||
|
||||
METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
||||
private_medcli_config_t *this, char *name)
|
||||
{
|
||||
enumerator_t *e;
|
||||
auth_cfg_t *auth;
|
||||
peer_cfg_t *peer_cfg;
|
||||
child_cfg_t *child_cfg;
|
||||
chunk_t me, other;
|
||||
char *local_net, *remote_net;
|
||||
peer_cfg_create_t peer = {
|
||||
.cert_policy = CERT_NEVER_SEND,
|
||||
.unique = UNIQUE_REPLACE,
|
||||
.keyingtries = 1,
|
||||
.rekey_time = this->rekey * 60,
|
||||
.jitter_time = this->rekey * 5,
|
||||
.over_time = this->rekey * 3,
|
||||
.dpd = this->dpd,
|
||||
};
|
||||
child_cfg_create_t child = {
|
||||
.lifetime = {
|
||||
.time = {
|
||||
.life = this->rekey * 60 + this->rekey,
|
||||
.rekey = this->rekey,
|
||||
.jitter = this->rekey
|
||||
},
|
||||
},
|
||||
.mode = MODE_TUNNEL,
|
||||
};
|
||||
|
||||
if (streq(name, "medcli-mediation"))
|
||||
{
|
||||
return build_mediation_config(this, &peer);
|
||||
}
|
||||
|
||||
/* query mediated config:
|
||||
* - use any-any ike_cfg
|
||||
@@ -150,8 +176,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
||||
DESTROY_IF(e);
|
||||
return NULL;
|
||||
}
|
||||
peer.mediation = FALSE;
|
||||
peer.mediated_by = med_cfg;
|
||||
peer.mediated_by = MEDIATION_CONN_NAME;
|
||||
peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other);
|
||||
peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer);
|
||||
|
||||
|
||||
@@ -381,12 +381,14 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
|
||||
ike = get_ike_cfg_by_id(this, ike_cfg);
|
||||
|
||||
#ifdef ME
|
||||
mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by) : NULL;
|
||||
mediated_cfg = mediated_by ? get_peer_cfg_by_id(this, mediated_by)
|
||||
: NULL;
|
||||
if (p_type)
|
||||
{
|
||||
peer_id = identification_create_from_encoding(p_type, p_data);
|
||||
}
|
||||
#endif
|
||||
#endif /* ME */
|
||||
|
||||
if (virtual)
|
||||
{
|
||||
vip = host_create_from_string(virtual, 0);
|
||||
@@ -405,7 +407,8 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
|
||||
.dpd = dpd_delay,
|
||||
#ifdef ME
|
||||
.mediation = mediation,
|
||||
.mediated_by = mediated_cfg,
|
||||
.mediated_by = mediated_cfg ?
|
||||
mediated_cfg->get_name(mediated_cfg) : NULL,
|
||||
.peer_id = peer_id,
|
||||
#endif /* ME */
|
||||
};
|
||||
@@ -443,6 +446,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
|
||||
}
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
|
||||
add_child_cfgs(this, peer_cfg, id);
|
||||
DESTROY_IF(mediated_cfg);
|
||||
return peer_cfg;
|
||||
}
|
||||
DESTROY_IF(ike);
|
||||
|
||||
@@ -642,28 +642,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
|
||||
/* force unique connections for mediation connections */
|
||||
msg->add_conn.unique = 1;
|
||||
}
|
||||
|
||||
if (msg->add_conn.ikeme.mediated_by)
|
||||
else if (msg->add_conn.ikeme.mediated_by)
|
||||
{
|
||||
peer_cfg_t *mediated_by;
|
||||
|
||||
mediated_by = charon->backends->get_peer_cfg_by_name(
|
||||
charon->backends, msg->add_conn.ikeme.mediated_by);
|
||||
if (!mediated_by)
|
||||
{
|
||||
DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
|
||||
msg->add_conn.ikeme.mediated_by);
|
||||
return NULL;
|
||||
}
|
||||
if (!mediated_by->is_mediation(mediated_by))
|
||||
{
|
||||
DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
|
||||
"no mediation connection, aborting",
|
||||
msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
|
||||
mediated_by->destroy(mediated_by);
|
||||
return NULL;
|
||||
}
|
||||
peer.mediated_by = mediated_by;
|
||||
peer.mediated_by = msg->add_conn.ikeme.mediated_by;
|
||||
if (msg->add_conn.ikeme.peerid)
|
||||
{
|
||||
peer.peer_id = identification_create_from_string(
|
||||
|
||||
@@ -641,7 +641,8 @@ static void charon_route(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
|
||||
mode = child_cfg->get_mode(child_cfg);
|
||||
if (mode == MODE_PASS || mode == MODE_DROP)
|
||||
{
|
||||
if (charon->shunts->install(charon->shunts, child_cfg))
|
||||
if (charon->shunts->install(charon->shunts,
|
||||
peer_cfg->get_name(peer_cfg), child_cfg))
|
||||
{
|
||||
fprintf(out, "'%s' shunt %N policy installed\n",
|
||||
name, ipsec_mode_names, mode);
|
||||
@@ -729,15 +730,30 @@ METHOD(stroke_control_t, route, void,
|
||||
METHOD(stroke_control_t, unroute, void,
|
||||
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
|
||||
{
|
||||
child_cfg_t *child_cfg;
|
||||
child_sa_t *child_sa;
|
||||
enumerator_t *enumerator;
|
||||
char *ns, *found = NULL;
|
||||
uint32_t id = 0;
|
||||
|
||||
if (charon->shunts->uninstall(charon->shunts, msg->unroute.name))
|
||||
enumerator = charon->shunts->create_enumerator(charon->shunts);
|
||||
while (enumerator->enumerate(enumerator, &ns, &child_cfg))
|
||||
{
|
||||
if (ns && streq(msg->unroute.name, child_cfg->get_name(child_cfg)))
|
||||
{
|
||||
found = strdup(ns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (found && charon->shunts->uninstall(charon->shunts, found,
|
||||
msg->unroute.name))
|
||||
{
|
||||
free(found);
|
||||
fprintf(out, "shunt policy '%s' uninstalled\n", msg->unroute.name);
|
||||
return;
|
||||
}
|
||||
free(found);
|
||||
|
||||
enumerator = charon->traps->create_enumerator(charon->traps);
|
||||
while (enumerator->enumerate(enumerator, NULL, &child_sa))
|
||||
|
||||
@@ -603,7 +603,7 @@ METHOD(stroke_list_t, status, void,
|
||||
/* Enumerate shunt policies */
|
||||
first = TRUE;
|
||||
enumerator = charon->shunts->create_enumerator(charon->shunts);
|
||||
while (enumerator->enumerate(enumerator, &child_cfg))
|
||||
while (enumerator->enumerate(enumerator, NULL, &child_cfg))
|
||||
{
|
||||
if (name && !streq(name, child_cfg->get_name(child_cfg)))
|
||||
{
|
||||
|
||||
@@ -235,7 +235,7 @@ static job_requeue_t add_exclude_async(entry_t *entry)
|
||||
enumerator->destroy(enumerator);
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
|
||||
charon->shunts->install(charon->shunts, child_cfg);
|
||||
charon->shunts->install(charon->shunts, "unity", child_cfg);
|
||||
child_cfg->destroy(child_cfg);
|
||||
|
||||
DBG1(DBG_IKE, "installed %N bypass policy for %R",
|
||||
@@ -310,7 +310,8 @@ static bool remove_exclude(private_unity_handler_t *this, chunk_t data)
|
||||
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
|
||||
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
|
||||
ts->destroy(ts);
|
||||
success = charon->shunts->uninstall(charon->shunts, name) && success;
|
||||
success = charon->shunts->uninstall(charon->shunts, "unity",
|
||||
name) && success;
|
||||
}
|
||||
list->destroy(list);
|
||||
return success;
|
||||
|
||||
@@ -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>
|
||||
@@ -726,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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
##
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Tobias Brunner
|
||||
* Copyright (C) 2015 Andreas Steffen
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -199,8 +200,27 @@ 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
|
||||
*/
|
||||
@@ -216,6 +236,28 @@ CALLBACK(parse_string, bool,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -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))
|
||||
{
|
||||
authority_destroy(data.authority);
|
||||
free_load_data(data);
|
||||
return FALSE;
|
||||
}
|
||||
log_authority_data(data.authority);
|
||||
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)
|
||||
{
|
||||
request->reply = create_reply("CA certificate missing: %s", name);
|
||||
free_load_data(data);
|
||||
return FALSE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
@@ -246,6 +246,28 @@ typedef struct {
|
||||
vici_message_t *reply;
|
||||
} 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
|
||||
*/
|
||||
@@ -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;
|
||||
@@ -835,6 +878,24 @@ CALLBACK(parse_uint32, bool,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -983,6 +1044,20 @@ CALLBACK(parse_tfc, bool,
|
||||
return parse_uint32(out, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -1108,28 +1183,53 @@ CALLBACK(parse_group, bool,
|
||||
return parse_id(cfg, AUTH_RULE_GROUP, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse certificate policy
|
||||
*/
|
||||
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)
|
||||
{
|
||||
vici_authority_t *authority;
|
||||
vici_cred_t *cred;
|
||||
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,
|
||||
|
||||
@@ -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,35 @@ 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 && charon->shunts->uninstall(charon->shunts, ike, child))
|
||||
{
|
||||
free(ike);
|
||||
return send_reply(this, NULL);
|
||||
}
|
||||
free(ike);
|
||||
}
|
||||
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;
|
||||
@@ -647,6 +768,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);
|
||||
|
||||
@@ -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
|
||||
@@ -54,6 +56,11 @@ struct private_vici_cred_t {
|
||||
*/
|
||||
mem_cred_t *creds;
|
||||
|
||||
/**
|
||||
* separate credential set for token PINs
|
||||
*/
|
||||
mem_cred_t *pins;
|
||||
|
||||
/**
|
||||
* cache CRLs to disk?
|
||||
*/
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,29 @@ static void add_mark(vici_builder_t *b, mark_t mark,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -105,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)
|
||||
@@ -397,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");
|
||||
@@ -425,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);
|
||||
}
|
||||
@@ -446,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);
|
||||
@@ -484,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);
|
||||
@@ -531,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);
|
||||
}
|
||||
@@ -557,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;
|
||||
}
|
||||
@@ -568,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:
|
||||
@@ -746,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);
|
||||
@@ -757,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);
|
||||
|
||||
@@ -82,8 +82,25 @@ METHOD(job_t, initiate, job_requeue_t,
|
||||
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
|
||||
|
||||
mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
|
||||
mediation_cfg->get_ref(mediation_cfg);
|
||||
mediation_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
|
||||
mediated_cfg->get_mediated_by(mediated_cfg));
|
||||
if (!mediation_cfg)
|
||||
{
|
||||
DBG1(DBG_IKE, "mediation connection '%s' not found, aborting",
|
||||
mediated_cfg->get_mediated_by(mediated_cfg));
|
||||
mediated_cfg->destroy(mediated_cfg);
|
||||
return JOB_REQUEUE_NONE;
|
||||
}
|
||||
if (!mediation_cfg->is_mediation(mediation_cfg))
|
||||
{
|
||||
DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is no "
|
||||
"mediation connection, aborting",
|
||||
mediated_cfg->get_mediated_by(mediated_cfg),
|
||||
mediated_cfg->get_name(mediated_cfg));
|
||||
mediated_cfg->destroy(mediated_cfg);
|
||||
mediation_cfg->destroy(mediation_cfg);
|
||||
return JOB_REQUEUE_NONE;
|
||||
}
|
||||
|
||||
enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg,
|
||||
TRUE);
|
||||
|
||||
@@ -68,7 +68,9 @@ METHOD(job_t, execute, job_requeue_t,
|
||||
mode = child_cfg->get_mode(child_cfg);
|
||||
if (mode == MODE_PASS || mode == MODE_DROP)
|
||||
{
|
||||
charon->shunts->install(charon->shunts, child_cfg);
|
||||
charon->shunts->install(charon->shunts,
|
||||
peer_cfg->get_name(peer_cfg),
|
||||
child_cfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ struct private_shunt_manager_t {
|
||||
shunt_manager_t public;
|
||||
|
||||
/**
|
||||
* Installed shunts, as child_cfg_t
|
||||
* Installed shunts, as entry_t
|
||||
*/
|
||||
linked_list_t *shunts;
|
||||
|
||||
@@ -56,6 +56,32 @@ struct private_shunt_manager_t {
|
||||
rwlock_condvar_t *condvar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Config entry for a shunt
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Configured namespace
|
||||
*/
|
||||
char *ns;
|
||||
|
||||
/**
|
||||
* Child config
|
||||
*/
|
||||
child_cfg_t *cfg;
|
||||
|
||||
} entry_t;
|
||||
|
||||
/**
|
||||
* Destroy a config entry
|
||||
*/
|
||||
static void entry_destroy(entry_t *this)
|
||||
{
|
||||
this->cfg->destroy(this->cfg);
|
||||
free(this->ns);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install in and out shunt policies in the kernel
|
||||
*/
|
||||
@@ -162,10 +188,10 @@ static bool install_shunt_policy(child_cfg_t *child)
|
||||
}
|
||||
|
||||
METHOD(shunt_manager_t, install, bool,
|
||||
private_shunt_manager_t *this, child_cfg_t *child)
|
||||
private_shunt_manager_t *this, char *ns, child_cfg_t *cfg)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
child_cfg_t *child_cfg;
|
||||
entry_t *entry;
|
||||
bool found = FALSE, success;
|
||||
|
||||
/* check if not already installed */
|
||||
@@ -176,9 +202,10 @@ METHOD(shunt_manager_t, install, bool,
|
||||
return FALSE;
|
||||
}
|
||||
enumerator = this->shunts->create_enumerator(this->shunts);
|
||||
while (enumerator->enumerate(enumerator, &child_cfg))
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (streq(child_cfg->get_name(child_cfg), child->get_name(child)))
|
||||
if (streq(ns, entry->ns) &&
|
||||
streq(cfg->get_name(cfg), entry->cfg->get_name(entry->cfg)))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -188,21 +215,25 @@ METHOD(shunt_manager_t, install, bool,
|
||||
if (found)
|
||||
{
|
||||
DBG1(DBG_CFG, "shunt %N policy '%s' already installed",
|
||||
ipsec_mode_names, child->get_mode(child), child->get_name(child));
|
||||
ipsec_mode_names, cfg->get_mode(cfg), cfg->get_name(cfg));
|
||||
this->lock->unlock(this->lock);
|
||||
return TRUE;
|
||||
}
|
||||
this->shunts->insert_last(this->shunts, child->get_ref(child));
|
||||
INIT(entry,
|
||||
.ns = strdupnull(ns),
|
||||
.cfg = cfg->get_ref(cfg),
|
||||
);
|
||||
this->shunts->insert_last(this->shunts, entry);
|
||||
this->installing++;
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
success = install_shunt_policy(child);
|
||||
success = install_shunt_policy(cfg);
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
if (!success)
|
||||
{
|
||||
this->shunts->remove(this->shunts, child, NULL);
|
||||
child->destroy(child);
|
||||
this->shunts->remove(this->shunts, entry, NULL);
|
||||
entry_destroy(entry);
|
||||
}
|
||||
this->installing--;
|
||||
this->condvar->signal(this->condvar);
|
||||
@@ -320,19 +351,20 @@ static void uninstall_shunt_policy(child_cfg_t *child)
|
||||
}
|
||||
|
||||
METHOD(shunt_manager_t, uninstall, bool,
|
||||
private_shunt_manager_t *this, char *name)
|
||||
private_shunt_manager_t *this, char *ns, char *name)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
child_cfg_t *child, *found = NULL;
|
||||
entry_t *entry, *found = NULL;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
enumerator = this->shunts->create_enumerator(this->shunts);
|
||||
while (enumerator->enumerate(enumerator, &child))
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (streq(name, child->get_name(child)))
|
||||
if (streq(ns, entry->ns) &&
|
||||
streq(name, entry->cfg->get_name(entry->cfg)))
|
||||
{
|
||||
this->shunts->remove_at(this->shunts, enumerator);
|
||||
found = child;
|
||||
found = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -343,8 +375,19 @@ METHOD(shunt_manager_t, uninstall, bool,
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
uninstall_shunt_policy(child);
|
||||
child->destroy(child);
|
||||
uninstall_shunt_policy(found->cfg);
|
||||
entry_destroy(found);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CALLBACK(filter_entries, bool,
|
||||
void *unused, entry_t **entry, char **ns, void **in, child_cfg_t **cfg)
|
||||
{
|
||||
if (ns)
|
||||
{
|
||||
*ns = (*entry)->ns;
|
||||
}
|
||||
*cfg = (*entry)->cfg;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -352,25 +395,26 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
|
||||
private_shunt_manager_t *this)
|
||||
{
|
||||
this->lock->read_lock(this->lock);
|
||||
return enumerator_create_cleaner(
|
||||
return enumerator_create_filter(
|
||||
this->shunts->create_enumerator(this->shunts),
|
||||
(void*)this->lock->unlock, this->lock);
|
||||
(void*)filter_entries, this->lock,
|
||||
(void*)this->lock->unlock);
|
||||
}
|
||||
|
||||
METHOD(shunt_manager_t, flush, void,
|
||||
private_shunt_manager_t *this)
|
||||
{
|
||||
child_cfg_t *child;
|
||||
entry_t *entry;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
while (this->installing)
|
||||
{
|
||||
this->condvar->wait(this->condvar, this->lock);
|
||||
}
|
||||
while (this->shunts->remove_last(this->shunts, (void**)&child) == SUCCESS)
|
||||
while (this->shunts->remove_last(this->shunts, (void**)&entry) == SUCCESS)
|
||||
{
|
||||
uninstall_shunt_policy(child);
|
||||
child->destroy(child);
|
||||
uninstall_shunt_policy(entry->cfg);
|
||||
entry_destroy(entry);
|
||||
}
|
||||
this->installing = INSTALL_DISABLED;
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Tobias Brunner
|
||||
* Copyright (C) 2015-2016 Tobias Brunner
|
||||
* Copyright (C) 2011 Andreas Steffen
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -36,23 +36,26 @@ struct shunt_manager_t {
|
||||
/**
|
||||
* Install a policy as a shunt.
|
||||
*
|
||||
* @param child child configuration to install as a shunt
|
||||
* @param ns optional namespace (e.g. name of a connection or
|
||||
* plugin), cloned
|
||||
* @param child child configuration to install as a shunt
|
||||
* @return TRUE if installed successfully
|
||||
*/
|
||||
bool (*install)(shunt_manager_t *this, child_cfg_t *child);
|
||||
bool (*install)(shunt_manager_t *this, char *ns, child_cfg_t *child);
|
||||
|
||||
/**
|
||||
* Uninstall a shunt policy.
|
||||
*
|
||||
* @param ns namespace (same as given during installation)
|
||||
* @param name name of child configuration to uninstall as a shunt
|
||||
* @return TRUE if uninstalled successfully
|
||||
*/
|
||||
bool (*uninstall)(shunt_manager_t *this, char *name);
|
||||
bool (*uninstall)(shunt_manager_t *this, char *ns, char *name);
|
||||
|
||||
/**
|
||||
* Create an enumerator over all installed shunts.
|
||||
*
|
||||
* @return enumerator over (child_sa_t)
|
||||
* @return enumerator over (char*, child_cfg_t*)
|
||||
*/
|
||||
enumerator_t* (*create_enumerator)(shunt_manager_t *this);
|
||||
|
||||
|
||||
@@ -370,14 +370,42 @@ METHOD(mem_cred_t, add_key, void,
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, remove_key, bool,
|
||||
private_mem_cred_t *this, chunk_t fp)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
private_key_t *current;
|
||||
bool found = FALSE;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
|
||||
enumerator = this->keys->create_enumerator(this->keys);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (current->has_fingerprint(current, fp))
|
||||
{
|
||||
this->keys->remove_at(this->keys, enumerator);
|
||||
current->destroy(current);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
this->lock->unlock(this->lock);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared key entry
|
||||
*/
|
||||
typedef struct {
|
||||
/* shared key */
|
||||
/** shared key */
|
||||
shared_key_t *shared;
|
||||
/* list of owners, identification_t */
|
||||
/** list of owners, identification_t */
|
||||
linked_list_t *owners;
|
||||
/** optional unique identifier */
|
||||
char *id;
|
||||
} shared_entry_t;
|
||||
|
||||
/**
|
||||
@@ -388,11 +416,12 @@ static void shared_entry_destroy(shared_entry_t *entry)
|
||||
entry->owners->destroy_offset(entry->owners,
|
||||
offsetof(identification_t, destroy));
|
||||
entry->shared->destroy(entry->shared);
|
||||
free(entry->id);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two shared key entries equal
|
||||
* Check if two shared key entries are equal (ignoring the unique identifier)
|
||||
*/
|
||||
static bool shared_entry_equals(shared_entry_t *a, shared_entry_t *b)
|
||||
{
|
||||
@@ -528,8 +557,9 @@ METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
|
||||
(void*)shared_filter, data, (void*)shared_data_destroy);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, add_shared_list, void,
|
||||
private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
|
||||
METHOD(mem_cred_t, add_shared_unique, void,
|
||||
private_mem_cred_t *this, char *id, shared_key_t *shared,
|
||||
linked_list_t* owners)
|
||||
{
|
||||
shared_entry_t *current, *new;
|
||||
enumerator_t *enumerator;
|
||||
@@ -537,6 +567,7 @@ METHOD(mem_cred_t, add_shared_list, void,
|
||||
INIT(new,
|
||||
.shared = shared,
|
||||
.owners = owners,
|
||||
.id = strdupnull(id),
|
||||
);
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
@@ -544,7 +575,10 @@ METHOD(mem_cred_t, add_shared_list, void,
|
||||
enumerator = this->shared->create_enumerator(this->shared);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (shared_entry_equals(current, new))
|
||||
/* always replace keys with the same unique identifier, only compare
|
||||
* them if both have no unique id assigned */
|
||||
if ((id && streq(id, current->id)) ||
|
||||
(!id && !current->id && shared_entry_equals(current, new)))
|
||||
{
|
||||
this->shared->remove_at(this->shared, enumerator);
|
||||
shared_entry_destroy(current);
|
||||
@@ -558,6 +592,12 @@ METHOD(mem_cred_t, add_shared_list, void,
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, add_shared_list, void,
|
||||
private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
|
||||
{
|
||||
add_shared_unique(this, NULL, shared, owners);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, add_shared, void,
|
||||
private_mem_cred_t *this, shared_key_t *shared, ...)
|
||||
{
|
||||
@@ -580,6 +620,63 @@ METHOD(mem_cred_t, add_shared, void,
|
||||
add_shared_list(this, shared, owners);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, remove_shared_unique, void,
|
||||
private_mem_cred_t *this, char *id)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
shared_entry_t *current;
|
||||
|
||||
if (!id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
|
||||
enumerator = this->shared->create_enumerator(this->shared);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (streq(id, current->id))
|
||||
{
|
||||
this->shared->remove_at(this->shared, enumerator);
|
||||
shared_entry_destroy(current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
this->lock->unlock(this->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter unique ids of shared keys (ingore secrets without unique id)
|
||||
*/
|
||||
static bool unique_filter(void *unused,
|
||||
shared_entry_t **in, char **id)
|
||||
{
|
||||
shared_entry_t *entry = *in;
|
||||
|
||||
if (!entry->id)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (id)
|
||||
{
|
||||
*id = entry->id;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, create_unique_shared_enumerator, enumerator_t*,
|
||||
private_mem_cred_t *this)
|
||||
{
|
||||
this->lock->read_lock(this->lock);
|
||||
return enumerator_create_filter(
|
||||
this->shared->create_enumerator(this->shared),
|
||||
(void*)unique_filter, this->lock,
|
||||
(void*)this->lock->unlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Certificate distribution point
|
||||
*/
|
||||
@@ -817,8 +914,12 @@ mem_cred_t *mem_cred_create()
|
||||
.get_cert_ref = _get_cert_ref,
|
||||
.add_crl = _add_crl,
|
||||
.add_key = _add_key,
|
||||
.remove_key = _remove_key,
|
||||
.add_shared = _add_shared,
|
||||
.add_shared_list = _add_shared_list,
|
||||
.add_shared_unique = _add_shared_unique,
|
||||
.remove_shared_unique = _remove_shared_unique,
|
||||
.create_unique_shared_enumerator = _create_unique_shared_enumerator,
|
||||
.add_cdp = _add_cdp,
|
||||
.replace_certs = _replace_certs,
|
||||
.replace_secrets = _replace_secrets,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* Copyright (C) 2010-2016 Tobias Brunner
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Copyright (C) 2010 revosec AG
|
||||
*
|
||||
@@ -86,6 +87,14 @@ struct mem_cred_t {
|
||||
*/
|
||||
void (*add_key)(mem_cred_t *this, private_key_t *key);
|
||||
|
||||
/**
|
||||
* Remove a private key from the credential set.
|
||||
*
|
||||
* @param fp fingerprint of the key to remove
|
||||
* @return TRUE if the key was found and removed
|
||||
*/
|
||||
bool (*remove_key)(mem_cred_t *this, chunk_t fp);
|
||||
|
||||
/**
|
||||
* Add a shared key to the credential set.
|
||||
*
|
||||
@@ -103,6 +112,33 @@ struct mem_cred_t {
|
||||
void (*add_shared_list)(mem_cred_t *this, shared_key_t *shared,
|
||||
linked_list_t *owners);
|
||||
|
||||
/**
|
||||
* Add a shared key to the credential set, associated with the given unique
|
||||
* identifier.
|
||||
*
|
||||
* If a shared key with the same id already exists it is replaced.
|
||||
*
|
||||
* @param id unique identifier of this key (cloned)
|
||||
* @param shared shared key to add, gets owned by set
|
||||
* @param ... NULL terminated list of owners (identification_t*)
|
||||
*/
|
||||
void (*add_shared_unique)(mem_cred_t *this, char *id, shared_key_t *shared,
|
||||
linked_list_t *owners);
|
||||
|
||||
/**
|
||||
* Remove a shared key by its unique identifier.
|
||||
*
|
||||
* @param id unique identifier of this key
|
||||
*/
|
||||
void (*remove_shared_unique)(mem_cred_t *this, char *id);
|
||||
|
||||
/**
|
||||
* Create an enumerator over the unique identifiers of shared keys.
|
||||
*
|
||||
* @return enumerator over char*
|
||||
*/
|
||||
enumerator_t *(*create_unique_shared_enumerator)(mem_cred_t *this);
|
||||
|
||||
/**
|
||||
* Add a certificate distribution point to the set.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ swanctl_SOURCES = \
|
||||
command.c command.h \
|
||||
commands/initiate.c \
|
||||
commands/terminate.c \
|
||||
commands/rekey.c \
|
||||
commands/redirect.c \
|
||||
commands/install.c \
|
||||
commands/list_sas.c \
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
/**
|
||||
* Maximum number of commands (+1).
|
||||
*/
|
||||
#define MAX_COMMANDS 24
|
||||
#define MAX_COMMANDS 25
|
||||
|
||||
/**
|
||||
* Maximum number of options in a command (+3)
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,40 +106,50 @@ 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"))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
map = chunk_map(token, FALSE);
|
||||
if (map)
|
||||
{
|
||||
vici_add_list_item(req, map->ptr, map->len);
|
||||
chunk_unmap(map);
|
||||
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
|
||||
{
|
||||
fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
|
||||
key, token, strerror(errno));
|
||||
ret = FALSE;
|
||||
break;
|
||||
if (!path_absolute(token))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
@@ -551,11 +568,97 @@ 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_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_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_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR);
|
||||
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(&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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -40,6 +40,9 @@ initiate a connection
|
||||
.B "\-t, \-\-terminate"
|
||||
terminate a connection
|
||||
.TP
|
||||
.B "\-R, \-\-rekey"
|
||||
rekey an SA
|
||||
.TP
|
||||
.B "\-d, \-\-redirect"
|
||||
redirect an IKE_SA
|
||||
.TP
|
||||
|
||||
+194
-10
@@ -102,6 +102,14 @@ connections.<conn>.pull = yes
|
||||
Push mode is currently supported for IKEv1, but not in IKEv2. It is used
|
||||
by a few implementations only, pull mode is recommended.
|
||||
|
||||
connections.<conn>.dscp = 000000
|
||||
Differentiated Services Field Codepoint to set on outgoing IKE packets (six
|
||||
binary digits).
|
||||
|
||||
Differentiated Services Field Codepoint to set on outgoing IKE packets for
|
||||
this connection. The value is a six digit binary encoded string specifying
|
||||
the Codepoint to set, as defined in RFC 2474.
|
||||
|
||||
connections.<conn>.encap = no
|
||||
Enforce UDP encapsulation by faking NAT-D payloads.
|
||||
|
||||
@@ -256,6 +264,30 @@ connections.<conn>.pools =
|
||||
other configuration attributes from. Each name references a pool by name
|
||||
from either the **pools** section or an external pool.
|
||||
|
||||
connections.<conn>.mediation = no
|
||||
Whether this connection is a mediation connection.
|
||||
|
||||
Whether this connection is a mediation connection, that is, whether this
|
||||
connection is used to mediate other connections using the IKEv2 Mediation
|
||||
Extension. Mediation connections create no CHILD_SA.
|
||||
|
||||
connections.<conn>.mediated_by =
|
||||
The name of the connection to mediate this connection through.
|
||||
|
||||
The name of the connection to mediate this connection through. If given, the
|
||||
connection will be mediated through the named mediation connection.
|
||||
The mediation connection must have **mediation** enabled.
|
||||
|
||||
connections.<conn>.mediation_peer =
|
||||
Identity under which the peer is registered at the mediation server.
|
||||
|
||||
Identity under which the peer is registered at the mediation server, that
|
||||
is, the IKE identity the other end of this connection uses as its local
|
||||
identity on its connection to the mediation server. This is the identity we
|
||||
request the mediation server to mediate us with. Only relevant on
|
||||
connections that set **mediated_by**. If it is not given, the remote IKE
|
||||
identity of the first authentication round of this connection will be used.
|
||||
|
||||
connections.<conn>.local<suffix> {}
|
||||
Section for a local authentication round.
|
||||
|
||||
@@ -284,6 +316,34 @@ connections.<conn>.local<suffix>.certs =
|
||||
certificate request payloads. If no appropriate CA can be located, the
|
||||
first certificate is used.
|
||||
|
||||
connections.<conn>.local<suffix>.cert<suffix> =
|
||||
Section for a certificate candidate to use for authentication.
|
||||
|
||||
Section for a certificate candidate to use for authentication. Certificates
|
||||
in _certs_ are transmitted as binary blobs, these sections offer more
|
||||
flexibility.
|
||||
|
||||
connections.<conn>.local<suffix>.cert<suffix>.file =
|
||||
Absolute path to the certificate to load.
|
||||
|
||||
Absolute path to the certificate to load. Passed as-is to the daemon, so it
|
||||
must be readable by it.
|
||||
|
||||
Configure either this or _handle_, but not both, in one section.
|
||||
|
||||
connections.<conn>.local<suffix>.cert<suffix>.handle =
|
||||
Hex-encoded CKA_ID of the certificate on a token.
|
||||
|
||||
Hex-encoded CKA_ID of the certificate on a token.
|
||||
|
||||
Configure either this or _file_, but not both, in one section.
|
||||
|
||||
connections.<conn>.local<suffix>.cert<suffix>.slot =
|
||||
Optional slot number of the token that stores the certificate.
|
||||
|
||||
connections.<conn>.local<suffix>.cert<suffix>.module =
|
||||
Optional PKCS#11 module name.
|
||||
|
||||
connections.<conn>.local<suffix>.pubkeys =
|
||||
Comma separated list of raw public key candidates to use for authentication.
|
||||
|
||||
@@ -398,6 +458,12 @@ connections.<conn>.remote<suffix>.groups =
|
||||
can be certified by different means, for example by appropriate Attribute
|
||||
Certificates or by an AAA backend involved in the authentication.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert_policy =
|
||||
Certificate policy OIDs the peer's certificate must have.
|
||||
|
||||
Comma separated list of certificate policy OIDs the peer's certificate must
|
||||
have. OIDs are specified using the numerical dotted representation.
|
||||
|
||||
connections.<conn>.remote<suffix>.certs =
|
||||
Comma separated list of certificate to accept for authentication.
|
||||
|
||||
@@ -405,6 +471,34 @@ connections.<conn>.remote<suffix>.certs =
|
||||
The certificates may use a relative path from the **swanctl** _x509_
|
||||
directory or an absolute path.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert<suffix> =
|
||||
Section for a certificate to accept for authentication.
|
||||
|
||||
Section for a certificate to accept for authentication. Certificates
|
||||
in _certs_ are transmitted as binary blobs, these sections offer more
|
||||
flexibility.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert<suffix>.file =
|
||||
Absolute path to the certificate to load.
|
||||
|
||||
Absolute path to the certificate to load. Passed as-is to the daemon, so it
|
||||
must be readable by it.
|
||||
|
||||
Configure either this or _handle_, but not both, in one section.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert<suffix>.handle =
|
||||
Hex-encoded CKA_ID of the certificate on a token.
|
||||
|
||||
Hex-encoded CKA_ID of the certificate on a token.
|
||||
|
||||
Configure either this or _file_, but not both, in one section.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert<suffix>.slot =
|
||||
Optional slot number of the token that stores the certificate.
|
||||
|
||||
connections.<conn>.remote<suffix>.cert<suffix>.module =
|
||||
Optional PKCS#11 module name.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacerts =
|
||||
Comma separated list of CA certificates to accept for authentication.
|
||||
|
||||
@@ -412,6 +506,34 @@ connections.<conn>.remote<suffix>.cacerts =
|
||||
The certificates may use a relative path from the **swanctl** _x509ca_
|
||||
directory or an absolute path.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacert<suffix> =
|
||||
Section for a CA certificate to accept for authentication.
|
||||
|
||||
Section for a CA certificate to accept for authentication. Certificates
|
||||
in _cacerts_ are transmitted as binary blobs, these sections offer more
|
||||
flexibility.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacert<suffix>.file =
|
||||
Absolute path to the certificate to load.
|
||||
|
||||
Absolute path to the certificate to load. Passed as-is to the daemon, so it
|
||||
must be readable by it.
|
||||
|
||||
Configure either this or _handle_, but not both, in one section.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacert<suffix>.handle =
|
||||
Hex-encoded CKA_ID of the CA certificate on a token.
|
||||
|
||||
Hex-encoded CKA_ID of the CA certificate on a token.
|
||||
|
||||
Configure either this or _file_, but not both, in one section.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacert<suffix>.slot =
|
||||
Optional slot number of the token that stores the CA certificate.
|
||||
|
||||
connections.<conn>.remote<suffix>.cacert<suffix>.module =
|
||||
Optional PKCS#11 module name.
|
||||
|
||||
connections.<conn>.remote<suffix>.pubkeys =
|
||||
Comma separated list of raw public keys to accept for authentication.
|
||||
|
||||
@@ -640,11 +762,13 @@ connections.<conn>.children.<child>.hostaccess = yes
|
||||
Hostaccess variable to pass to **updown** script.
|
||||
|
||||
connections.<conn>.children.<child>.mode = tunnel
|
||||
IPsec Mode to establish (_tunnel_, _transport_, _beet_, _pass_ or _drop_).
|
||||
IPsec Mode to establish (_tunnel_, _transport_, _transport_proxy_, _beet_,
|
||||
_pass_ or _drop_).
|
||||
|
||||
IPsec Mode to establish CHILD_SA with. _tunnel_ negotiates the CHILD_SA
|
||||
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. _beet_
|
||||
is the Bound End to End Tunnel mixture mode, working with fixed inner
|
||||
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode.
|
||||
_transport_proxy_ signifying the special Mobile IPv6 Transport Proxy Mode.
|
||||
_beet_ is the Bound End to End Tunnel mixture mode, working with fixed inner
|
||||
addresses without the need to include them in each packet.
|
||||
|
||||
Both _transport_ and _beet_ modes are subject to mode negotiation; _tunnel_
|
||||
@@ -815,6 +939,28 @@ secrets.eap<suffix>.id<suffix> =
|
||||
be specified, each having an _id_ prefix, if a secret is shared between
|
||||
multiple users.
|
||||
|
||||
secrets.ntlm<suffix> { # }
|
||||
NTLM secret section for a specific secret.
|
||||
|
||||
NTLM secret section for a specific secret. Each NTLM secret is defined in
|
||||
a unique section having the _ntlm_ prefix. NTLM secrets may only be used for
|
||||
EAP-MSCHAPv2 authentication.
|
||||
|
||||
secrets.ntlm<suffix>.secret =
|
||||
Value of the NTLM secret.
|
||||
|
||||
Value of the NTLM secret, which is the NT Hash of the actual secret, that
|
||||
is, MD4(UTF-16LE(secret)). The resulting 16-byte value may either be given
|
||||
as a hex encoded string with a _0x_ prefix or as a Base64 encoded string
|
||||
with a _0s_ prefix.
|
||||
|
||||
secrets.ntlm<suffix>.id<suffix> =
|
||||
Identity the NTLM secret belongs to.
|
||||
|
||||
Identity the NTLM secret belongs to. Multiple unique identities may
|
||||
be specified, each having an _id_ prefix, if a secret is shared between
|
||||
multiple users.
|
||||
|
||||
secrets.ike<suffix> { # }
|
||||
IKE preshared secret section for a specific secret.
|
||||
|
||||
@@ -880,6 +1026,22 @@ secrets.pkcs12<suffix>.file =
|
||||
secrets.pkcs12<suffix>.secret
|
||||
Value of decryption passphrase for PKCS#12 container.
|
||||
|
||||
secrets.token<suffix> { # }
|
||||
Definition for a private key that's stored on a token/smartcard.
|
||||
|
||||
secrets.token<suffix>.handle =
|
||||
Hex-encoded CKA_ID of the private key on the token.
|
||||
|
||||
secrets.token<suffix>.slot =
|
||||
Optional slot number to access the token.
|
||||
|
||||
secrets.token<suffix>.module =
|
||||
Optional PKCS#11 module name to access the token.
|
||||
|
||||
secrets.token<suffix>.pin =
|
||||
Optional PIN required to access the key on the token. If none is provided
|
||||
the user is prompted during an interactive --load-creds call.
|
||||
|
||||
pools { # }
|
||||
Section defining named pools.
|
||||
|
||||
@@ -916,18 +1078,40 @@ authorities.<name> { # }
|
||||
authorities.<name>.cacert =
|
||||
CA certificate belonging to the certification authority.
|
||||
|
||||
The certificates may use a relative path from the **swanctl** _x509ca_
|
||||
directory or an absolute path.
|
||||
CA certificate belonging to the certification authority. The certificates
|
||||
may use a relative path from the **swanctl** _x509ca_ directory or an
|
||||
absolute path.
|
||||
|
||||
Configure one of _cacert_, _file_, or _handle_ per section.
|
||||
|
||||
authorities.<name>.file =
|
||||
Absolute path to the certificate to load.
|
||||
|
||||
Absolute path to the certificate to load. Passed as-is to the daemon, so it
|
||||
must be readable by it.
|
||||
|
||||
Configure one of _cacert_, _file_, or _handle_ per section.
|
||||
|
||||
authorities.<name>.handle =
|
||||
Hex-encoded CKA_ID of the CA certificate on a token.
|
||||
|
||||
Hex-encoded CKA_ID of the CA certificate on a token.
|
||||
|
||||
Configure one of _cacert_, _file_, or _handle_ per section.
|
||||
|
||||
authorities.<name>.slot =
|
||||
Optional slot number of the token that stores the CA certificate.
|
||||
|
||||
authorities.<name>.module =
|
||||
Optional PKCS#11 module name.
|
||||
|
||||
authorities.<name>.crl_uris =
|
||||
Comma-separated list of CRL distribution points
|
||||
Comma-separated list of CRL distribution points.
|
||||
|
||||
Comma-separated list of CRL distribution points (ldap, http, or file URI)
|
||||
Comma-separated list of CRL distribution points (ldap, http, or file URI).
|
||||
|
||||
authorities.<name>.ocsp_uris =
|
||||
Comma-separated list of OCSP URIs
|
||||
|
||||
Comma-separated list of OCSP URIs
|
||||
Comma-separated list of OCSP URIs.
|
||||
|
||||
authorities.<name>.cert_uri_base =
|
||||
Defines the base URI for the Hash and URL feature supported by IKEv2.
|
||||
|
||||
Reference in New Issue
Block a user