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
|
draft-ietf-ipsecme-eddsa. Ed25519-based public key pairs, X.509 certificates
|
||||||
and CRLs can be generated and printed by the pki tool.
|
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.
|
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
|
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-2009 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
@@ -164,7 +164,7 @@ struct private_peer_cfg_t {
|
|||||||
/**
|
/**
|
||||||
* Name of the mediation connection to mediate through
|
* 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
|
* 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;
|
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)
|
private_peer_cfg_t *this)
|
||||||
{
|
{
|
||||||
return this->mediated_by;
|
return this->mediated_by;
|
||||||
@@ -683,7 +683,7 @@ METHOD(peer_cfg_t, equals, bool,
|
|||||||
auth_cfg_equal(this, other)
|
auth_cfg_equal(this, other)
|
||||||
#ifdef ME
|
#ifdef ME
|
||||||
&& this->mediation == other->mediation &&
|
&& 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 && other->peer_id &&
|
(this->peer_id && other->peer_id &&
|
||||||
this->peer_id->equals(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->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
|
||||||
this->pools->destroy_function(this->pools, free);
|
this->pools->destroy_function(this->pools, free);
|
||||||
#ifdef ME
|
#ifdef ME
|
||||||
DESTROY_IF(this->mediated_by);
|
|
||||||
DESTROY_IF(this->peer_id);
|
DESTROY_IF(this->peer_id);
|
||||||
|
free(this->mediated_by);
|
||||||
#endif /* ME */
|
#endif /* ME */
|
||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
free(this->name);
|
free(this->name);
|
||||||
@@ -802,7 +802,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
|
|||||||
.refcount = 1,
|
.refcount = 1,
|
||||||
#ifdef ME
|
#ifdef ME
|
||||||
.mediation = data->mediation,
|
.mediation = data->mediation,
|
||||||
.mediated_by = data->mediated_by,
|
.mediated_by = strdupnull(data->mediated_by),
|
||||||
.peer_id = data->peer_id,
|
.peer_id = data->peer_id,
|
||||||
#endif /* ME */
|
#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-2009 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
@@ -319,14 +319,14 @@ struct peer_cfg_t {
|
|||||||
*
|
*
|
||||||
* @return TRUE, if this is a mediation connection
|
* @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.
|
* 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
|
* @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 */
|
#endif /* ME */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -398,8 +398,8 @@ struct peer_cfg_create_t {
|
|||||||
#ifdef ME
|
#ifdef ME
|
||||||
/** TRUE if this is a mediation connection */
|
/** TRUE if this is a mediation connection */
|
||||||
bool mediation;
|
bool mediation;
|
||||||
/** peer_cfg_t of the mediation connection to mediate through (adopted) */
|
/** peer_cfg_t of the mediation connection to mediate through (cloned) */
|
||||||
peer_cfg_t *mediated_by;
|
char *mediated_by;
|
||||||
/** ID that identifies our peer at the mediation server (adopted) */
|
/** ID that identifies our peer at the mediation server (adopted) */
|
||||||
identification_t *peer_id;
|
identification_t *peer_id;
|
||||||
#endif /* ME */
|
#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),
|
ts = traffic_selector_create_from_subnet(this->net->clone(this->net),
|
||||||
this->mask, 0, 0, 65535);
|
this->mask, 0, 0, 65535);
|
||||||
DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts);
|
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->get_name(this->cfg));
|
||||||
this->cfg->destroy(this->cfg);
|
this->cfg->destroy(this->cfg);
|
||||||
ts->destroy(ts);
|
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 = child_cfg_create(name, &child);
|
||||||
cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
|
cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
|
||||||
cfg->add_traffic_selector(cfg, TRUE, 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);
|
DBG1(DBG_IKE, "installed bypass policy for %R", ts);
|
||||||
|
|
||||||
INIT(found,
|
INIT(found,
|
||||||
|
|||||||
@@ -23,6 +23,11 @@
|
|||||||
|
|
||||||
typedef struct private_medcli_config_t private_medcli_config_t;
|
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
|
* 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);
|
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;
|
enumerator_t *e;
|
||||||
peer_cfg_t *peer_cfg, *med_cfg;
|
|
||||||
auth_cfg_t *auth;
|
auth_cfg_t *auth;
|
||||||
ike_cfg_t *ike_cfg;
|
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;
|
chunk_t me, other;
|
||||||
char *address, *local_net, *remote_net;
|
char *address;
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* query mediation server config:
|
/* query mediation server config:
|
||||||
* - build ike_cfg/peer_cfg for mediation connection on-the-fly
|
* - 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);
|
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(PROTO_IKE));
|
||||||
ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(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);
|
e->destroy(e);
|
||||||
|
|
||||||
auth = auth_cfg_create();
|
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,
|
auth->add(auth, AUTH_RULE_IDENTITY,
|
||||||
identification_create_from_encoding(ID_KEY_ID, other));
|
identification_create_from_encoding(ID_KEY_ID, other));
|
||||||
med_cfg->add_auth_cfg(med_cfg, auth, FALSE);
|
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:
|
/* query mediated config:
|
||||||
* - use any-any ike_cfg
|
* - use any-any ike_cfg
|
||||||
@@ -150,8 +176,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
|
|||||||
DESTROY_IF(e);
|
DESTROY_IF(e);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
peer.mediation = FALSE;
|
peer.mediated_by = MEDIATION_CONN_NAME;
|
||||||
peer.mediated_by = med_cfg;
|
|
||||||
peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other);
|
peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other);
|
||||||
peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer);
|
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);
|
ike = get_ike_cfg_by_id(this, ike_cfg);
|
||||||
|
|
||||||
#ifdef ME
|
#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)
|
if (p_type)
|
||||||
{
|
{
|
||||||
peer_id = identification_create_from_encoding(p_type, p_data);
|
peer_id = identification_create_from_encoding(p_type, p_data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* ME */
|
||||||
|
|
||||||
if (virtual)
|
if (virtual)
|
||||||
{
|
{
|
||||||
vip = host_create_from_string(virtual, 0);
|
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,
|
.dpd = dpd_delay,
|
||||||
#ifdef ME
|
#ifdef ME
|
||||||
.mediation = mediation,
|
.mediation = mediation,
|
||||||
.mediated_by = mediated_cfg,
|
.mediated_by = mediated_cfg ?
|
||||||
|
mediated_cfg->get_name(mediated_cfg) : NULL,
|
||||||
.peer_id = peer_id,
|
.peer_id = peer_id,
|
||||||
#endif /* ME */
|
#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);
|
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
|
||||||
add_child_cfgs(this, peer_cfg, id);
|
add_child_cfgs(this, peer_cfg, id);
|
||||||
|
DESTROY_IF(mediated_cfg);
|
||||||
return peer_cfg;
|
return peer_cfg;
|
||||||
}
|
}
|
||||||
DESTROY_IF(ike);
|
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 */
|
/* force unique connections for mediation connections */
|
||||||
msg->add_conn.unique = 1;
|
msg->add_conn.unique = 1;
|
||||||
}
|
}
|
||||||
|
else if (msg->add_conn.ikeme.mediated_by)
|
||||||
if (msg->add_conn.ikeme.mediated_by)
|
|
||||||
{
|
{
|
||||||
peer_cfg_t *mediated_by;
|
peer.mediated_by = msg->add_conn.ikeme.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;
|
|
||||||
if (msg->add_conn.ikeme.peerid)
|
if (msg->add_conn.ikeme.peerid)
|
||||||
{
|
{
|
||||||
peer.peer_id = identification_create_from_string(
|
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);
|
mode = child_cfg->get_mode(child_cfg);
|
||||||
if (mode == MODE_PASS || mode == MODE_DROP)
|
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",
|
fprintf(out, "'%s' shunt %N policy installed\n",
|
||||||
name, ipsec_mode_names, mode);
|
name, ipsec_mode_names, mode);
|
||||||
@@ -729,15 +730,30 @@ METHOD(stroke_control_t, route, void,
|
|||||||
METHOD(stroke_control_t, unroute, void,
|
METHOD(stroke_control_t, unroute, void,
|
||||||
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
|
private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
|
||||||
{
|
{
|
||||||
|
child_cfg_t *child_cfg;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
|
char *ns, *found = NULL;
|
||||||
uint32_t id = 0;
|
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);
|
fprintf(out, "shunt policy '%s' uninstalled\n", msg->unroute.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
free(found);
|
||||||
|
|
||||||
enumerator = charon->traps->create_enumerator(charon->traps);
|
enumerator = charon->traps->create_enumerator(charon->traps);
|
||||||
while (enumerator->enumerate(enumerator, NULL, &child_sa))
|
while (enumerator->enumerate(enumerator, NULL, &child_sa))
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ METHOD(stroke_list_t, status, void,
|
|||||||
/* Enumerate shunt policies */
|
/* Enumerate shunt policies */
|
||||||
first = TRUE;
|
first = TRUE;
|
||||||
enumerator = charon->shunts->create_enumerator(charon->shunts);
|
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)))
|
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);
|
enumerator->destroy(enumerator);
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
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);
|
child_cfg->destroy(child_cfg);
|
||||||
|
|
||||||
DBG1(DBG_IKE, "installed %N bypass policy for %R",
|
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",
|
DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
|
||||||
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
|
configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
|
||||||
ts->destroy(ts);
|
ts->destroy(ts);
|
||||||
success = charon->shunts->uninstall(charon->shunts, name) && success;
|
success = charon->shunts->uninstall(charon->shunts, "unity",
|
||||||
|
name) && success;
|
||||||
}
|
}
|
||||||
list->destroy(list);
|
list->destroy(list);
|
||||||
return success;
|
return success;
|
||||||
|
|||||||
@@ -283,12 +283,29 @@ Terminates an SA while streaming _control-log_ events.
|
|||||||
loglevel = <loglevel to issue "control-log" events for>
|
loglevel = <loglevel to issue "control-log" events for>
|
||||||
} => {
|
} => {
|
||||||
success = <yes or no>
|
success = <yes or no>
|
||||||
|
matches = <number of matched SAs>
|
||||||
|
terminated = <number of terminated SAs>
|
||||||
errmsg = <error string on failure or timeout>
|
errmsg = <error string on failure or timeout>
|
||||||
}
|
}
|
||||||
|
|
||||||
The default timeout of 0 waits indefinitely for a result, and a timeout value
|
The default timeout of 0 waits indefinitely for a result, and a timeout value
|
||||||
of -1 returns a result immediately.
|
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() ###
|
||||||
|
|
||||||
Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
|
Redirect a client-initiated IKE_SA to another gateway. Only for IKEv2 and if
|
||||||
@@ -303,6 +320,7 @@ supported by the peer.
|
|||||||
wildcards>
|
wildcards>
|
||||||
} => {
|
} => {
|
||||||
success = <yes or no>
|
success = <yes or no>
|
||||||
|
matches = <number of matched SAs>
|
||||||
errmsg = <error string on failure>
|
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>
|
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>
|
success = <yes or no>
|
||||||
errmsg = <error string on failure>
|
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>
|
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>
|
success = <yes or no>
|
||||||
errmsg = <error string on failure>
|
errmsg = <error string on failure>
|
||||||
@@ -352,6 +372,7 @@ _list-policy_ events.
|
|||||||
pass = <set to yes to list bypass policies>
|
pass = <set to yes to list bypass policies>
|
||||||
trap = <set to yes to list trap policies>
|
trap = <set to yes to list trap policies>
|
||||||
child = <filter by CHILD_SA configuration name>
|
child = <filter by CHILD_SA configuration name>
|
||||||
|
ike = <filter by IKE_SA configuration name>
|
||||||
} => {
|
} => {
|
||||||
# completes after streaming list-sa events
|
# completes after streaming list-sa events
|
||||||
}
|
}
|
||||||
@@ -466,12 +487,53 @@ Load a private key into the daemon.
|
|||||||
errmsg = <error string on failure>
|
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-shared() ###
|
||||||
|
|
||||||
Load a shared IKE PSK, EAP or XAuth secret into the daemon.
|
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>
|
data = <raw shared key data>
|
||||||
owners = [
|
owners = [
|
||||||
<list of shared key owner identities>
|
<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>
|
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() ###
|
### flush-certs() ###
|
||||||
|
|
||||||
Flushes the certificate cache. The optional type argument allows to flush
|
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>
|
leases = <set to yes to include leases>
|
||||||
|
name = <optional name of the pool to query>
|
||||||
} => {
|
} => {
|
||||||
<pool name>* = {
|
<pool name>* = {
|
||||||
base = <virtual IP pool base address>
|
base = <virtual IP pool base address>
|
||||||
@@ -678,7 +764,8 @@ command.
|
|||||||
<list of tasks currently handling passively>
|
<list of tasks currently handling passively>
|
||||||
]
|
]
|
||||||
child-sas = {
|
child-sas = {
|
||||||
<child-sa-name>* = {
|
<unique child-sa-name>* = {
|
||||||
|
name = <name of the CHILD_SA>
|
||||||
uniqueid = <unique CHILD_SA identifier>
|
uniqueid = <unique CHILD_SA identifier>
|
||||||
reqid = <reqid of CHILD_SA>
|
reqid = <reqid of CHILD_SA>
|
||||||
state = <state string 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.
|
_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>
|
mode = <policy mode, tunnel|transport|pass|drop>
|
||||||
local-ts = [
|
local-ts = [
|
||||||
<list of local traffic selectors>
|
<list of local traffic selectors>
|
||||||
|
|||||||
@@ -208,13 +208,15 @@ class Session(object):
|
|||||||
"""
|
"""
|
||||||
self.handler.request("unload-pool", pool_name)
|
self.handler.request("unload-pool", pool_name)
|
||||||
|
|
||||||
def get_pools(self):
|
def get_pools(self, options):
|
||||||
"""Retrieve loaded pools.
|
"""Retrieve loaded pools.
|
||||||
|
|
||||||
|
:param options: filter by name and/or retrieve leases (optional)
|
||||||
|
:type options: dict
|
||||||
:return: loaded pools
|
:return: loaded pools
|
||||||
:rtype: dict
|
:rtype: dict
|
||||||
"""
|
"""
|
||||||
return self.handler.request("get-pools")
|
return self.handler.request("get-pools", options)
|
||||||
|
|
||||||
def listen(self, event_types):
|
def listen(self, event_types):
|
||||||
"""Register and listen for the given events.
|
"""Register and listen for the given events.
|
||||||
|
|||||||
@@ -492,8 +492,8 @@ module Vici
|
|||||||
|
|
||||||
##
|
##
|
||||||
# Get the currently loaded pools.
|
# Get the currently loaded pools.
|
||||||
def get_pools()
|
def get_pools(options)
|
||||||
@transp.request("get-pools").root
|
@transp.request("get-pools", Message.new(options)).root
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014-2015 Tobias Brunner
|
* Copyright (C) 2014-2016 Tobias Brunner
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Martin Willi
|
* Copyright (C) 2014 Martin Willi
|
||||||
* Copyright (C) 2014 revosec AG
|
* Copyright (C) 2014 revosec AG
|
||||||
@@ -668,10 +668,11 @@ CALLBACK(get_pools, vici_message_t*,
|
|||||||
identification_t *uid;
|
identification_t *uid;
|
||||||
host_t *lease;
|
host_t *lease;
|
||||||
bool list_leases, on;
|
bool list_leases, on;
|
||||||
char buf[32];
|
char buf[32], *filter;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
list_leases = message->get_bool(message, FALSE, "leases");
|
list_leases = message->get_bool(message, FALSE, "leases");
|
||||||
|
filter = message->get_str(message, NULL, "name");
|
||||||
|
|
||||||
builder = vici_builder_create();
|
builder = vici_builder_create();
|
||||||
|
|
||||||
@@ -679,6 +680,11 @@ CALLBACK(get_pools, vici_message_t*,
|
|||||||
enumerator = this->pools->create_enumerator(this->pools);
|
enumerator = this->pools->create_enumerator(this->pools);
|
||||||
while (enumerator->enumerate(enumerator, &name, &pool))
|
while (enumerator->enumerate(enumerator, &name, &pool))
|
||||||
{
|
{
|
||||||
|
if (filter && !streq(name, filter))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
vips = pool->vips;
|
vips = pool->vips;
|
||||||
|
|
||||||
builder->begin_section(builder, name);
|
builder->begin_section(builder, name);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2016 Tobias Brunner
|
||||||
* Copyright (C) 2015 Andreas Steffen
|
* Copyright (C) 2015 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -199,8 +200,27 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
request_data_t *request;
|
request_data_t *request;
|
||||||
authority_t *authority;
|
authority_t *authority;
|
||||||
|
char *handle;
|
||||||
|
uint32_t slot;
|
||||||
|
char *module;
|
||||||
|
char *file;
|
||||||
} load_data_t;
|
} 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
|
* Parse a string
|
||||||
*/
|
*/
|
||||||
@@ -216,6 +236,28 @@ CALLBACK(parse_string, bool,
|
|||||||
return TRUE;
|
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
|
* 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)
|
load_data_t *data, vici_message_t *message, char *name, chunk_t value)
|
||||||
{
|
{
|
||||||
parse_rule_t rules[] = {
|
parse_rule_t rules[] = {
|
||||||
{ "cacert", parse_cacert, &data->authority->cert },
|
{ "cacert", parse_cacert, &data->authority->cert },
|
||||||
{ "cert_uri_base", parse_string, &data->authority->cert_uri_base },
|
{ "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,
|
return parse_rules(rules, countof(rules), name, value,
|
||||||
@@ -341,21 +387,60 @@ CALLBACK(authority_sn, bool,
|
|||||||
linked_list_t *authorities;
|
linked_list_t *authorities;
|
||||||
authority_t *authority;
|
authority_t *authority;
|
||||||
vici_cred_t *cred;
|
vici_cred_t *cred;
|
||||||
|
load_data_t *data;
|
||||||
|
chunk_t handle;
|
||||||
|
|
||||||
load_data_t data = {
|
INIT(data,
|
||||||
.request = request,
|
.request = request,
|
||||||
.authority = authority_create(name),
|
.authority = authority_create(name),
|
||||||
};
|
.slot = -1,
|
||||||
|
);
|
||||||
|
|
||||||
DBG2(DBG_CFG, " authority %s:", name);
|
DBG2(DBG_CFG, " authority %s:", name);
|
||||||
|
|
||||||
if (!message->parse(message, ctx, NULL, authority_kv, authority_li, &data) ||
|
if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data))
|
||||||
!data.authority->cert)
|
|
||||||
{
|
{
|
||||||
authority_destroy(data.authority);
|
free_load_data(data);
|
||||||
return FALSE;
|
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);
|
request->this->lock->write_lock(request->this->lock);
|
||||||
|
|
||||||
@@ -372,12 +457,14 @@ CALLBACK(authority_sn, bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
authorities->insert_last(authorities, data.authority);
|
authorities->insert_last(authorities, data->authority);
|
||||||
|
|
||||||
cred = request->this->cred;
|
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);
|
request->this->lock->unlock(request->this->lock);
|
||||||
|
free_load_data(data);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (C) 2014 Martin Willi
|
* Copyright (C) 2014 Martin Willi
|
||||||
* Copyright (C) 2014 revosec AG
|
* Copyright (C) 2014 revosec AG
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Tobias Brunner
|
* Copyright (C) 2015-2017 Tobias Brunner
|
||||||
* Copyright (C) 2015-2016 Andreas Steffen
|
* Copyright (C) 2015-2016 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -246,6 +246,28 @@ typedef struct {
|
|||||||
vici_message_t *reply;
|
vici_message_t *reply;
|
||||||
} request_data_t;
|
} 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
|
* Auth config data
|
||||||
*/
|
*/
|
||||||
@@ -295,6 +317,12 @@ typedef struct {
|
|||||||
uint64_t rekey_time;
|
uint64_t rekey_time;
|
||||||
uint64_t over_time;
|
uint64_t over_time;
|
||||||
uint64_t rand_time;
|
uint64_t rand_time;
|
||||||
|
uint8_t dscp;
|
||||||
|
#ifdef ME
|
||||||
|
bool mediation;
|
||||||
|
char *mediated_by;
|
||||||
|
identification_t *peer_id;
|
||||||
|
#endif /* ME */
|
||||||
} peer_data_t;
|
} 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, " send_cert = %N", cert_policy_names, data->send_cert);
|
||||||
DBG2(DBG_CFG, " mobike = %u", data->mobike);
|
DBG2(DBG_CFG, " mobike = %u", data->mobike);
|
||||||
DBG2(DBG_CFG, " aggressive = %u", data->aggressive);
|
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, " encap = %u", data->encap);
|
||||||
DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay);
|
DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay);
|
||||||
DBG2(DBG_CFG, " dpd_timeout = %llu", data->dpd_timeout);
|
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, " over_time = %llu", data->over_time);
|
||||||
DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
|
DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
|
||||||
DBG2(DBG_CFG, " proposals = %#P", data->proposals);
|
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))
|
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->pools);
|
||||||
free(data->local_addrs);
|
free(data->local_addrs);
|
||||||
free(data->remote_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, " updown = %s", cfg->updown);
|
||||||
DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess);
|
DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess);
|
||||||
DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp);
|
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 = %u", data->policies);
|
||||||
DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out);
|
DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out);
|
||||||
if (data->replay_window != REPLAY_UNDEFINED)
|
if (data->replay_window != REPLAY_UNDEFINED)
|
||||||
@@ -770,20 +812,22 @@ CALLBACK(parse_bool, bool,
|
|||||||
* Parse a ipsec_mode_t
|
* Parse a ipsec_mode_t
|
||||||
*/
|
*/
|
||||||
CALLBACK(parse_mode, bool,
|
CALLBACK(parse_mode, bool,
|
||||||
ipsec_mode_t *out, chunk_t v)
|
child_cfg_create_t *cfg, chunk_t v)
|
||||||
{
|
{
|
||||||
enum_map_t map[] = {
|
enum_map_t map[] = {
|
||||||
{ "tunnel", MODE_TUNNEL },
|
{ "tunnel", MODE_TUNNEL },
|
||||||
{ "transport", MODE_TRANSPORT },
|
{ "transport", MODE_TRANSPORT },
|
||||||
{ "beet", MODE_BEET },
|
{ "transport_proxy", MODE_TRANSPORT },
|
||||||
{ "drop", MODE_DROP },
|
{ "beet", MODE_BEET },
|
||||||
{ "pass", MODE_PASS },
|
{ "drop", MODE_DROP },
|
||||||
|
{ "pass", MODE_PASS },
|
||||||
};
|
};
|
||||||
int d;
|
int d;
|
||||||
|
|
||||||
if (parse_map(map, countof(map), &d, v))
|
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 TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
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,
|
static bool parse_uint32_base(uint32_t *out, chunk_t v, int base)
|
||||||
uint32_t *out, chunk_t v)
|
|
||||||
{
|
{
|
||||||
char buf[16], *end;
|
char buf[16], *end;
|
||||||
u_long l;
|
u_long l;
|
||||||
@@ -826,7 +869,7 @@ CALLBACK(parse_uint32, bool,
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
l = strtoul(buf, &end, 0);
|
l = strtoul(buf, &end, base);
|
||||||
if (*end == 0)
|
if (*end == 0)
|
||||||
{
|
{
|
||||||
*out = l;
|
*out = l;
|
||||||
@@ -835,6 +878,24 @@ CALLBACK(parse_uint32, bool,
|
|||||||
return FALSE;
|
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
|
* Parse a uint64_t
|
||||||
*/
|
*/
|
||||||
@@ -983,6 +1044,20 @@ CALLBACK(parse_tfc, bool,
|
|||||||
return parse_uint32(out, v);
|
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
|
* Parse authentication config
|
||||||
*/
|
*/
|
||||||
@@ -1108,28 +1183,53 @@ CALLBACK(parse_group, bool,
|
|||||||
return parse_id(cfg, AUTH_RULE_GROUP, v);
|
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
|
* Parse a certificate; add as auth rule to config
|
||||||
*/
|
*/
|
||||||
static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
|
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;
|
certificate_t *cert;
|
||||||
|
|
||||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||||
BUILD_BLOB_PEM, v, BUILD_END);
|
BUILD_BLOB_PEM, v, BUILD_END);
|
||||||
if (cert)
|
if (cert)
|
||||||
{
|
{
|
||||||
if (rule == AUTH_RULE_SUBJECT_CERT)
|
return add_cert(auth, rule, 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 FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1314,6 +1414,38 @@ CALLBACK(parse_hosts, bool,
|
|||||||
return TRUE;
|
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,
|
CALLBACK(child_li, bool,
|
||||||
child_data_t *child, vici_message_t *message, char *name, chunk_t value)
|
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[] = {
|
parse_rule_t rules[] = {
|
||||||
{ "updown", parse_string, &child->cfg.updown },
|
{ "updown", parse_string, &child->cfg.updown },
|
||||||
{ "hostaccess", parse_bool, &child->cfg.hostaccess },
|
{ "hostaccess", parse_bool, &child->cfg.hostaccess },
|
||||||
{ "mode", parse_mode, &child->cfg.mode },
|
{ "mode", parse_mode, &child->cfg },
|
||||||
{ "policies", parse_bool, &child->policies },
|
{ "policies", parse_bool, &child->policies },
|
||||||
{ "policies_fwd_out", parse_bool, &child->policies_fwd_out },
|
{ "policies_fwd_out", parse_bool, &child->policies_fwd_out },
|
||||||
{ "replay_window", parse_uint32, &child->replay_window },
|
{ "replay_window", parse_uint32, &child->replay_window },
|
||||||
@@ -1369,6 +1501,7 @@ CALLBACK(auth_li, bool,
|
|||||||
{
|
{
|
||||||
parse_rule_t rules[] = {
|
parse_rule_t rules[] = {
|
||||||
{ "groups", parse_group, auth->cfg },
|
{ "groups", parse_group, auth->cfg },
|
||||||
|
{ "cert_policy", parse_cert_policy, auth },
|
||||||
{ "certs", parse_certs, auth },
|
{ "certs", parse_certs, auth },
|
||||||
{ "cacerts", parse_cacerts, auth },
|
{ "cacerts", parse_cacerts, auth },
|
||||||
{ "pubkeys", parse_pubkeys, auth },
|
{ "pubkeys", parse_pubkeys, auth },
|
||||||
@@ -1417,6 +1550,7 @@ CALLBACK(peer_kv, bool,
|
|||||||
{ "version", parse_uint32, &peer->version },
|
{ "version", parse_uint32, &peer->version },
|
||||||
{ "aggressive", parse_bool, &peer->aggressive },
|
{ "aggressive", parse_bool, &peer->aggressive },
|
||||||
{ "pull", parse_bool, &peer->pull },
|
{ "pull", parse_bool, &peer->pull },
|
||||||
|
{ "dscp", parse_dscp, &peer->dscp },
|
||||||
{ "encap", parse_bool, &peer->encap },
|
{ "encap", parse_bool, &peer->encap },
|
||||||
{ "mobike", parse_bool, &peer->mobike },
|
{ "mobike", parse_bool, &peer->mobike },
|
||||||
{ "dpd_delay", parse_time, &peer->dpd_delay },
|
{ "dpd_delay", parse_time, &peer->dpd_delay },
|
||||||
@@ -1432,12 +1566,94 @@ CALLBACK(peer_kv, bool,
|
|||||||
{ "rekey_time", parse_time, &peer->rekey_time },
|
{ "rekey_time", parse_time, &peer->rekey_time },
|
||||||
{ "over_time", parse_time, &peer->over_time },
|
{ "over_time", parse_time, &peer->over_time },
|
||||||
{ "rand_time", parse_time, &peer->rand_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,
|
return parse_rules(rules, countof(rules), name, value,
|
||||||
&peer->request->reply);
|
&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
|
* Check and update lifetimes
|
||||||
*/
|
*/
|
||||||
@@ -1600,7 +1816,7 @@ CALLBACK(peer_sn, bool,
|
|||||||
.cfg = auth_cfg_create(),
|
.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);
|
free_auth_data(auth);
|
||||||
return FALSE;
|
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_PASS:
|
||||||
case MODE_DROP:
|
case MODE_DROP:
|
||||||
charon->shunts->install(charon->shunts, child_cfg);
|
charon->shunts->install(charon->shunts,
|
||||||
|
peer_cfg->get_name(peer_cfg), child_cfg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
charon->traps->install(charon->traps, peer_cfg, child_cfg,
|
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;
|
enumerator_t *enumerator, *children;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
|
peer_cfg_t *peer_cfg;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
uint32_t id = 0, others;
|
uint32_t id = 0, others;
|
||||||
array_t *ids = NULL, *ikeids = NULL;
|
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_PASS:
|
||||||
case MODE_DROP:
|
case MODE_DROP:
|
||||||
charon->shunts->uninstall(charon->shunts, name);
|
charon->shunts->uninstall(charon->shunts, peer_name, name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
enumerator = charon->traps->create_enumerator(charon->traps);
|
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);
|
id = child_sa->get_reqid(child_sa);
|
||||||
break;
|
break;
|
||||||
@@ -2080,12 +2300,48 @@ CALLBACK(config_sn, bool,
|
|||||||
peer.rand_time = min(peer.over_time, peer.rand_time / 2);
|
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);
|
log_peer_data(&peer);
|
||||||
|
|
||||||
ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap,
|
ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap,
|
||||||
peer.local_addrs, peer.local_port,
|
peer.local_addrs, peer.local_port,
|
||||||
peer.remote_addrs, peer.remote_port,
|
peer.remote_addrs, peer.remote_port,
|
||||||
peer.fragmentation, 0);
|
peer.fragmentation, peer.dscp);
|
||||||
|
|
||||||
cfg = (peer_cfg_create_t){
|
cfg = (peer_cfg_create_t){
|
||||||
.cert_policy = peer.send_cert,
|
.cert_policy = peer.send_cert,
|
||||||
@@ -2101,6 +2357,14 @@ CALLBACK(config_sn, bool,
|
|||||||
.dpd = peer.dpd_delay,
|
.dpd = peer.dpd_delay,
|
||||||
.dpd_timeout = peer.dpd_timeout,
|
.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);
|
peer_cfg = peer_cfg_create(name, ike_cfg, &cfg);
|
||||||
|
|
||||||
while (peer.local->remove_first(peer.local,
|
while (peer.local->remove_first(peer.local,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Tobias Brunner
|
* Copyright (C) 2015-2017 Tobias Brunner
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Martin Willi
|
* Copyright (C) 2014 Martin Willi
|
||||||
* Copyright (C) 2014 revosec AG
|
* Copyright (C) 2014 revosec AG
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
#include <collections/array.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>
|
#include <processing/jobs/redirect_job.h>
|
||||||
|
|
||||||
typedef struct private_vici_control_t private_vici_control_t;
|
typedef struct private_vici_control_t private_vici_control_t;
|
||||||
@@ -360,6 +362,100 @@ CALLBACK(terminate, vici_message_t*,
|
|||||||
return builder->finalize(builder);
|
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
|
* Parse a peer-ip specified, which can be a subnet in CIDR notation, a range
|
||||||
* or a single IP address.
|
* or a single IP address.
|
||||||
@@ -494,6 +590,7 @@ CALLBACK(redirect, vici_message_t*,
|
|||||||
errmsg = "no matching SAs to redirect found";
|
errmsg = "no matching SAs to redirect found";
|
||||||
}
|
}
|
||||||
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
|
builder->add_kv(builder, "success", errmsg ? "no" : "yes");
|
||||||
|
builder->add_kv(builder, "matches", "%u", found);
|
||||||
if (errmsg)
|
if (errmsg)
|
||||||
{
|
{
|
||||||
builder->add_kv(builder, "errmsg", "%s", errmsg);
|
builder->add_kv(builder, "errmsg", "%s", errmsg);
|
||||||
@@ -565,7 +662,8 @@ CALLBACK(install, vici_message_t*,
|
|||||||
{
|
{
|
||||||
case MODE_PASS:
|
case MODE_PASS:
|
||||||
case MODE_DROP:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
ok = charon->traps->install(charon->traps, peer_cfg, child_cfg,
|
ok = charon->traps->install(charon->traps, peer_cfg, child_cfg,
|
||||||
@@ -581,12 +679,15 @@ CALLBACK(install, vici_message_t*,
|
|||||||
CALLBACK(uninstall, vici_message_t*,
|
CALLBACK(uninstall, vici_message_t*,
|
||||||
private_vici_control_t *this, char *name, u_int id, vici_message_t *request)
|
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;
|
child_sa_t *child_sa;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
uint32_t reqid = 0;
|
uint32_t reqid = 0;
|
||||||
char *child;
|
char *child, *ike, *ns;
|
||||||
|
|
||||||
child = request->get_str(request, NULL, "child");
|
child = request->get_str(request, NULL, "child");
|
||||||
|
ike = request->get_str(request, NULL, "ike");
|
||||||
if (!child)
|
if (!child)
|
||||||
{
|
{
|
||||||
return send_reply(this, "missing configuration name");
|
return send_reply(this, "missing configuration name");
|
||||||
@@ -594,15 +695,35 @@ CALLBACK(uninstall, vici_message_t*,
|
|||||||
|
|
||||||
DBG1(DBG_CFG, "vici uninstall '%s'", child);
|
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);
|
return send_reply(this, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
enumerator = charon->traps->create_enumerator(charon->traps);
|
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);
|
reqid = child_sa->get_reqid(child_sa);
|
||||||
break;
|
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, "initiate", initiate, reg);
|
||||||
manage_command(this, "terminate", terminate, reg);
|
manage_command(this, "terminate", terminate, reg);
|
||||||
|
manage_command(this, "rekey", rekey, reg);
|
||||||
manage_command(this, "redirect", redirect, reg);
|
manage_command(this, "redirect", redirect, reg);
|
||||||
manage_command(this, "install", install, reg);
|
manage_command(this, "install", install, reg);
|
||||||
manage_command(this, "uninstall", uninstall, 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 Martin Willi
|
||||||
* Copyright (C) 2014 revosec AG
|
* 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
|
* 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
|
* 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;
|
mem_cred_t *creds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* separate credential set for token PINs
|
||||||
|
*/
|
||||||
|
mem_cred_t *pins;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cache CRLs to disk?
|
* cache CRLs to disk?
|
||||||
*/
|
*/
|
||||||
@@ -249,6 +256,139 @@ CALLBACK(load_key, vici_message_t*,
|
|||||||
return create_reply(NULL);
|
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,
|
CALLBACK(shared_owners, bool,
|
||||||
linked_list_t *owners, vici_message_t *message, char *name, chunk_t value)
|
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;
|
shared_key_type_t type;
|
||||||
linked_list_t *owners;
|
linked_list_t *owners;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
char *str, buf[512] = "";
|
char *unique, *str, buf[512] = "";
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
identification_t *owner;
|
identification_t *owner;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
unique = message->get_str(message, NULL, "id");
|
||||||
str = message->get_str(message, NULL, "type");
|
str = message->get_str(message, NULL, "type");
|
||||||
if (!str)
|
if (!str)
|
||||||
{
|
{
|
||||||
@@ -289,6 +430,10 @@ CALLBACK(load_shared, vici_message_t*,
|
|||||||
{
|
{
|
||||||
type = SHARED_EAP;
|
type = SHARED_EAP;
|
||||||
}
|
}
|
||||||
|
else if (strcaseeq(str, "ntlm"))
|
||||||
|
{
|
||||||
|
type = SHARED_NT_HASH;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return create_reply("invalid shared key type: %s", str);
|
return create_reply("invalid shared key type: %s", str);
|
||||||
@@ -322,15 +467,59 @@ CALLBACK(load_shared, vici_message_t*,
|
|||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
DBG1(DBG_CFG, "loaded %N shared key for: %s",
|
if (unique)
|
||||||
shared_key_type_names, type, buf);
|
{
|
||||||
|
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);
|
shared_key_create(type, chunk_clone(data)), owners);
|
||||||
|
|
||||||
return create_reply(NULL);
|
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*,
|
CALLBACK(clear_creds, vici_message_t*,
|
||||||
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
|
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, "flush-certs", flush_certs, reg);
|
||||||
manage_command(this, "load-cert", load_cert, reg);
|
manage_command(this, "load-cert", load_cert, reg);
|
||||||
manage_command(this, "load-key", load_key, 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, "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*,
|
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);
|
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
|
||||||
this->creds->destroy(this->creds);
|
this->creds->destroy(this->creds);
|
||||||
|
lib->credmgr->remove_set(lib->credmgr, &this->pins->set);
|
||||||
|
this->pins->destroy(this->pins);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,6 +610,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
|
|||||||
},
|
},
|
||||||
.dispatcher = dispatcher,
|
.dispatcher = dispatcher,
|
||||||
.creds = mem_cred_create(),
|
.creds = mem_cred_create(),
|
||||||
|
.pins = mem_cred_create(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns))
|
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);
|
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->creds->set);
|
||||||
|
lib->credmgr->add_set(lib->credmgr, &this->pins->set);
|
||||||
|
|
||||||
manage_commands(this, TRUE);
|
manage_commands(this, TRUE);
|
||||||
|
|
||||||
|
|||||||
@@ -471,15 +471,17 @@ METHOD(vici_dispatcher_t, manage_event, void,
|
|||||||
METHOD(vici_dispatcher_t, has_event_listeners, bool,
|
METHOD(vici_dispatcher_t, has_event_listeners, bool,
|
||||||
private_vici_dispatcher_t *this, char *name)
|
private_vici_dispatcher_t *this, char *name)
|
||||||
{
|
{
|
||||||
|
event_t *event;
|
||||||
bool retval = FALSE;
|
bool retval = FALSE;
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
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
|
/* the entry might be getting destroyed, but returning
|
||||||
* false positive is not a problem as a later raise_event
|
* false positive is not a problem as a later raise_event
|
||||||
* will check things again. */
|
* will check things again. */
|
||||||
retval = TRUE;
|
retval = array_count(event->clients);
|
||||||
}
|
}
|
||||||
this->mutex->unlock(this->mutex);
|
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,
|
private_vici_logger_t *this, debug_t group, level_t level, int thread,
|
||||||
ike_sa_t* ike_sa, const char *msg)
|
ike_sa_t* ike_sa, const char *msg)
|
||||||
{
|
{
|
||||||
|
if (!this->dispatcher->has_event_listeners(this->dispatcher, "log"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
|
|
||||||
/* avoid recursive invocations by the vici subsystem */
|
/* avoid recursive invocations by the vici subsystem */
|
||||||
@@ -130,6 +135,8 @@ METHOD(logger_t, log_, void,
|
|||||||
METHOD(logger_t, get_level, level_t,
|
METHOD(logger_t, get_level, level_t,
|
||||||
private_vici_logger_t *this, debug_t group)
|
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;
|
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
|
* 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;
|
enumerator_t *enumerator;
|
||||||
traffic_selector_t *ts;
|
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, "uniqueid", "%u", child->get_unique_id(child));
|
||||||
b->add_kv(b, "reqid", "%u", child->get_reqid(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, "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 ||
|
if (child->get_state(child) == CHILD_INSTALLED ||
|
||||||
child->get_state(child) == CHILD_REKEYING ||
|
child->get_state(child) == CHILD_REKEYING ||
|
||||||
child->get_state(child) == CHILD_REKEYED)
|
child->get_state(child) == CHILD_REKEYED)
|
||||||
@@ -397,6 +421,7 @@ CALLBACK(list_sas, vici_message_t*,
|
|||||||
char *ike;
|
char *ike;
|
||||||
u_int ike_id;
|
u_int ike_id;
|
||||||
bool bl;
|
bool bl;
|
||||||
|
char buf[BUF_LEN];
|
||||||
|
|
||||||
bl = request->get_str(request, NULL, "noblock") == NULL;
|
bl = request->get_str(request, NULL, "noblock") == NULL;
|
||||||
ike = request->get_str(request, NULL, "ike");
|
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);
|
csas = ike_sa->create_child_sa_enumerator(ike_sa);
|
||||||
while (csas->enumerate(csas, &child_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);
|
list_child(this, b, child_sa, now);
|
||||||
b->end_section(b);
|
b->end_section(b);
|
||||||
}
|
}
|
||||||
@@ -446,16 +473,21 @@ CALLBACK(list_sas, vici_message_t*,
|
|||||||
/**
|
/**
|
||||||
* Raise a list-policy event for given CHILD_SA
|
* 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;
|
enumerator_t *enumerator;
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
vici_builder_t *b;
|
vici_builder_t *b;
|
||||||
|
char buf[BUF_LEN];
|
||||||
|
|
||||||
b = vici_builder_create();
|
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");
|
b->begin_list(b, "local-ts");
|
||||||
enumerator = child->create_ts_enumerator(child, TRUE);
|
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
|
* 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)
|
child_cfg_t *cfg)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
linked_list_t *list;
|
linked_list_t *list;
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
vici_builder_t *b;
|
vici_builder_t *b;
|
||||||
|
char buf[BUF_LEN];
|
||||||
|
|
||||||
b = vici_builder_create();
|
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");
|
b->begin_list(b, "local-ts");
|
||||||
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
|
list = cfg->get_traffic_selectors(cfg, TRUE, NULL, NULL);
|
||||||
@@ -531,25 +571,28 @@ CALLBACK(list_policies, vici_message_t*,
|
|||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
vici_builder_t *b;
|
vici_builder_t *b;
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
|
peer_cfg_t *peer_cfg;
|
||||||
child_cfg_t *child_cfg;
|
child_cfg_t *child_cfg;
|
||||||
bool drop, pass, trap;
|
bool drop, pass, trap;
|
||||||
char *child;
|
char *child, *ike, *ns;
|
||||||
|
|
||||||
drop = request->get_str(request, NULL, "drop") != NULL;
|
drop = request->get_str(request, NULL, "drop") != NULL;
|
||||||
pass = request->get_str(request, NULL, "pass") != NULL;
|
pass = request->get_str(request, NULL, "pass") != NULL;
|
||||||
trap = request->get_str(request, NULL, "trap") != NULL;
|
trap = request->get_str(request, NULL, "trap") != NULL;
|
||||||
child = request->get_str(request, NULL, "child");
|
child = request->get_str(request, NULL, "child");
|
||||||
|
ike = request->get_str(request, NULL, "ike");
|
||||||
|
|
||||||
if (trap)
|
if (trap)
|
||||||
{
|
{
|
||||||
enumerator = charon->traps->create_enumerator(charon->traps);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
raise_policy(this, id, child_sa);
|
raise_policy(this, id, peer_cfg->get_name(peer_cfg), child_sa);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
}
|
}
|
||||||
@@ -557,9 +600,10 @@ CALLBACK(list_policies, vici_message_t*,
|
|||||||
if (drop || pass)
|
if (drop || pass)
|
||||||
{
|
{
|
||||||
enumerator = charon->shunts->create_enumerator(charon->shunts);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -568,13 +612,13 @@ CALLBACK(list_policies, vici_message_t*,
|
|||||||
case MODE_DROP:
|
case MODE_DROP:
|
||||||
if (drop)
|
if (drop)
|
||||||
{
|
{
|
||||||
raise_policy_cfg(this, id, child_cfg);
|
raise_policy_cfg(this, id, ns, child_cfg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MODE_PASS:
|
case MODE_PASS:
|
||||||
if (pass)
|
if (pass)
|
||||||
{
|
{
|
||||||
raise_policy_cfg(this, id, child_cfg);
|
raise_policy_cfg(this, id, ns, child_cfg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -746,6 +790,8 @@ CALLBACK(list_conns, vici_message_t*,
|
|||||||
peer_cfg->get_reauth_time(peer_cfg, FALSE));
|
peer_cfg->get_reauth_time(peer_cfg, FALSE));
|
||||||
b->add_kv(b, "rekey_time", "%u",
|
b->add_kv(b, "rekey_time", "%u",
|
||||||
peer_cfg->get_rekey_time(peer_cfg, FALSE));
|
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, TRUE, b);
|
||||||
build_auth_cfgs(peer_cfg, FALSE, 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->begin_section(b, child_cfg->get_name(child_cfg));
|
||||||
|
|
||||||
b->add_kv(b, "mode", "%N", ipsec_mode_names,
|
list_mode(b, NULL, child_cfg);
|
||||||
child_cfg->get_mode(child_cfg));
|
|
||||||
|
|
||||||
lft = child_cfg->get_lifetime(child_cfg, FALSE);
|
lft = child_cfg->get_lifetime(child_cfg, FALSE);
|
||||||
b->add_kv(b, "rekey_time", "%"PRIu64, lft->time.rekey);
|
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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
|
||||||
|
|
||||||
mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
|
mediation_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
|
||||||
mediation_cfg->get_ref(mediation_cfg);
|
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,
|
enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|||||||
@@ -68,7 +68,9 @@ METHOD(job_t, execute, job_requeue_t,
|
|||||||
mode = child_cfg->get_mode(child_cfg);
|
mode = child_cfg->get_mode(child_cfg);
|
||||||
if (mode == MODE_PASS || mode == MODE_DROP)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ struct private_shunt_manager_t {
|
|||||||
shunt_manager_t public;
|
shunt_manager_t public;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installed shunts, as child_cfg_t
|
* Installed shunts, as entry_t
|
||||||
*/
|
*/
|
||||||
linked_list_t *shunts;
|
linked_list_t *shunts;
|
||||||
|
|
||||||
@@ -56,6 +56,32 @@ struct private_shunt_manager_t {
|
|||||||
rwlock_condvar_t *condvar;
|
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
|
* 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,
|
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;
|
enumerator_t *enumerator;
|
||||||
child_cfg_t *child_cfg;
|
entry_t *entry;
|
||||||
bool found = FALSE, success;
|
bool found = FALSE, success;
|
||||||
|
|
||||||
/* check if not already installed */
|
/* check if not already installed */
|
||||||
@@ -176,9 +202,10 @@ METHOD(shunt_manager_t, install, bool,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
enumerator = this->shunts->create_enumerator(this->shunts);
|
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;
|
found = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -188,21 +215,25 @@ METHOD(shunt_manager_t, install, bool,
|
|||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "shunt %N policy '%s' already installed",
|
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);
|
this->lock->unlock(this->lock);
|
||||||
return TRUE;
|
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->installing++;
|
||||||
this->lock->unlock(this->lock);
|
this->lock->unlock(this->lock);
|
||||||
|
|
||||||
success = install_shunt_policy(child);
|
success = install_shunt_policy(cfg);
|
||||||
|
|
||||||
this->lock->write_lock(this->lock);
|
this->lock->write_lock(this->lock);
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
this->shunts->remove(this->shunts, child, NULL);
|
this->shunts->remove(this->shunts, entry, NULL);
|
||||||
child->destroy(child);
|
entry_destroy(entry);
|
||||||
}
|
}
|
||||||
this->installing--;
|
this->installing--;
|
||||||
this->condvar->signal(this->condvar);
|
this->condvar->signal(this->condvar);
|
||||||
@@ -320,19 +351,20 @@ static void uninstall_shunt_policy(child_cfg_t *child)
|
|||||||
}
|
}
|
||||||
|
|
||||||
METHOD(shunt_manager_t, uninstall, bool,
|
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;
|
enumerator_t *enumerator;
|
||||||
child_cfg_t *child, *found = NULL;
|
entry_t *entry, *found = NULL;
|
||||||
|
|
||||||
this->lock->write_lock(this->lock);
|
this->lock->write_lock(this->lock);
|
||||||
enumerator = this->shunts->create_enumerator(this->shunts);
|
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);
|
this->shunts->remove_at(this->shunts, enumerator);
|
||||||
found = child;
|
found = entry;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,8 +375,19 @@ METHOD(shunt_manager_t, uninstall, bool,
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
uninstall_shunt_policy(child);
|
uninstall_shunt_policy(found->cfg);
|
||||||
child->destroy(child);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,25 +395,26 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
|
|||||||
private_shunt_manager_t *this)
|
private_shunt_manager_t *this)
|
||||||
{
|
{
|
||||||
this->lock->read_lock(this->lock);
|
this->lock->read_lock(this->lock);
|
||||||
return enumerator_create_cleaner(
|
return enumerator_create_filter(
|
||||||
this->shunts->create_enumerator(this->shunts),
|
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,
|
METHOD(shunt_manager_t, flush, void,
|
||||||
private_shunt_manager_t *this)
|
private_shunt_manager_t *this)
|
||||||
{
|
{
|
||||||
child_cfg_t *child;
|
entry_t *entry;
|
||||||
|
|
||||||
this->lock->write_lock(this->lock);
|
this->lock->write_lock(this->lock);
|
||||||
while (this->installing)
|
while (this->installing)
|
||||||
{
|
{
|
||||||
this->condvar->wait(this->condvar, this->lock);
|
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);
|
uninstall_shunt_policy(entry->cfg);
|
||||||
child->destroy(child);
|
entry_destroy(entry);
|
||||||
}
|
}
|
||||||
this->installing = INSTALL_DISABLED;
|
this->installing = INSTALL_DISABLED;
|
||||||
this->lock->unlock(this->lock);
|
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
|
* Copyright (C) 2011 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -36,23 +36,26 @@ struct shunt_manager_t {
|
|||||||
/**
|
/**
|
||||||
* Install a policy as a shunt.
|
* 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
|
* @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.
|
* Uninstall a shunt policy.
|
||||||
*
|
*
|
||||||
|
* @param ns namespace (same as given during installation)
|
||||||
* @param name name of child configuration to uninstall as a shunt
|
* @param name name of child configuration to uninstall as a shunt
|
||||||
* @return TRUE if uninstalled successfully
|
* @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.
|
* 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);
|
enumerator_t* (*create_enumerator)(shunt_manager_t *this);
|
||||||
|
|
||||||
|
|||||||
@@ -370,14 +370,42 @@ METHOD(mem_cred_t, add_key, void,
|
|||||||
this->lock->unlock(this->lock);
|
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
|
* Shared key entry
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* shared key */
|
/** shared key */
|
||||||
shared_key_t *shared;
|
shared_key_t *shared;
|
||||||
/* list of owners, identification_t */
|
/** list of owners, identification_t */
|
||||||
linked_list_t *owners;
|
linked_list_t *owners;
|
||||||
|
/** optional unique identifier */
|
||||||
|
char *id;
|
||||||
} shared_entry_t;
|
} shared_entry_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,11 +416,12 @@ static void shared_entry_destroy(shared_entry_t *entry)
|
|||||||
entry->owners->destroy_offset(entry->owners,
|
entry->owners->destroy_offset(entry->owners,
|
||||||
offsetof(identification_t, destroy));
|
offsetof(identification_t, destroy));
|
||||||
entry->shared->destroy(entry->shared);
|
entry->shared->destroy(entry->shared);
|
||||||
|
free(entry->id);
|
||||||
free(entry);
|
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)
|
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);
|
(void*)shared_filter, data, (void*)shared_data_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(mem_cred_t, add_shared_list, void,
|
METHOD(mem_cred_t, add_shared_unique, void,
|
||||||
private_mem_cred_t *this, shared_key_t *shared, linked_list_t* owners)
|
private_mem_cred_t *this, char *id, shared_key_t *shared,
|
||||||
|
linked_list_t* owners)
|
||||||
{
|
{
|
||||||
shared_entry_t *current, *new;
|
shared_entry_t *current, *new;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
@@ -537,6 +567,7 @@ METHOD(mem_cred_t, add_shared_list, void,
|
|||||||
INIT(new,
|
INIT(new,
|
||||||
.shared = shared,
|
.shared = shared,
|
||||||
.owners = owners,
|
.owners = owners,
|
||||||
|
.id = strdupnull(id),
|
||||||
);
|
);
|
||||||
|
|
||||||
this->lock->write_lock(this->lock);
|
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);
|
enumerator = this->shared->create_enumerator(this->shared);
|
||||||
while (enumerator->enumerate(enumerator, ¤t))
|
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);
|
this->shared->remove_at(this->shared, enumerator);
|
||||||
shared_entry_destroy(current);
|
shared_entry_destroy(current);
|
||||||
@@ -558,6 +592,12 @@ METHOD(mem_cred_t, add_shared_list, void,
|
|||||||
this->lock->unlock(this->lock);
|
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,
|
METHOD(mem_cred_t, add_shared, void,
|
||||||
private_mem_cred_t *this, shared_key_t *shared, ...)
|
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);
|
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
|
* Certificate distribution point
|
||||||
*/
|
*/
|
||||||
@@ -817,8 +914,12 @@ mem_cred_t *mem_cred_create()
|
|||||||
.get_cert_ref = _get_cert_ref,
|
.get_cert_ref = _get_cert_ref,
|
||||||
.add_crl = _add_crl,
|
.add_crl = _add_crl,
|
||||||
.add_key = _add_key,
|
.add_key = _add_key,
|
||||||
|
.remove_key = _remove_key,
|
||||||
.add_shared = _add_shared,
|
.add_shared = _add_shared,
|
||||||
.add_shared_list = _add_shared_list,
|
.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,
|
.add_cdp = _add_cdp,
|
||||||
.replace_certs = _replace_certs,
|
.replace_certs = _replace_certs,
|
||||||
.replace_secrets = _replace_secrets,
|
.replace_secrets = _replace_secrets,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010-2015 Tobias Brunner
|
* Copyright (C) 2010-2016 Tobias Brunner
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
* Copyright (C) 2010 Martin Willi
|
* Copyright (C) 2010 Martin Willi
|
||||||
* Copyright (C) 2010 revosec AG
|
* Copyright (C) 2010 revosec AG
|
||||||
*
|
*
|
||||||
@@ -86,6 +87,14 @@ struct mem_cred_t {
|
|||||||
*/
|
*/
|
||||||
void (*add_key)(mem_cred_t *this, private_key_t *key);
|
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.
|
* 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,
|
void (*add_shared_list)(mem_cred_t *this, shared_key_t *shared,
|
||||||
linked_list_t *owners);
|
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.
|
* Add a certificate distribution point to the set.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ swanctl_SOURCES = \
|
|||||||
command.c command.h \
|
command.c command.h \
|
||||||
commands/initiate.c \
|
commands/initiate.c \
|
||||||
commands/terminate.c \
|
commands/terminate.c \
|
||||||
|
commands/rekey.c \
|
||||||
commands/redirect.c \
|
commands/redirect.c \
|
||||||
commands/install.c \
|
commands/install.c \
|
||||||
commands/list_sas.c \
|
commands/list_sas.c \
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
/**
|
/**
|
||||||
* Maximum number of commands (+1).
|
* Maximum number of commands (+1).
|
||||||
*/
|
*/
|
||||||
#define MAX_COMMANDS 24
|
#define MAX_COMMANDS 25
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of options in a command (+3)
|
* Maximum number of options in a command (+3)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ static int initiate(vici_conn_t *conn)
|
|||||||
vici_req_t *req;
|
vici_req_t *req;
|
||||||
vici_res_t *res;
|
vici_res_t *res;
|
||||||
command_format_options_t format = COMMAND_FORMAT_NONE;
|
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;
|
int ret = 0, timeout = 0, level = 1;
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
@@ -55,6 +55,9 @@ static int initiate(vici_conn_t *conn)
|
|||||||
case 'c':
|
case 'c':
|
||||||
child = arg;
|
child = arg;
|
||||||
continue;
|
continue;
|
||||||
|
case 'i':
|
||||||
|
ike = arg;
|
||||||
|
continue;
|
||||||
case 't':
|
case 't':
|
||||||
timeout = atoi(arg);
|
timeout = atoi(arg);
|
||||||
continue;
|
continue;
|
||||||
@@ -80,6 +83,10 @@ static int initiate(vici_conn_t *conn)
|
|||||||
{
|
{
|
||||||
vici_add_key_valuef(req, "child", "%s", child);
|
vici_add_key_valuef(req, "child", "%s", child);
|
||||||
}
|
}
|
||||||
|
if (ike)
|
||||||
|
{
|
||||||
|
vici_add_key_valuef(req, "ike", "%s", ike);
|
||||||
|
}
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
vici_add_key_valuef(req, "timeout", "%d", timeout * 1000);
|
vici_add_key_valuef(req, "timeout", "%d", timeout * 1000);
|
||||||
@@ -121,10 +128,11 @@ static void __attribute__ ((constructor))reg()
|
|||||||
{
|
{
|
||||||
command_register((command_t) {
|
command_register((command_t) {
|
||||||
initiate, 'i', "initiate", "initiate a connection",
|
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"},
|
{"help", 'h', 0, "show usage information"},
|
||||||
{"child", 'c', 1, "initate a CHILD_SA configuration"},
|
{"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"},
|
{"timeout", 't', 1, "timeout in seconds before detaching"},
|
||||||
{"raw", 'r', 0, "dump raw response message"},
|
{"raw", 'r', 0, "dump raw response message"},
|
||||||
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
{"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_req_t *req;
|
||||||
vici_res_t *res;
|
vici_res_t *res;
|
||||||
command_format_options_t format = COMMAND_FORMAT_NONE;
|
command_format_options_t format = COMMAND_FORMAT_NONE;
|
||||||
char *arg, *child = NULL;
|
char *arg, *child = NULL, *ike = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
@@ -40,6 +40,9 @@ static int manage_policy(vici_conn_t *conn, char *label)
|
|||||||
case 'c':
|
case 'c':
|
||||||
child = arg;
|
child = arg;
|
||||||
continue;
|
continue;
|
||||||
|
case 'i':
|
||||||
|
ike = arg;
|
||||||
|
continue;
|
||||||
case EOF:
|
case EOF:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -52,6 +55,10 @@ static int manage_policy(vici_conn_t *conn, char *label)
|
|||||||
{
|
{
|
||||||
vici_add_key_valuef(req, "child", "%s", child);
|
vici_add_key_valuef(req, "child", "%s", child);
|
||||||
}
|
}
|
||||||
|
if (ike)
|
||||||
|
{
|
||||||
|
vici_add_key_valuef(req, "ike", "%s", ike);
|
||||||
|
}
|
||||||
res = vici_submit(req, conn);
|
res = vici_submit(req, conn);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
@@ -98,10 +105,11 @@ static void __attribute__ ((constructor))reg_uninstall()
|
|||||||
{
|
{
|
||||||
command_register((command_t) {
|
command_register((command_t) {
|
||||||
uninstall, 'u', "uninstall", "uninstall a trap or shunt policy",
|
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"},
|
{"help", 'h', 0, "show usage information"},
|
||||||
{"child", 'c', 1, "CHILD_SA configuration to uninstall"},
|
{"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"},
|
{"raw", 'r', 0, "dump raw response message"},
|
||||||
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
||||||
}
|
}
|
||||||
@@ -115,10 +123,11 @@ static void __attribute__ ((constructor))reg_install()
|
|||||||
{
|
{
|
||||||
command_register((command_t) {
|
command_register((command_t) {
|
||||||
install, 'p', "install", "install a trap or shunt policy",
|
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"},
|
{"help", 'h', 0, "show usage information"},
|
||||||
{"child", 'c', 1, "CHILD_SA configuration to install"},
|
{"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"},
|
{"raw", 'r', 0, "dump raw response message"},
|
||||||
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Tobias Brunner
|
* Copyright (C) 2015-2016 Tobias Brunner
|
||||||
* Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Martin Willi
|
* Copyright (C) 2014 Martin Willi
|
||||||
* Copyright (C) 2014 revosec AG
|
* Copyright (C) 2014 revosec AG
|
||||||
@@ -58,7 +58,7 @@ static int list_pools(vici_conn_t *conn)
|
|||||||
vici_req_t *req;
|
vici_req_t *req;
|
||||||
vici_res_t *res;
|
vici_res_t *res;
|
||||||
command_format_options_t format = COMMAND_FORMAT_NONE;
|
command_format_options_t format = COMMAND_FORMAT_NONE;
|
||||||
char *arg;
|
char *arg, *name = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool leases = FALSE;
|
bool leases = FALSE;
|
||||||
|
|
||||||
@@ -77,6 +77,9 @@ static int list_pools(vici_conn_t *conn)
|
|||||||
case 'l':
|
case 'l':
|
||||||
leases = TRUE;
|
leases = TRUE;
|
||||||
continue;
|
continue;
|
||||||
|
case 'n':
|
||||||
|
name = arg;
|
||||||
|
continue;
|
||||||
case EOF:
|
case EOF:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -90,6 +93,10 @@ static int list_pools(vici_conn_t *conn)
|
|||||||
{
|
{
|
||||||
vici_add_key_valuef(req, "leases", "yes");
|
vici_add_key_valuef(req, "leases", "yes");
|
||||||
}
|
}
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
vici_add_key_valuef(req, "name", "%s", name);
|
||||||
|
}
|
||||||
res = vici_submit(req, conn);
|
res = vici_submit(req, conn);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
@@ -123,6 +130,7 @@ static void __attribute__ ((constructor))reg()
|
|||||||
{"raw", 'r', 0, "dump raw response message"},
|
{"raw", 'r', 0, "dump raw response message"},
|
||||||
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
{"pretty", 'P', 0, "dump raw response message in pretty print"},
|
||||||
{"leases", 'l', 0, "list leases of each pool"},
|
{"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)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
printf(" %s: #%s, reqid %s, %s, %s%s, %s:",
|
printf(" %s: #%s, reqid %s, %s, %s%s, %s:",
|
||||||
name, child->get(child, "uniqueid"), child->get(child, "reqid"),
|
child->get(child, "name"), child->get(child, "uniqueid"),
|
||||||
child->get(child, "state"), child->get(child, "mode"),
|
child->get(child, "reqid"), child->get(child, "state"),
|
||||||
|
child->get(child, "mode"),
|
||||||
child->get(child, "encap") ? "-in-UDP" : "",
|
child->get(child, "encap") ? "-in-UDP" : "",
|
||||||
child->get(child, "protocol"));
|
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);
|
enumerator = cfg->create_key_value_enumerator(cfg, section);
|
||||||
while (enumerator->enumerate(enumerator, &key, &value))
|
while (enumerator->enumerate(enumerator, &key, &value))
|
||||||
{
|
{
|
||||||
/* pool subnet is encoded as key/value, all other attributes as list */
|
|
||||||
if (streq(key, "cacert"))
|
if (streq(key, "cacert"))
|
||||||
{
|
{
|
||||||
ret = add_file_key_value(req, key, value);
|
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
|
else
|
||||||
{
|
{
|
||||||
add_list_key(req, key, value);
|
vici_add_key_valuef(req, key, "%s", value);
|
||||||
}
|
}
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ static bool is_list_key(char *key)
|
|||||||
"vips",
|
"vips",
|
||||||
"pools",
|
"pools",
|
||||||
"groups",
|
"groups",
|
||||||
|
"cert_policy",
|
||||||
};
|
};
|
||||||
int i;
|
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)
|
static bool add_file_list_key(vici_req_t *req, char *key, char *value)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
chunk_t *map;
|
chunk_t *map, blob;
|
||||||
char *token, buf[PATH_MAX];
|
char *token, buf[PATH_MAX];
|
||||||
bool ret = TRUE;
|
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, ",", " ");
|
enumerator = enumerator_create_token(value, ",", " ");
|
||||||
while (enumerator->enumerate(enumerator, &token))
|
while (enumerator->enumerate(enumerator, &token))
|
||||||
{
|
{
|
||||||
if (!path_absolute(token))
|
if (strcasepfx(token, "0x") || strcasepfx(token, "0s"))
|
||||||
{
|
{
|
||||||
if (streq(key, "certs"))
|
blob = chunk_from_str(token + 2);
|
||||||
{
|
blob = strcasepfx(token, "0x") ? chunk_from_hex(blob, NULL)
|
||||||
snprintf(buf, sizeof(buf), "%s%s%s",
|
: chunk_from_base64(blob, NULL);
|
||||||
SWANCTL_X509DIR, DIRECTORY_SEPARATOR, token);
|
vici_add_list_item(req, blob.ptr, blob.len);
|
||||||
token = buf;
|
chunk_free(&blob);
|
||||||
}
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
|
if (!path_absolute(token))
|
||||||
key, token, strerror(errno));
|
{
|
||||||
ret = FALSE;
|
if (streq(key, "certs"))
|
||||||
break;
|
{
|
||||||
|
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);
|
enumerator->destroy(enumerator);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Martin Willi
|
|
||||||
* Copyright (C) 2014 revosec AG
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 Tobias Brunner
|
* Copyright (C) 2016 Tobias Brunner
|
||||||
* Copyright (C) 2015 Andreas Steffen
|
* Copyright (C) 2015 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* 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
|
* 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
|
* 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
|
* 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/mem_cred.h>
|
||||||
#include <credentials/sets/callback_cred.h>
|
#include <credentials/sets/callback_cred.h>
|
||||||
#include <credentials/containers/pkcs12.h>
|
#include <credentials/containers/pkcs12.h>
|
||||||
|
#include <collections/hashtable.h>
|
||||||
|
|
||||||
#include <vici_cert_info.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
|
* Load a single certificate over vici
|
||||||
*/
|
*/
|
||||||
static bool load_cert(vici_conn_t *conn, command_format_options_t format,
|
static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type,
|
||||||
char *dir, certificate_type_t type, x509_flag_t flag,
|
x509_flag_t flag, chunk_t data)
|
||||||
chunk_t data)
|
|
||||||
{
|
{
|
||||||
vici_req_t *req;
|
vici_req_t *req;
|
||||||
vici_res_t *res;
|
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);
|
vici_add_key_value(req, "data", data.ptr, data.len);
|
||||||
|
|
||||||
res = vici_submit(req, conn);
|
res = vici_submit(req, ctx->conn);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
|
fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
|
||||||
return FALSE;
|
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);
|
stdout);
|
||||||
}
|
}
|
||||||
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
|
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
|
* Load certficiates from a directory
|
||||||
*/
|
*/
|
||||||
static void load_certs(vici_conn_t *conn, command_format_options_t format,
|
static void load_certs(load_ctx_t *ctx, char *type_str, char *dir)
|
||||||
char *type_str, char *dir)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
certificate_type_t type;
|
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);
|
map = chunk_map(path, FALSE);
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
load_cert(conn, format, path, type, flag, *map);
|
load_cert(ctx, path, type, flag, *map);
|
||||||
chunk_unmap(map);
|
chunk_unmap(map);
|
||||||
}
|
}
|
||||||
else
|
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
|
* Load a single private key over vici
|
||||||
*/
|
*/
|
||||||
static bool load_key(vici_conn_t *conn, command_format_options_t format,
|
static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
|
||||||
char *dir, char *type, chunk_t data)
|
|
||||||
{
|
{
|
||||||
vici_req_t *req;
|
vici_req_t *req;
|
||||||
vici_res_t *res;
|
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);
|
vici_add_key_value(req, "data", data.ptr, data.len);
|
||||||
|
|
||||||
res = vici_submit(req, conn);
|
res = vici_submit(req, ctx->conn);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
|
fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
|
||||||
return FALSE;
|
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);
|
stdout);
|
||||||
}
|
}
|
||||||
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
|
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
|
* Load a private key of any type to vici
|
||||||
*/
|
*/
|
||||||
static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format,
|
static bool load_key_anytype(load_ctx_t *ctx, char *path,
|
||||||
char *path, private_key_t *private)
|
private_key_t *private)
|
||||||
{
|
{
|
||||||
bool loaded = FALSE;
|
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))
|
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))
|
switch (private->get_type(private))
|
||||||
{
|
{
|
||||||
case KEY_RSA:
|
case KEY_RSA:
|
||||||
loaded = load_key(conn, format, path, "rsa", encoding);
|
loaded = load_key(ctx, path, "rsa", encoding);
|
||||||
break;
|
break;
|
||||||
case KEY_ECDSA:
|
case KEY_ECDSA:
|
||||||
loaded = load_key(conn, format, path, "ecdsa", encoding);
|
loaded = load_key(ctx, path, "ecdsa", encoding);
|
||||||
break;
|
break;
|
||||||
case KEY_BLISS:
|
case KEY_BLISS:
|
||||||
loaded = load_key(conn, format, path, "bliss", encoding);
|
loaded = load_key(ctx, path, "bliss", encoding);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "unsupported key type in '%s'\n", path);
|
fprintf(stderr, "unsupported key type in '%s'\n", path);
|
||||||
break;
|
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);
|
chunk_clear(&encoding);
|
||||||
return loaded;
|
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
|
* 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)
|
chunk_t encoding)
|
||||||
{
|
{
|
||||||
credential_type_t credtype;
|
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 */
|
/* 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))
|
while (enumerator->enumerate(enumerator, §ion))
|
||||||
{
|
{
|
||||||
if (strpfx(section, type))
|
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))
|
if (file && strcaseeq(file, name))
|
||||||
{
|
{
|
||||||
snprintf(buf, sizeof(buf), "secrets.%s", section);
|
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))
|
while (secrets->enumerate(secrets, &key, &value))
|
||||||
{
|
{
|
||||||
if (strpfx(key, "secret"))
|
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
|
* Try to decrypt and load a private key
|
||||||
*/
|
*/
|
||||||
static bool load_encrypted_key(vici_conn_t *conn,
|
static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
|
||||||
command_format_options_t format, settings_t *cfg,
|
char *type, chunk_t data)
|
||||||
char *rel, char *path, char *type, bool noprompt,
|
|
||||||
chunk_t data)
|
|
||||||
{
|
{
|
||||||
private_key_t *private;
|
private_key_t *private;
|
||||||
bool loaded = FALSE;
|
bool loaded = FALSE;
|
||||||
|
|
||||||
private = decrypt_with_config(cfg, rel, type, data);
|
private = decrypt_with_config(ctx, rel, type, data);
|
||||||
if (!private && !noprompt)
|
if (!private && !ctx->noprompt)
|
||||||
{
|
{
|
||||||
private = decrypt(rel, type, data);
|
private = decrypt(rel, type, data);
|
||||||
}
|
}
|
||||||
if (private)
|
if (private)
|
||||||
{
|
{
|
||||||
loaded = load_key_anytype(conn, format, path, private);
|
loaded = load_key_anytype(ctx, path, private);
|
||||||
private->destroy(private);
|
private->destroy(private);
|
||||||
}
|
}
|
||||||
return loaded;
|
return loaded;
|
||||||
@@ -406,8 +430,7 @@ static bool load_encrypted_key(vici_conn_t *conn,
|
|||||||
/**
|
/**
|
||||||
* Load private keys from a directory
|
* Load private keys from a directory
|
||||||
*/
|
*/
|
||||||
static void load_keys(vici_conn_t *conn, command_format_options_t format,
|
static void load_keys(load_ctx_t *ctx, char *type, char *dir)
|
||||||
bool noprompt, settings_t *cfg, char *type, char *dir)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
struct stat st;
|
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);
|
map = chunk_map(path, FALSE);
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
if (!load_encrypted_key(conn, format, cfg, rel, path, type,
|
if (!load_encrypted_key(ctx, rel, path, type, *map))
|
||||||
noprompt, *map))
|
|
||||||
{
|
{
|
||||||
load_key(conn, format, path, type, *map);
|
load_key(ctx, path, type, *map);
|
||||||
}
|
}
|
||||||
chunk_unmap(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
|
* Load credentials from a PKCS#12 container over vici
|
||||||
*/
|
*/
|
||||||
static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format,
|
static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
|
||||||
char *path, pkcs12_t *p12)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
certificate_t *cert;
|
certificate_t *cert;
|
||||||
@@ -460,8 +481,7 @@ static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format,
|
|||||||
loaded = FALSE;
|
loaded = FALSE;
|
||||||
if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
|
if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
|
||||||
{
|
{
|
||||||
loaded = load_cert(conn, format, path, CERT_X509, X509_NONE,
|
loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
|
||||||
encoding);
|
|
||||||
if (loaded)
|
if (loaded)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " %Y\n", cert->get_subject(cert));
|
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);
|
enumerator = p12->create_key_enumerator(p12);
|
||||||
while (loaded && enumerator->enumerate(enumerator, &private))
|
while (loaded && enumerator->enumerate(enumerator, &private))
|
||||||
{
|
{
|
||||||
loaded = load_key_anytype(conn, format, path, private);
|
loaded = load_key_anytype(ctx, path, private);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
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
|
* Try to decrypt and load credentials from a container
|
||||||
*/
|
*/
|
||||||
static bool load_encrypted_container(vici_conn_t *conn,
|
static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
|
||||||
command_format_options_t format, settings_t *cfg, char *rel,
|
char *type, chunk_t data)
|
||||||
char *path, char *type, bool noprompt, chunk_t data)
|
|
||||||
{
|
{
|
||||||
container_t *container;
|
container_t *container;
|
||||||
bool loaded = FALSE;
|
bool loaded = FALSE;
|
||||||
|
|
||||||
container = decrypt_with_config(cfg, rel, type, data);
|
container = decrypt_with_config(ctx, rel, type, data);
|
||||||
if (!container && !noprompt)
|
if (!container && !ctx->noprompt)
|
||||||
{
|
{
|
||||||
container = decrypt(rel, type, data);
|
container = decrypt(rel, type, data);
|
||||||
}
|
}
|
||||||
@@ -505,7 +524,7 @@ static bool load_encrypted_container(vici_conn_t *conn,
|
|||||||
switch (container->get_type(container))
|
switch (container->get_type(container))
|
||||||
{
|
{
|
||||||
case CONTAINER_PKCS12:
|
case CONTAINER_PKCS12:
|
||||||
loaded = load_pkcs12(conn, format, path, (pkcs12_t*)container);
|
loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -518,8 +537,7 @@ static bool load_encrypted_container(vici_conn_t *conn,
|
|||||||
/**
|
/**
|
||||||
* Load credential containers from a directory
|
* Load credential containers from a directory
|
||||||
*/
|
*/
|
||||||
static void load_containers(vici_conn_t *conn, command_format_options_t format,
|
static void load_containers(load_ctx_t *ctx, char *type, char *dir)
|
||||||
bool noprompt, settings_t *cfg, char *type, char *dir)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
struct stat st;
|
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);
|
map = chunk_map(path, FALSE);
|
||||||
if (map)
|
if (map)
|
||||||
{
|
{
|
||||||
load_encrypted_container(conn, format, cfg, rel, path,
|
load_encrypted_container(ctx, rel, path, type, *map);
|
||||||
type, noprompt, *map);
|
|
||||||
chunk_unmap(map);
|
chunk_unmap(map);
|
||||||
}
|
}
|
||||||
else
|
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
|
* Load a single secret over VICI
|
||||||
*/
|
*/
|
||||||
static bool load_secret(vici_conn_t *conn, settings_t *cfg,
|
static bool load_secret(load_ctx_t *ctx, char *section)
|
||||||
char *section, command_format_options_t format)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
vici_req_t *req;
|
vici_req_t *req;
|
||||||
@@ -567,6 +670,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg,
|
|||||||
char *types[] = {
|
char *types[] = {
|
||||||
"eap",
|
"eap",
|
||||||
"xauth",
|
"xauth",
|
||||||
|
"ntlm",
|
||||||
"ike",
|
"ike",
|
||||||
"private",
|
"private",
|
||||||
"rsa",
|
"rsa",
|
||||||
@@ -574,6 +678,7 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg,
|
|||||||
"bliss",
|
"bliss",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"pkcs12",
|
"pkcs12",
|
||||||
|
"token",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < countof(types); i++)
|
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);
|
fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
|
||||||
return FALSE;
|
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 */
|
{ /* skip non-shared secrets */
|
||||||
return TRUE;
|
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)
|
if (!value)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "missing secret in '%s', ignored\n", section);
|
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");
|
req = vici_begin("load-shared");
|
||||||
|
|
||||||
|
vici_add_key_valuef(req, "id", "%s", section);
|
||||||
vici_add_key_valuef(req, "type", "%s", type);
|
vici_add_key_valuef(req, "type", "%s", type);
|
||||||
vici_add_key_value(req, "data", data.ptr, data.len);
|
vici_add_key_value(req, "data", data.ptr, data.len);
|
||||||
chunk_clear(&data);
|
chunk_clear(&data);
|
||||||
|
|
||||||
vici_begin_list(req, "owners");
|
vici_begin_list(req, "owners");
|
||||||
snprintf(buf, sizeof(buf), "secrets.%s", section);
|
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))
|
while (enumerator->enumerate(enumerator, &key, &value))
|
||||||
{
|
{
|
||||||
if (strpfx(key, "id"))
|
if (strpfx(key, "id"))
|
||||||
@@ -632,15 +739,15 @@ static bool load_secret(vici_conn_t *conn, settings_t *cfg,
|
|||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
vici_end_list(req);
|
vici_end_list(req);
|
||||||
|
|
||||||
res = vici_submit(req, conn);
|
res = vici_submit(req, ctx->conn);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
|
fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
|
||||||
return FALSE;
|
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);
|
stdout);
|
||||||
}
|
}
|
||||||
else if (!streq(vici_find_str(res, "no", "success"), "yes"))
|
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);
|
printf("loaded %s secret '%s'\n", type, section);
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
free(ctx->shared->remove(ctx->shared, section));
|
||||||
|
}
|
||||||
vici_free_res(res);
|
vici_free_res(res);
|
||||||
return ret;
|
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
|
* 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;
|
enumerator_t *enumerator;
|
||||||
char *section;
|
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)
|
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);
|
get_creds(&ctx);
|
||||||
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);
|
|
||||||
|
|
||||||
load_keys(conn, format, noprompt, cfg, "private", SWANCTL_PRIVATEDIR);
|
load_certs(&ctx, "x509", SWANCTL_X509DIR);
|
||||||
load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
|
load_certs(&ctx, "x509ca", SWANCTL_X509CADIR);
|
||||||
load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
|
load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
|
||||||
load_keys(conn, format, noprompt, cfg, "bliss", SWANCTL_BLISSDIR);
|
load_certs(&ctx, "x509aa", SWANCTL_X509AADIR);
|
||||||
load_keys(conn, format, noprompt, cfg, "pkcs8", SWANCTL_PKCS8DIR);
|
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");
|
enumerator = cfg->create_section_enumerator(cfg, "secrets");
|
||||||
while (enumerator->enumerate(enumerator, §ion))
|
while (enumerator->enumerate(enumerator, §ion))
|
||||||
{
|
{
|
||||||
load_secret(conn, cfg, section, format);
|
load_secret(&ctx, section);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
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;
|
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"
|
.B "\-t, \-\-terminate"
|
||||||
terminate a connection
|
terminate a connection
|
||||||
.TP
|
.TP
|
||||||
|
.B "\-R, \-\-rekey"
|
||||||
|
rekey an SA
|
||||||
|
.TP
|
||||||
.B "\-d, \-\-redirect"
|
.B "\-d, \-\-redirect"
|
||||||
redirect an IKE_SA
|
redirect an IKE_SA
|
||||||
.TP
|
.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
|
Push mode is currently supported for IKEv1, but not in IKEv2. It is used
|
||||||
by a few implementations only, pull mode is recommended.
|
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
|
connections.<conn>.encap = no
|
||||||
Enforce UDP encapsulation by faking NAT-D payloads.
|
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
|
other configuration attributes from. Each name references a pool by name
|
||||||
from either the **pools** section or an external pool.
|
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> {}
|
connections.<conn>.local<suffix> {}
|
||||||
Section for a local authentication round.
|
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
|
certificate request payloads. If no appropriate CA can be located, the
|
||||||
first certificate is used.
|
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 =
|
connections.<conn>.local<suffix>.pubkeys =
|
||||||
Comma separated list of raw public key candidates to use for authentication.
|
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
|
can be certified by different means, for example by appropriate Attribute
|
||||||
Certificates or by an AAA backend involved in the authentication.
|
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 =
|
connections.<conn>.remote<suffix>.certs =
|
||||||
Comma separated list of certificate to accept for authentication.
|
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_
|
The certificates may use a relative path from the **swanctl** _x509_
|
||||||
directory or an absolute path.
|
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 =
|
connections.<conn>.remote<suffix>.cacerts =
|
||||||
Comma separated list of CA certificates to accept for authentication.
|
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_
|
The certificates may use a relative path from the **swanctl** _x509ca_
|
||||||
directory or an absolute path.
|
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 =
|
connections.<conn>.remote<suffix>.pubkeys =
|
||||||
Comma separated list of raw public keys to accept for authentication.
|
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.
|
Hostaccess variable to pass to **updown** script.
|
||||||
|
|
||||||
connections.<conn>.children.<child>.mode = tunnel
|
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
|
IPsec Mode to establish CHILD_SA with. _tunnel_ negotiates the CHILD_SA
|
||||||
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode. _beet_
|
in IPsec Tunnel Mode, whereas _transport_ uses IPsec Transport Mode.
|
||||||
is the Bound End to End Tunnel mixture mode, working with fixed inner
|
_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.
|
addresses without the need to include them in each packet.
|
||||||
|
|
||||||
Both _transport_ and _beet_ modes are subject to mode negotiation; _tunnel_
|
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
|
be specified, each having an _id_ prefix, if a secret is shared between
|
||||||
multiple users.
|
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> { # }
|
secrets.ike<suffix> { # }
|
||||||
IKE preshared secret section for a specific secret.
|
IKE preshared secret section for a specific secret.
|
||||||
|
|
||||||
@@ -880,6 +1026,22 @@ secrets.pkcs12<suffix>.file =
|
|||||||
secrets.pkcs12<suffix>.secret
|
secrets.pkcs12<suffix>.secret
|
||||||
Value of decryption passphrase for PKCS#12 container.
|
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 { # }
|
pools { # }
|
||||||
Section defining named pools.
|
Section defining named pools.
|
||||||
|
|
||||||
@@ -916,18 +1078,40 @@ authorities.<name> { # }
|
|||||||
authorities.<name>.cacert =
|
authorities.<name>.cacert =
|
||||||
CA certificate belonging to the certification authority.
|
CA certificate belonging to the certification authority.
|
||||||
|
|
||||||
The certificates may use a relative path from the **swanctl** _x509ca_
|
CA certificate belonging to the certification authority. The certificates
|
||||||
directory or an absolute path.
|
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 =
|
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 =
|
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 =
|
authorities.<name>.cert_uri_base =
|
||||||
Defines the base URI for the Hash and URL feature supported by IKEv2.
|
Defines the base URI for the Hash and URL feature supported by IKEv2.
|
||||||
|
|||||||
Reference in New Issue
Block a user