merged multi-auth branch back into trunk
This commit is contained in:
@@ -17,6 +17,9 @@
|
||||
|
||||
#include "eap_mschapv2.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <daemon.h>
|
||||
#include <library.h>
|
||||
#include <utils/enumerator.h>
|
||||
@@ -141,7 +144,7 @@ ENUM_END(mschapv2_error_names, ERROR_CHANGING_PASSWORD);
|
||||
/* Name we send as authenticator */
|
||||
#define MSCHAPV2_HOST_NAME "strongSwan"
|
||||
/* Message sent on success */
|
||||
#define SUCCESS_MESSAGE " M=Welcome to strongSwan"
|
||||
#define SUCCESS_MESSAGE " M=Welcome2strongSwan"
|
||||
/* Message sent on failure */
|
||||
#define FAILURE_MESSAGE "E=691 R=1 C="
|
||||
/* Length of the complete failure message */
|
||||
@@ -366,7 +369,6 @@ static status_t AuthenticatorResponse(chunk_t password_hash_hash,
|
||||
static const chunk_t magic1 = chunk_from_buf(magic1_data);
|
||||
static const chunk_t magic2 = chunk_from_buf(magic2_data);
|
||||
|
||||
status_t status = FAILED;
|
||||
chunk_t digest = chunk_empty, concat;
|
||||
hasher_t *hasher;
|
||||
|
||||
@@ -526,6 +528,24 @@ static chunk_t ascii_to_unicode(chunk_t ascii)
|
||||
return unicode;
|
||||
}
|
||||
|
||||
/**
|
||||
* sanitize a string for printing
|
||||
*/
|
||||
static char* sanitize(char *str)
|
||||
{
|
||||
char *pos = str;
|
||||
|
||||
while (pos && *pos)
|
||||
{
|
||||
if (!isprint(*pos))
|
||||
{
|
||||
*pos = '?';
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a chunk of just the username part of the given user identity.
|
||||
* Note: the chunk points to internal data of the identification.
|
||||
@@ -535,7 +555,7 @@ static chunk_t extract_username(identification_t* identification)
|
||||
char *has_domain;
|
||||
chunk_t id;
|
||||
id = identification->get_encoding(identification);
|
||||
has_domain = (char*)memrchr(id.ptr, '\\', id.len);
|
||||
has_domain = (char*)memchr(id.ptr, '\\', id.len);
|
||||
if (has_domain)
|
||||
{
|
||||
int len;
|
||||
@@ -625,7 +645,8 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
|
||||
|
||||
if (cha->value_size != CHALLENGE_LEN)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge size");
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
|
||||
"invalid challenge size");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
@@ -643,11 +664,11 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
|
||||
rng->destroy(rng);
|
||||
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_EAP, this->peer, this->server);
|
||||
SHARED_EAP, this->peer, this->server);
|
||||
if (shared == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'",
|
||||
this->server, this->peer);
|
||||
this->server, this->peer);
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -725,7 +746,8 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
|
||||
token += 2;
|
||||
if (strlen(token) != AUTH_RESPONSE_LEN - 2)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid auth string");
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
|
||||
"invalid auth string");
|
||||
goto error;
|
||||
}
|
||||
hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
|
||||
@@ -741,7 +763,8 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
|
||||
|
||||
if (auth_string.ptr == NULL)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: auth string missing");
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
|
||||
"auth string missing");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -751,7 +774,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
|
||||
goto error;
|
||||
}
|
||||
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", msg);
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", sanitize(msg));
|
||||
|
||||
eap = alloca(len);
|
||||
eap->code = EAP_RESPONSE;
|
||||
@@ -780,7 +803,6 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
|
||||
char *message, *token, *msg = NULL;
|
||||
int message_len, error, retryable;
|
||||
chunk_t challenge = chunk_empty;
|
||||
u_int16_t len = SHORT_HEADER_LEN;
|
||||
|
||||
data = in->get_data(in);
|
||||
eap = (eap_mschapv2_header_t*)data.ptr;
|
||||
@@ -816,7 +838,8 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
|
||||
token += 2;
|
||||
if (strlen(token) != 2 * CHALLENGE_LEN)
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge");
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message:"
|
||||
"invalid challenge");
|
||||
goto error;
|
||||
}
|
||||
hex = chunk_create(token, 2 * CHALLENGE_LEN);
|
||||
@@ -836,7 +859,8 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'", mschapv2_error_names, error, msg);
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'",
|
||||
mschapv2_error_names, error, sanitize(msg));
|
||||
|
||||
/**
|
||||
* at this point, if the error is retryable, we MAY retry the authentication
|
||||
@@ -898,8 +922,8 @@ static status_t process_peer(private_eap_mschapv2_t *this, eap_payload_t *in,
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!",
|
||||
mschapv2_opcode_names, eap->opcode);
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
|
||||
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -925,7 +949,8 @@ static status_t process_server_retry(private_eap_mschapv2_t *this,
|
||||
* so, to clean up our state we just fail with an EAP-Failure.
|
||||
* this gives an unknown error on the windows side, but is also fine
|
||||
* with the standard. */
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: maximum number of retries reached");
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: "
|
||||
"maximum number of retries reached");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
@@ -977,6 +1002,7 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
||||
identification_t *userid;
|
||||
shared_key_t *shared;
|
||||
int name_len;
|
||||
char buf[256];
|
||||
|
||||
data = in->get_data(in);
|
||||
eap = (eap_mschapv2_header_t*)data.ptr;
|
||||
@@ -991,10 +1017,10 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
||||
peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN);
|
||||
|
||||
name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
|
||||
userid = identification_create_from_encoding(ID_EAP,
|
||||
chunk_create(res->name, name_len));
|
||||
snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
|
||||
userid = identification_create_from_string(buf);
|
||||
DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%D'", userid);
|
||||
username = extract_username(userid);
|
||||
DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%.*s'", name_len, res->name);
|
||||
|
||||
shared = charon->credentials->get_shared(charon->credentials,
|
||||
SHARED_EAP, this->server, userid);
|
||||
@@ -1015,7 +1041,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
|
||||
password = ascii_to_unicode(shared->get_key(shared));
|
||||
shared->destroy(shared);
|
||||
|
||||
if (GenerateStuff(this, this->challenge, peer_challenge, username, password) != SUCCESS)
|
||||
if (GenerateStuff(this, this->challenge, peer_challenge,
|
||||
username, password) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
|
||||
userid->destroy(userid);
|
||||
@@ -1063,7 +1090,8 @@ static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in,
|
||||
|
||||
if (this->identifier != in->get_identifier(in))
|
||||
{
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: unexpected identifier");
|
||||
DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
|
||||
"unexpected identifier");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
@@ -1092,8 +1120,8 @@ static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in,
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!",
|
||||
mschapv2_opcode_names, eap->opcode);
|
||||
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
|
||||
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ static bool get_triplet(private_eap_sim_file_card_t *this,
|
||||
identification_t *id;
|
||||
char *c_rand, *c_sres, *c_kc;
|
||||
|
||||
|
||||
DBG1(DBG_CFG, "looking for rand: %b", rand, RAND_LEN);
|
||||
DBG2(DBG_CFG, "looking for rand: %b", rand, RAND_LEN);
|
||||
|
||||
enumerator = this->triplets->create_enumerator(this->triplets);
|
||||
while (enumerator->enumerate(enumerator, &id, &c_rand, &c_sres, &c_kc))
|
||||
{
|
||||
DBG1(DBG_CFG, "found triplet: %b %b %b", c_rand, RAND_LEN, c_sres, SRES_LEN, c_kc, KC_LEN);
|
||||
DBG2(DBG_CFG, "found triplet: rand %b\nsres %b\n kc %b",
|
||||
c_rand, RAND_LEN, c_sres, SRES_LEN, c_kc, KC_LEN);
|
||||
if (memeq(c_rand, rand, RAND_LEN))
|
||||
{
|
||||
memcpy(sres, c_sres, SRES_LEN);
|
||||
|
||||
@@ -196,8 +196,7 @@ static void read_triplets(private_eap_sim_file_triplets_t *this, char *path)
|
||||
switch (i++)
|
||||
{
|
||||
case 0: /* IMSI */
|
||||
triplet->imsi = identification_create_from_encoding(ID_EAP,
|
||||
chunk_create(token, strlen(token)));
|
||||
triplet->imsi = identification_create_from_string(token);
|
||||
continue;
|
||||
case 1: /* rand */
|
||||
parse_token(triplet->rand, token, RAND_LEN);
|
||||
@@ -221,7 +220,7 @@ static void read_triplets(private_eap_sim_file_triplets_t *this, char *path)
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG1(DBG_CFG, "triplet: imsi %D\nrand %b\nsres %b\nkc %b",
|
||||
DBG2(DBG_CFG, "triplet: imsi %D\nrand %b\nsres %b\nkc %b",
|
||||
triplet->imsi, triplet->rand, RAND_LEN,
|
||||
triplet->sres, SRES_LEN, triplet->kc, KC_LEN);
|
||||
|
||||
|
||||
@@ -57,9 +57,14 @@ struct private_load_tester_config_t {
|
||||
proposal_t *proposal;
|
||||
|
||||
/**
|
||||
* Authentication method to use
|
||||
* Authentication method(s) to use/expect from initiator
|
||||
*/
|
||||
auth_class_t class;
|
||||
char *initiator_auth;
|
||||
|
||||
/**
|
||||
* Authentication method(s) use/expected from responder
|
||||
*/
|
||||
char *responder_auth;
|
||||
|
||||
/**
|
||||
* incremental numbering of generated configs
|
||||
@@ -67,6 +72,97 @@ struct private_load_tester_config_t {
|
||||
u_int num;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate auth config from string
|
||||
*/
|
||||
static void generate_auth_cfg(private_load_tester_config_t *this, char *str,
|
||||
peer_cfg_t *peer_cfg, bool local, int num)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *auth;
|
||||
identification_t *id;
|
||||
auth_class_t class;
|
||||
eap_type_t type;
|
||||
char buf[128];
|
||||
int rnd = 0;
|
||||
|
||||
enumerator = enumerator_create_token(str, "|", " ");
|
||||
while (enumerator->enumerate(enumerator, &str))
|
||||
{
|
||||
auth = auth_cfg_create();
|
||||
rnd++;
|
||||
|
||||
if (streq(str, "psk"))
|
||||
{ /* PSK authentication, use FQDNs */
|
||||
class = AUTH_CLASS_PSK;
|
||||
if ((local && !num) || (!local && num))
|
||||
{
|
||||
id = identification_create_from_string("srv.strongswan.org");
|
||||
}
|
||||
else if (local)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "c%d-r%d.strongswan.org", num, rnd);
|
||||
id = identification_create_from_string(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = identification_create_from_string("*.strongswan.org");
|
||||
}
|
||||
}
|
||||
else if (strneq(str, "eap", strlen("eap")))
|
||||
{ /* EAP authentication, use a NAI */
|
||||
class = AUTH_CLASS_EAP;
|
||||
if (*(str + strlen("eap")) == '-')
|
||||
{
|
||||
type = eap_type_from_string(str + strlen("eap-"));
|
||||
if (type)
|
||||
{
|
||||
auth->add(auth, AUTH_RULE_EAP_TYPE, type);
|
||||
}
|
||||
}
|
||||
if (local && num)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "1%.10d%[email protected]", num, rnd);
|
||||
id = identification_create_from_string(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = identification_create_from_encoding(ID_ANY, chunk_empty);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!streq(str, "pubkey"))
|
||||
{
|
||||
DBG1(DBG_CFG, "invalid authentication: '%s', fallback to pubkey",
|
||||
str);
|
||||
}
|
||||
/* certificate authentication, use distinguished names */
|
||||
class = AUTH_CLASS_PUBKEY;
|
||||
if ((local && !num) || (!local && num))
|
||||
{
|
||||
id = identification_create_from_string(
|
||||
"CN=srv, OU=load-test, O=strongSwan");
|
||||
}
|
||||
else if (local)
|
||||
{
|
||||
snprintf(buf, sizeof(buf),
|
||||
"CN=c%d-r%d, OU=load-test, O=strongSwan", num, rnd);
|
||||
id = identification_create_from_string(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = identification_create_from_string(
|
||||
"CN=*, OU=load-test, O=strongSwan");
|
||||
}
|
||||
}
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, class);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, id);
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, local);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new initiator config, num = 0 for responder config
|
||||
*/
|
||||
@@ -76,36 +172,26 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num)
|
||||
child_cfg_t *child_cfg;
|
||||
peer_cfg_t *peer_cfg;
|
||||
traffic_selector_t *ts;
|
||||
auth_info_t *auth;
|
||||
identification_t *local, *remote;
|
||||
proposal_t *proposal;
|
||||
char buf[128];
|
||||
|
||||
if (num)
|
||||
{ /* initiator */
|
||||
snprintf(buf, sizeof(buf), "CN=cli-%d, OU=load-test, O=strongSwan", num);
|
||||
local = identification_create_from_string(buf);
|
||||
snprintf(buf, sizeof(buf), "CN=srv, OU=load-test, O=strongSwan", num);
|
||||
remote = identification_create_from_string(buf);
|
||||
}
|
||||
else
|
||||
{ /* responder */
|
||||
local = identification_create_from_string(
|
||||
"CN=srv, OU=load-test, O=strongSwan");
|
||||
remote = identification_create_from_string(
|
||||
"CN=*, OU=load-test, O=strongSwan");
|
||||
}
|
||||
|
||||
ike_cfg = ike_cfg_create(FALSE, FALSE, "0.0.0.0", this->remote);
|
||||
ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal));
|
||||
peer_cfg = peer_cfg_create("load-test", 2, ike_cfg, local, remote,
|
||||
peer_cfg = peer_cfg_create("load-test", 2, ike_cfg,
|
||||
CERT_SEND_IF_ASKED, UNIQUE_NO, 1, 0, 0, /* keytries, rekey, reauth */
|
||||
0, 0, FALSE, 0, /* jitter, overtime, mobike, dpddelay */
|
||||
this->vip ? this->vip->clone(this->vip) : NULL,
|
||||
this->pool, FALSE, NULL, NULL);
|
||||
auth = peer_cfg->get_auth(peer_cfg);
|
||||
auth->add_item(auth, AUTHN_AUTH_CLASS, &this->class);
|
||||
child_cfg = child_cfg_create("load-test", 600, 400, 100, NULL, TRUE,
|
||||
if (num)
|
||||
{ /* initiator */
|
||||
generate_auth_cfg(this, this->initiator_auth, peer_cfg, TRUE, num);
|
||||
generate_auth_cfg(this, this->responder_auth, peer_cfg, FALSE, num);
|
||||
}
|
||||
else
|
||||
{ /* responder */
|
||||
generate_auth_cfg(this, this->responder_auth, peer_cfg, TRUE, num);
|
||||
generate_auth_cfg(this, this->initiator_auth, peer_cfg, FALSE, num);
|
||||
}
|
||||
child_cfg = child_cfg_create("load-test", 1200, 600, 0, NULL, TRUE,
|
||||
MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE);
|
||||
proposal = proposal_create_from_string(PROTO_ESP, "aes128-sha1");
|
||||
child_cfg->add_proposal(child_cfg, proposal);
|
||||
@@ -169,7 +255,6 @@ static void destroy(private_load_tester_config_t *this)
|
||||
load_tester_config_t *load_tester_config_create()
|
||||
{
|
||||
private_load_tester_config_t *this = malloc_thing(private_load_tester_config_t);
|
||||
char *authstr;
|
||||
|
||||
this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator;
|
||||
this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator;
|
||||
@@ -195,16 +280,10 @@ load_tester_config_t *load_tester_config_create()
|
||||
this->proposal = proposal_create_from_string(PROTO_IKE,
|
||||
"aes128-sha1-modp768");
|
||||
}
|
||||
authstr = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.load_tester.auth", "pubkey");
|
||||
if (streq(authstr, "psk"))
|
||||
{
|
||||
this->class = AUTH_CLASS_PSK;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->class = AUTH_CLASS_PUBKEY;
|
||||
}
|
||||
this->initiator_auth = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.load_tester.initiator_auth", "pubkey");
|
||||
this->responder_auth = lib->settings->get_str(lib->settings,
|
||||
"charon.plugins.load_tester.responder_auth", "pubkey");
|
||||
|
||||
this->num = 1;
|
||||
this->peer_cfg = generate_config(this, 0);
|
||||
|
||||
@@ -259,9 +259,7 @@ static void set_username_password(private_nm_creds_t *this, identification_t *id
|
||||
{
|
||||
this->lock->write_lock(this->lock);
|
||||
DESTROY_IF(this->user);
|
||||
/* for EAP authentication, we use always use ID_EAP type */
|
||||
this->user = identification_create_from_encoding(ID_EAP,
|
||||
id->get_encoding(id));
|
||||
this->user = id->clone(id);
|
||||
free(this->pass);
|
||||
this->pass = password ? strdup(password) : NULL;
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
@@ -151,7 +151,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
|
||||
child_cfg_t *child_cfg;
|
||||
traffic_selector_t *ts;
|
||||
ike_sa_t *ike_sa;
|
||||
auth_info_t *auth;
|
||||
auth_cfg_t *auth;
|
||||
auth_class_t auth_class = AUTH_CLASS_EAP;
|
||||
certificate_t *cert = NULL;
|
||||
bool agent = FALSE;
|
||||
@@ -223,8 +223,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
|
||||
str = nm_setting_vpn_get_data_item(settings, "user");
|
||||
if (str)
|
||||
{
|
||||
user = identification_create_from_encoding(ID_KEY_ID,
|
||||
chunk_create(str, strlen(str)));
|
||||
user = identification_create_from_string(str);
|
||||
str = nm_setting_vpn_get_secret(settings, "password");
|
||||
creds->set_username_password(creds, user, (char*)str);
|
||||
}
|
||||
@@ -322,15 +321,21 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
|
||||
ike_cfg = ike_cfg_create(TRUE, encap, "0.0.0.0", (char*)address);
|
||||
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
|
||||
peer_cfg = peer_cfg_create(CONFIG_NAME, 2, ike_cfg,
|
||||
user, gateway->clone(gateway),
|
||||
CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
|
||||
36000, 0, /* rekey 10h, reauth none */
|
||||
600, 600, /* jitter, over 10min */
|
||||
TRUE, 0, /* mobike, DPD */
|
||||
virtual ? host_create_from_string("0.0.0.0", 0) : NULL,
|
||||
NULL, FALSE, NULL, NULL); /* pool, mediation */
|
||||
auth = peer_cfg->get_auth(peer_cfg);
|
||||
auth->add_item(auth, AUTHN_AUTH_CLASS, &auth_class);
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, user);
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, gateway->clone(gateway));
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
|
||||
|
||||
child_cfg = child_cfg_create(CONFIG_NAME,
|
||||
10800, 10200, /* lifetime 3h, rekey 2h50min */
|
||||
300, /* jitter 5min */
|
||||
|
||||
@@ -294,8 +294,9 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write
|
||||
/* <configlist> */
|
||||
xmlTextWriterStartElement(writer, "configlist");
|
||||
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
|
||||
while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
|
||||
NULL, NULL, NULL, NULL);
|
||||
while (enumerator->enumerate(enumerator, &peer_cfg))
|
||||
{
|
||||
enumerator_t *children;
|
||||
child_cfg_t *child_cfg;
|
||||
@@ -310,8 +311,8 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write
|
||||
/* <peerconfig> */
|
||||
xmlTextWriterStartElement(writer, "peerconfig");
|
||||
xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg));
|
||||
write_id(writer, "local", peer_cfg->get_my_id(peer_cfg));
|
||||
write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg));
|
||||
|
||||
/* TODO: write auth_cfgs */
|
||||
|
||||
/* <ikeconfig> */
|
||||
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
|
||||
|
||||
@@ -401,11 +401,6 @@ static enumerator_t *create_lease_query(char *filter)
|
||||
{
|
||||
id = identification_create_from_string(value);
|
||||
}
|
||||
if (!id)
|
||||
{
|
||||
fprintf(stderr, "invalid 'id' in filter string.\n");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case FIL_ADDR:
|
||||
if (value)
|
||||
|
||||
@@ -179,7 +179,7 @@ static host_t *get_address(private_sql_attribute_t *this, char *name,
|
||||
*/
|
||||
static host_t* acquire_address(private_sql_attribute_t *this,
|
||||
char *name, identification_t *id,
|
||||
auth_info_t *auth, host_t *requested)
|
||||
host_t *requested)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
u_int pool, timeout, identity;
|
||||
@@ -263,7 +263,7 @@ sql_attribute_t *sql_attribute_create(database_t *db)
|
||||
private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t);
|
||||
time_t now = time(NULL);
|
||||
|
||||
this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address;
|
||||
this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))acquire_address;
|
||||
this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address;
|
||||
this->public.destroy = (void(*)(sql_attribute_t*))destroy;
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
|
||||
peer_cfg_t *peer_cfg, *mediated_cfg;
|
||||
ike_cfg_t *ike;
|
||||
host_t *vip = NULL;
|
||||
auth_info_t *auth;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
local_id = identification_create_from_encoding(l_type, l_data);
|
||||
remote_id = identification_create_from_encoding(r_type, r_data);
|
||||
@@ -291,20 +291,26 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
|
||||
if (ike)
|
||||
{
|
||||
peer_cfg = peer_cfg_create(
|
||||
name, 2, ike, local_id, remote_id, cert_policy, uniqueid,
|
||||
name, 2, ike, cert_policy, uniqueid,
|
||||
keyingtries, rekeytime, reauthtime, jitter, overtime,
|
||||
mobike, dpd_delay, vip, pool,
|
||||
mediation, mediated_cfg, peer_id);
|
||||
auth = peer_cfg->get_auth(peer_cfg);
|
||||
auth->add_item(auth, AUTHN_AUTH_CLASS, &auth_method);
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, local_id->clone(local_id));
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_IDENTITY, remote_id->clone(remote_id));
|
||||
if (eap_type)
|
||||
{
|
||||
auth->add_item(auth, AUTHN_EAP_TYPE, &eap_type);
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
|
||||
auth->add(auth, AUTH_RULE_EAP_TYPE, eap_type);
|
||||
if (eap_vendor)
|
||||
{
|
||||
auth->add_item(auth, AUTHN_EAP_VENDOR, &eap_vendor);
|
||||
auth->add(auth, AUTH_RULE_EAP_VENDOR, eap_vendor);
|
||||
}
|
||||
}
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
|
||||
add_child_cfgs(this, peer_cfg, id);
|
||||
return peer_cfg;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ int host2offset(pool_t *pool, host_t *addr)
|
||||
*/
|
||||
static host_t* acquire_address(private_stroke_attribute_t *this,
|
||||
char *name, identification_t *id,
|
||||
auth_info_t *auth, host_t *requested)
|
||||
host_t *requested)
|
||||
{
|
||||
pool_t *pool;
|
||||
uintptr_t offset = 0;
|
||||
@@ -530,7 +530,7 @@ stroke_attribute_t *stroke_attribute_create()
|
||||
{
|
||||
private_stroke_attribute_t *this = malloc_thing(private_stroke_attribute_t);
|
||||
|
||||
this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address;
|
||||
this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,host_t *))acquire_address;
|
||||
this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address;
|
||||
this->public.add_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))add_pool;
|
||||
this->public.del_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))del_pool;
|
||||
|
||||
@@ -54,49 +54,6 @@ struct private_stroke_config_t {
|
||||
stroke_cred_t *cred;
|
||||
};
|
||||
|
||||
/**
|
||||
* data to pass peer_filter
|
||||
*/
|
||||
typedef struct {
|
||||
private_stroke_config_t *this;
|
||||
identification_t *me;
|
||||
identification_t *other;
|
||||
} peer_data_t;
|
||||
|
||||
/**
|
||||
* destroy id enumerator data and unlock list
|
||||
*/
|
||||
static void peer_data_destroy(peer_data_t *data)
|
||||
{
|
||||
data->this->mutex->unlock(data->this->mutex);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* filter function for peer configs
|
||||
*/
|
||||
static bool peer_filter(peer_data_t *data, peer_cfg_t **in, peer_cfg_t **out)
|
||||
{
|
||||
bool match_me = FALSE, match_other = FALSE;
|
||||
identification_t *me, *other;
|
||||
|
||||
me = (*in)->get_my_id(*in);
|
||||
other = (*in)->get_other_id(*in);
|
||||
|
||||
/* own ID may have wildcards in data (no IDr payload) or in config */
|
||||
match_me = (!data->me || data->me->matches(data->me, me) ||
|
||||
me->matches(me, data->me));
|
||||
/* others ID has wildcards in config only */
|
||||
match_other = (!data->other || data->other->matches(data->other, other));
|
||||
|
||||
if (match_me && match_other)
|
||||
{
|
||||
*out = *in;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of backend_t.create_peer_cfg_enumerator.
|
||||
*/
|
||||
@@ -104,41 +61,15 @@ static enumerator_t* create_peer_cfg_enumerator(private_stroke_config_t *this,
|
||||
identification_t *me,
|
||||
identification_t *other)
|
||||
{
|
||||
peer_data_t *data;
|
||||
|
||||
data = malloc_thing(peer_data_t);
|
||||
data->this = this;
|
||||
data->me = me;
|
||||
data->other = other;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
return enumerator_create_filter(this->list->create_enumerator(this->list),
|
||||
(void*)peer_filter, data,
|
||||
(void*)peer_data_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* data to pass ike_filter
|
||||
*/
|
||||
typedef struct {
|
||||
private_stroke_config_t *this;
|
||||
host_t *me;
|
||||
host_t *other;
|
||||
} ike_data_t;
|
||||
|
||||
/**
|
||||
* destroy id enumerator data and unlock list
|
||||
*/
|
||||
static void ike_data_destroy(ike_data_t *data)
|
||||
{
|
||||
data->this->mutex->unlock(data->this->mutex);
|
||||
free(data);
|
||||
return enumerator_create_cleaner(this->list->create_enumerator(this->list),
|
||||
(void*)this->mutex->unlock, this->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* filter function for ike configs
|
||||
*/
|
||||
static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out)
|
||||
static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
|
||||
{
|
||||
*out = (*in)->get_ike_cfg(*in);
|
||||
return TRUE;
|
||||
@@ -150,17 +81,10 @@ static bool ike_filter(ike_data_t *data, peer_cfg_t **in, ike_cfg_t **out)
|
||||
static enumerator_t* create_ike_cfg_enumerator(private_stroke_config_t *this,
|
||||
host_t *me, host_t *other)
|
||||
{
|
||||
ike_data_t *data;
|
||||
|
||||
data = malloc_thing(ike_data_t);
|
||||
data->this = this;
|
||||
data->me = me;
|
||||
data->other = other;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
return enumerator_create_filter(this->list->create_enumerator(this->list),
|
||||
(void*)ike_filter, data,
|
||||
(void*)ike_data_destroy);
|
||||
(void*)ike_filter, this->mutex,
|
||||
(void*)this->mutex->unlock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,56 +95,40 @@ static peer_cfg_t *get_peer_cfg_by_name(private_stroke_config_t *this, char *nam
|
||||
enumerator_t *e1, *e2;
|
||||
peer_cfg_t *current, *found = NULL;
|
||||
child_cfg_t *child;
|
||||
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
e1 = this->list->create_enumerator(this->list);
|
||||
while (e1->enumerate(e1, ¤t))
|
||||
{
|
||||
/* compare peer_cfgs name first */
|
||||
if (streq(current->get_name(current), name))
|
||||
{
|
||||
found = current;
|
||||
found->get_ref(found);
|
||||
break;
|
||||
}
|
||||
/* compare all child_cfg names otherwise */
|
||||
e2 = current->create_child_cfg_enumerator(current);
|
||||
while (e2->enumerate(e2, &child))
|
||||
{
|
||||
if (streq(child->get_name(child), name))
|
||||
{
|
||||
found = current;
|
||||
found->get_ref(found);
|
||||
break;
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* compare peer_cfgs name first */
|
||||
if (streq(current->get_name(current), name))
|
||||
{
|
||||
found = current;
|
||||
found->get_ref(found);
|
||||
break;
|
||||
}
|
||||
/* compare all child_cfg names otherwise */
|
||||
e2 = current->create_child_cfg_enumerator(current);
|
||||
while (e2->enumerate(e2, &child))
|
||||
{
|
||||
if (streq(child->get_name(child), name))
|
||||
{
|
||||
found = current;
|
||||
found->get_ref(found);
|
||||
break;
|
||||
}
|
||||
}
|
||||
e2->destroy(e2);
|
||||
if (found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
e1->destroy(e1);
|
||||
this->mutex->unlock(this->mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a certificate has an ID
|
||||
*/
|
||||
static identification_t *update_peerid(certificate_t *cert, identification_t *id)
|
||||
{
|
||||
if (id->get_type(id) == ID_ANY || !cert->has_subject(cert, id))
|
||||
{
|
||||
DBG1(DBG_CFG, " peerid %D not confirmed by certificate, "
|
||||
"defaulting to subject DN", id);
|
||||
id->destroy(id);
|
||||
id = cert->get_subject(cert);
|
||||
return id->clone(id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a proposal string, either into ike_cfg or child_cfg
|
||||
*/
|
||||
@@ -332,45 +240,303 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
|
||||
add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
|
||||
return ike_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add CRL constraint to config
|
||||
*/
|
||||
static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
|
||||
{
|
||||
/* CRL/OCSP policy, for remote config only */
|
||||
if (!local)
|
||||
{
|
||||
switch (policy)
|
||||
{
|
||||
case CRL_STRICT_YES:
|
||||
/* if yes, we require a GOOD validation */
|
||||
cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
|
||||
break;
|
||||
case CRL_STRICT_IFURI:
|
||||
/* for ifuri, a SKIPPED validation is sufficient */
|
||||
cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build authentication config
|
||||
*/
|
||||
static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
|
||||
stroke_msg_t *msg, bool local, bool primary)
|
||||
{
|
||||
identification_t *identity;
|
||||
certificate_t *certificate;
|
||||
char *auth, *id, *cert, *ca;
|
||||
stroke_end_t *end, *other_end;
|
||||
auth_cfg_t *cfg;
|
||||
char eap_buf[32];
|
||||
|
||||
/* select strings */
|
||||
if (local)
|
||||
{
|
||||
end = &msg->add_conn.me;
|
||||
other_end = &msg->add_conn.other;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = &msg->add_conn.other;
|
||||
other_end = &msg->add_conn.me;
|
||||
}
|
||||
if (primary)
|
||||
{
|
||||
auth = end->auth;
|
||||
id = end->id;
|
||||
if (!id)
|
||||
{ /* leftid/rightid fallback to address */
|
||||
id = end->address;
|
||||
}
|
||||
cert = end->cert;
|
||||
ca = end->ca;
|
||||
if (ca && streq(ca, "%same"))
|
||||
{
|
||||
ca = other_end->ca;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auth = end->auth2;
|
||||
id = end->id2;
|
||||
if (local && !id)
|
||||
{ /* leftid2 falls back to leftid */
|
||||
id = end->id;
|
||||
}
|
||||
cert = end->cert2;
|
||||
ca = end->ca2;
|
||||
if (ca && streq(ca, "%same"))
|
||||
{
|
||||
ca = other_end->ca2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!auth)
|
||||
{
|
||||
if (primary)
|
||||
{
|
||||
if (local)
|
||||
{ /* "leftauth" not defined, fall back to deprecated "authby" */
|
||||
switch (msg->add_conn.auth_method)
|
||||
{
|
||||
default:
|
||||
case AUTH_CLASS_PUBKEY:
|
||||
auth = "pubkey";
|
||||
break;
|
||||
case AUTH_CLASS_PSK:
|
||||
auth = "psk";
|
||||
break;
|
||||
case AUTH_CLASS_EAP:
|
||||
auth = "eap";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* "rightauth" not defined, fall back to deprecated "eap" */
|
||||
if (msg->add_conn.eap_type)
|
||||
{
|
||||
if (msg->add_conn.eap_vendor)
|
||||
{
|
||||
snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d",
|
||||
msg->add_conn.eap_type,
|
||||
msg->add_conn.eap_vendor);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(eap_buf, sizeof(eap_buf), "eap-%d",
|
||||
msg->add_conn.eap_type);
|
||||
}
|
||||
auth = eap_buf;
|
||||
}
|
||||
else
|
||||
{ /* not EAP => no constraints for this peer */
|
||||
auth = "any";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* no second authentication round, fine */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cfg = auth_cfg_create();
|
||||
|
||||
/* add identity and peer certifcate */
|
||||
identity = identification_create_from_string(id);
|
||||
if (cert)
|
||||
{
|
||||
certificate = this->cred->load_peer(this->cred, cert);
|
||||
if (certificate)
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
this->ca->check_for_hash_and_url(this->ca, certificate);
|
||||
}
|
||||
cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
|
||||
if (identity->get_type(identity) == ID_ANY ||
|
||||
!certificate->has_subject(certificate, identity))
|
||||
{
|
||||
DBG1(DBG_CFG, " peerid %D not confirmed by certificate, "
|
||||
"defaulting to subject DN: %D", identity,
|
||||
certificate->get_subject(certificate));
|
||||
identity->destroy(identity);
|
||||
identity = certificate->get_subject(certificate);
|
||||
identity = identity->clone(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
|
||||
|
||||
/* CA constraint */
|
||||
if (ca)
|
||||
{
|
||||
identity = identification_create_from_string(ca);
|
||||
certificate = charon->credentials->get_cert(charon->credentials,
|
||||
CERT_X509, KEY_ANY, identity, TRUE);
|
||||
identity->destroy(identity);
|
||||
if (certificate)
|
||||
{
|
||||
cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "CA certificate %s not found, discarding CA "
|
||||
"constraint", ca);
|
||||
}
|
||||
}
|
||||
|
||||
/* AC groups */
|
||||
if (end->groups)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
char *group;
|
||||
|
||||
enumerator = enumerator_create_token(end->groups, ",", " ");
|
||||
while (enumerator->enumerate(enumerator, &group))
|
||||
{
|
||||
identity = identification_create_from_encoding(ID_IETF_ATTR_STRING,
|
||||
chunk_create(group, strlen(group)));
|
||||
cfg->add(cfg, AUTH_RULE_AC_GROUP, identity);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/* authentication metod (class, actually) */
|
||||
if (streq(auth, "pubkey") ||
|
||||
streq(auth, "rsasig") || streq(auth, "rsa") ||
|
||||
streq(auth, "ecdsasig") || streq(auth, "ecdsa"))
|
||||
{
|
||||
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
|
||||
build_crl_policy(cfg, local, msg->add_conn.crl_policy);
|
||||
}
|
||||
else if (streq(auth, "psk") || streq(auth, "secret"))
|
||||
{
|
||||
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
|
||||
}
|
||||
else if (strneq(auth, "eap", 3))
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
char *str;
|
||||
int i = 0, type = 0, vendor;
|
||||
|
||||
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
|
||||
|
||||
/* parse EAP string, format: eap[-type[-vendor]] */
|
||||
enumerator = enumerator_create_token(auth, "-", " ");
|
||||
while (enumerator->enumerate(enumerator, &str))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
type = eap_type_from_string(str);
|
||||
if (!type)
|
||||
{
|
||||
type = atoi(str);
|
||||
if (!type)
|
||||
{
|
||||
DBG1(DBG_CFG, "unknown EAP method: %s", str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
|
||||
break;
|
||||
case 2:
|
||||
if (type)
|
||||
{
|
||||
vendor = atoi(str);
|
||||
if (vendor)
|
||||
{
|
||||
cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (msg->add_conn.eap_identity)
|
||||
{
|
||||
if (streq(msg->add_conn.eap_identity, "%identity"))
|
||||
{
|
||||
identity = identification_create_from_encoding(ID_ANY,
|
||||
chunk_empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
identity = identification_create_from_string(
|
||||
msg->add_conn.eap_identity);
|
||||
}
|
||||
cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!streq(auth, "any"))
|
||||
{
|
||||
DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
|
||||
auth);
|
||||
}
|
||||
build_crl_policy(cfg, local, msg->add_conn.crl_policy);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* build a peer_cfg from a stroke msg
|
||||
*/
|
||||
static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
|
||||
stroke_msg_t *msg, ike_cfg_t *ike_cfg,
|
||||
identification_t **my_issuer,
|
||||
identification_t **other_issuer)
|
||||
stroke_msg_t *msg, ike_cfg_t *ike_cfg)
|
||||
{
|
||||
identification_t *me, *other, *peer_id = NULL;
|
||||
identification_t *peer_id = NULL;
|
||||
peer_cfg_t *mediated_by = NULL;
|
||||
host_t *vip = NULL;
|
||||
certificate_t *cert;
|
||||
unique_policy_t unique;
|
||||
u_int32_t rekey = 0, reauth = 0, over, jitter;
|
||||
|
||||
me = identification_create_from_string(msg->add_conn.me.id ?
|
||||
msg->add_conn.me.id : msg->add_conn.me.address);
|
||||
if (!me)
|
||||
{
|
||||
DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
|
||||
return NULL;
|
||||
}
|
||||
other = identification_create_from_string(msg->add_conn.other.id ?
|
||||
msg->add_conn.other.id : msg->add_conn.other.address);
|
||||
if (!other)
|
||||
{
|
||||
DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
|
||||
me->destroy(me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peer_cfg_t *peer_cfg;
|
||||
auth_cfg_t *auth_cfg;
|
||||
|
||||
#ifdef ME
|
||||
if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
|
||||
{
|
||||
DBG1(DBG_CFG, "a mediation connection cannot be a"
|
||||
" mediated connection at the same time, aborting");
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -388,8 +554,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
|
||||
{
|
||||
DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
|
||||
msg->add_conn.ikeme.mediated_by);
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -399,56 +563,19 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
|
||||
"no mediation connection, aborting",
|
||||
msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
|
||||
mediated_by->destroy(mediated_by);
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->add_conn.ikeme.peerid)
|
||||
{
|
||||
peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
|
||||
if (!peer_id)
|
||||
if (msg->add_conn.ikeme.peerid)
|
||||
{
|
||||
DBG1(DBG_CFG, "invalid peer ID: %s\n", msg->add_conn.ikeme.peerid);
|
||||
mediated_by->destroy(mediated_by);
|
||||
me->destroy(me);
|
||||
other->destroy(other);
|
||||
return NULL;
|
||||
peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
|
||||
}
|
||||
else if (msg->add_conn.other.id)
|
||||
{
|
||||
peer_id = identification_create_from_string(msg->add_conn.other.id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no peer ID supplied, assume right ID */
|
||||
peer_id = other->clone(other);
|
||||
}
|
||||
#endif /* ME */
|
||||
|
||||
if (msg->add_conn.me.cert)
|
||||
{
|
||||
cert = this->cred->load_peer(this->cred, msg->add_conn.me.cert);
|
||||
if (cert)
|
||||
{
|
||||
identification_t *issuer = cert->get_issuer(cert);
|
||||
|
||||
*my_issuer = issuer->clone(issuer);
|
||||
this->ca->check_for_hash_and_url(this->ca, cert);
|
||||
me = update_peerid(cert, me);
|
||||
cert->destroy(cert);
|
||||
}
|
||||
}
|
||||
if (msg->add_conn.other.cert)
|
||||
{
|
||||
cert = this->cred->load_peer(this->cred, msg->add_conn.other.cert);
|
||||
if (cert)
|
||||
{
|
||||
identification_t *issuer = cert->get_issuer(cert);
|
||||
|
||||
*other_issuer = issuer->clone(issuer);
|
||||
other = update_peerid(cert, other);
|
||||
cert->destroy(cert);
|
||||
}
|
||||
}
|
||||
jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
|
||||
over = msg->add_conn.rekey.margin;
|
||||
if (msg->add_conn.rekey.reauth)
|
||||
@@ -512,179 +639,45 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
|
||||
/* other.sourceip is managed in stroke_attributes. If it is set, we define
|
||||
* the pool name as the connection name, which the attribute provider
|
||||
* uses to serve pool addresses. */
|
||||
return peer_cfg_create(msg->add_conn.name,
|
||||
msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
|
||||
peer_cfg = peer_cfg_create(msg->add_conn.name,
|
||||
msg->add_conn.ikev2 ? 2 : 1, ike_cfg,
|
||||
msg->add_conn.me.sendcert, unique,
|
||||
msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
|
||||
msg->add_conn.mobike, msg->add_conn.dpd.delay,
|
||||
vip, msg->add_conn.other.sourceip_size ?
|
||||
msg->add_conn.name : msg->add_conn.other.sourceip,
|
||||
msg->add_conn.ikeme.mediation, mediated_by, peer_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill in auth_info from stroke message
|
||||
*/
|
||||
static void build_auth_info(private_stroke_config_t *this,
|
||||
stroke_msg_t *msg, auth_info_t *auth,
|
||||
identification_t *my_ca,
|
||||
identification_t *other_ca)
|
||||
{
|
||||
identification_t *id;
|
||||
bool my_ca_same = FALSE;
|
||||
bool other_ca_same = FALSE;
|
||||
cert_validation_t valid;
|
||||
|
||||
switch (msg->add_conn.crl_policy)
|
||||
{
|
||||
case CRL_STRICT_YES:
|
||||
valid = VALIDATION_GOOD;
|
||||
auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
|
||||
break;
|
||||
case CRL_STRICT_IFURI:
|
||||
valid = VALIDATION_SKIPPED;
|
||||
auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg->add_conn.me.ca)
|
||||
/* build leftauth= */
|
||||
auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
|
||||
if (auth_cfg)
|
||||
{
|
||||
if (my_ca)
|
||||
{
|
||||
my_ca->destroy(my_ca);
|
||||
my_ca = NULL;
|
||||
}
|
||||
if (streq(msg->add_conn.me.ca, "%same"))
|
||||
{
|
||||
my_ca_same = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_ca = identification_create_from_string(msg->add_conn.me.ca);
|
||||
}
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
|
||||
}
|
||||
|
||||
if (msg->add_conn.other.ca)
|
||||
else
|
||||
{ /* we require at least one config on our side */
|
||||
peer_cfg->destroy(peer_cfg);
|
||||
return NULL;
|
||||
}
|
||||
/* build leftauth2= */
|
||||
auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
|
||||
if (auth_cfg)
|
||||
{
|
||||
if (other_ca)
|
||||
{
|
||||
other_ca->destroy(other_ca);
|
||||
other_ca = NULL;
|
||||
}
|
||||
if (streq(msg->add_conn.other.ca, "%same"))
|
||||
{
|
||||
other_ca_same = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
other_ca = identification_create_from_string(msg->add_conn.other.ca);
|
||||
}
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
|
||||
}
|
||||
|
||||
if (other_ca_same && my_ca)
|
||||
/* build rightauth= */
|
||||
auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
|
||||
if (auth_cfg)
|
||||
{
|
||||
other_ca = my_ca->clone(my_ca);
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
|
||||
}
|
||||
else if (my_ca_same && other_ca)
|
||||
/* build rightauth2= */
|
||||
auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
|
||||
if (auth_cfg)
|
||||
{
|
||||
my_ca = other_ca->clone(other_ca);
|
||||
}
|
||||
|
||||
if (other_ca)
|
||||
{
|
||||
DBG2(DBG_CFG, " other ca: %D", other_ca);
|
||||
certificate_t *cert = charon->credentials->get_cert(charon->credentials,
|
||||
CERT_X509, KEY_ANY, other_ca, TRUE);
|
||||
if (cert)
|
||||
{
|
||||
auth->add_item(auth, AUTHZ_CA_CERT, cert);
|
||||
cert->destroy(cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
auth->add_item(auth, AUTHZ_CA_CERT_NAME, other_ca);
|
||||
}
|
||||
other_ca->destroy(other_ca);
|
||||
}
|
||||
|
||||
if (my_ca)
|
||||
{
|
||||
DBG2(DBG_CFG, " my ca: %D", my_ca);
|
||||
certificate_t *cert = charon->credentials->get_cert(charon->credentials,
|
||||
CERT_X509, KEY_ANY, my_ca, TRUE);
|
||||
if (cert)
|
||||
{
|
||||
auth->add_item(auth, AUTHN_CA_CERT, cert);
|
||||
cert->destroy(cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
auth->add_item(auth, AUTHN_CA_CERT_NAME, my_ca);
|
||||
}
|
||||
my_ca->destroy(my_ca);
|
||||
}
|
||||
auth->add_item(auth, AUTHN_AUTH_CLASS, &msg->add_conn.auth_method);
|
||||
if (msg->add_conn.eap_type)
|
||||
{
|
||||
auth->add_item(auth, AUTHN_EAP_TYPE, &msg->add_conn.eap_type);
|
||||
if (msg->add_conn.eap_vendor)
|
||||
{
|
||||
auth->add_item(auth, AUTHN_EAP_VENDOR, &msg->add_conn.eap_vendor);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->add_conn.eap_identity)
|
||||
{
|
||||
if (streq(msg->add_conn.eap_identity, "%identity"))
|
||||
{
|
||||
id = identification_create_from_encoding(ID_ANY, chunk_empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = identification_create_from_encoding(ID_EAP, chunk_create(
|
||||
msg->add_conn.eap_identity,
|
||||
strlen(msg->add_conn.eap_identity)));
|
||||
}
|
||||
auth->add_item(auth, AUTHN_EAP_IDENTITY, id);
|
||||
id->destroy(id);
|
||||
}
|
||||
|
||||
if (msg->add_conn.other.groups)
|
||||
{
|
||||
chunk_t line = { msg->add_conn.other.groups,
|
||||
strlen(msg->add_conn.other.groups) };
|
||||
|
||||
while (eat_whitespace(&line))
|
||||
{
|
||||
chunk_t group;
|
||||
|
||||
/* extract the next comma-separated group attribute */
|
||||
if (!extract_token(&group, ',', &line))
|
||||
{
|
||||
group = line;
|
||||
line.len = 0;
|
||||
}
|
||||
|
||||
/* remove any trailing spaces */
|
||||
while (group.len > 0 && *(group.ptr + group.len - 1) == ' ')
|
||||
{
|
||||
group.len--;
|
||||
}
|
||||
|
||||
/* add the group attribute to the list */
|
||||
if (group.len > 0)
|
||||
{
|
||||
identification_t *ac_group;
|
||||
|
||||
ac_group = identification_create_from_encoding(
|
||||
ID_IETF_ATTR_STRING, group);
|
||||
auth->add_item(auth, AUTHZ_AC_GROUP, ac_group);
|
||||
ac_group->destroy(ac_group);
|
||||
}
|
||||
}
|
||||
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
|
||||
}
|
||||
return peer_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -799,7 +792,6 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg)
|
||||
ike_cfg_t *ike_cfg, *existing_ike;
|
||||
peer_cfg_t *peer_cfg, *existing;
|
||||
child_cfg_t *child_cfg;
|
||||
identification_t *my_issuer = NULL, *other_issuer = NULL;
|
||||
enumerator_t *enumerator;
|
||||
bool use_existing = FALSE;
|
||||
|
||||
@@ -808,15 +800,13 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
peer_cfg = build_peer_cfg(this, msg, ike_cfg, &my_issuer, &other_issuer);
|
||||
peer_cfg = build_peer_cfg(this, msg, ike_cfg);
|
||||
if (!peer_cfg)
|
||||
{
|
||||
ike_cfg->destroy(ike_cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
build_auth_info(this, msg, peer_cfg->get_auth(peer_cfg),
|
||||
my_issuer, other_issuer);
|
||||
enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
|
||||
while (enumerator->enumerate(enumerator, &existing))
|
||||
{
|
||||
@@ -850,9 +840,7 @@ static void add(private_stroke_config_t *this, stroke_msg_t *msg)
|
||||
else
|
||||
{
|
||||
/* add config to backend */
|
||||
DBG1(DBG_CFG, "added configuration '%s': %s[%D]...%s[%D]", msg->add_conn.name,
|
||||
ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
|
||||
ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
|
||||
DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
|
||||
this->mutex->lock(this->mutex);
|
||||
this->list->insert_last(this->list, peer_cfg);
|
||||
this->mutex->unlock(this->mutex);
|
||||
|
||||
@@ -905,26 +905,13 @@ static void load_secrets(private_stroke_cred_t *this)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == SHARED_EAP)
|
||||
/* NULL terminate the ID string */
|
||||
*(id.ptr + id.len) = '\0';
|
||||
peer_id = identification_create_from_string(id.ptr);
|
||||
if (peer_id->get_type(peer_id) == ID_ANY)
|
||||
{
|
||||
/* we use a special EAP identity type for EAP secrets */
|
||||
peer_id = identification_create_from_encoding(ID_EAP, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NULL terminate the ID string */
|
||||
*(id.ptr + id.len) = '\0';
|
||||
peer_id = identification_create_from_string(id.ptr);
|
||||
if (peer_id == NULL)
|
||||
{
|
||||
DBG1(DBG_CFG, "line %d: malformed ID: %s", line_nr, id.ptr);
|
||||
goto error;
|
||||
}
|
||||
if (peer_id->get_type(peer_id) == ID_ANY)
|
||||
{
|
||||
peer_id->destroy(peer_id);
|
||||
continue;
|
||||
}
|
||||
peer_id->destroy(peer_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
shared_key->add_owner(shared_key, peer_id);
|
||||
|
||||
@@ -54,23 +54,6 @@ struct private_stroke_list_t {
|
||||
stroke_attribute_t *attribute;
|
||||
};
|
||||
|
||||
/**
|
||||
* get the authentication class of a config
|
||||
*/
|
||||
auth_class_t get_auth_class(peer_cfg_t *config)
|
||||
{
|
||||
auth_class_t *class;
|
||||
auth_info_t *auth_info;
|
||||
|
||||
auth_info = config->get_auth(config);
|
||||
if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class))
|
||||
{
|
||||
return *class;
|
||||
}
|
||||
/* fallback to pubkey authentication */
|
||||
return AUTH_CLASS_PUBKEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* log an IKE_SA to out
|
||||
*/
|
||||
@@ -110,9 +93,11 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
|
||||
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
|
||||
{
|
||||
time_t rekey, reauth;
|
||||
peer_cfg_t *peer_cfg;
|
||||
|
||||
rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY);
|
||||
reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
|
||||
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
|
||||
|
||||
if (rekey)
|
||||
{
|
||||
@@ -120,9 +105,24 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
|
||||
}
|
||||
if (reauth)
|
||||
{
|
||||
fprintf(out, ", %N reauthentication in %V", auth_class_names,
|
||||
get_auth_class(ike_sa->get_peer_cfg(ike_sa)),
|
||||
&reauth, &now);
|
||||
bool first = TRUE;
|
||||
enumerator_t *enumerator;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
fprintf(out, ", ");
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, TRUE);
|
||||
while (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
fprintf(out, "+");
|
||||
}
|
||||
first = FALSE;
|
||||
fprintf(out, "%N", auth_class_names,
|
||||
auth->get(auth, AUTH_RULE_AUTH_CLASS));
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
fprintf(out, " reauthentication in %V", &reauth, &now);
|
||||
}
|
||||
if (!rekey && !reauth)
|
||||
{
|
||||
@@ -247,6 +247,107 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a configs local or remote authentication config to out
|
||||
*/
|
||||
static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
|
||||
{
|
||||
enumerator_t *enumerator, *rules;
|
||||
auth_rule_t rule;
|
||||
auth_cfg_t *auth;
|
||||
auth_class_t auth_class;
|
||||
identification_t *id;
|
||||
certificate_t *cert;
|
||||
cert_validation_t valid;
|
||||
char *name;
|
||||
|
||||
name = peer_cfg->get_name(peer_cfg);
|
||||
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
|
||||
while (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
fprintf(out, "%12s: %s [%D] uses ", name, local ? "local: " : "remote:",
|
||||
auth->get(auth, AUTH_RULE_IDENTITY));
|
||||
|
||||
auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
|
||||
if (auth_class != AUTH_CLASS_EAP)
|
||||
{
|
||||
fprintf(out, "%N authentication\n", auth_class_names, auth_class);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK)
|
||||
{
|
||||
fprintf(out, "EAP authentication");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR))
|
||||
{
|
||||
fprintf(out, "EAP_%d-%d authentication",
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE),
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(out, "%N authentication", eap_type_names,
|
||||
(uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE));
|
||||
}
|
||||
}
|
||||
id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
|
||||
if (id)
|
||||
{
|
||||
fprintf(out, " with EAP identity '%D'", id);
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
|
||||
cert = auth->get(auth, AUTH_RULE_CA_CERT);
|
||||
if (cert)
|
||||
{
|
||||
fprintf(out, "%12s: ca: \"%D\"\n", name, cert->get_subject(cert));
|
||||
}
|
||||
|
||||
cert = auth->get(auth, AUTH_RULE_IM_CERT);
|
||||
if (cert)
|
||||
{
|
||||
fprintf(out, "%12s: im-ca: \"%D\"\n", name, cert->get_subject(cert));
|
||||
}
|
||||
|
||||
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (cert)
|
||||
{
|
||||
fprintf(out, "%12s: cert: \"%D\"\n", name,
|
||||
cert->get_subject(cert));
|
||||
}
|
||||
|
||||
valid = (uintptr_t)auth->get(auth, AUTH_RULE_OCSP_VALIDATION);
|
||||
if (valid != VALIDATION_FAILED)
|
||||
{
|
||||
fprintf(out, "%12s: ocsp: status must be GOOD%s\n", name,
|
||||
(valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
|
||||
}
|
||||
|
||||
valid = (uintptr_t)auth->get(auth, AUTH_RULE_CRL_VALIDATION);
|
||||
if (valid != VALIDATION_FAILED)
|
||||
{
|
||||
fprintf(out, "%12s: crl: status must be GOOD%s\n", name,
|
||||
(valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
|
||||
}
|
||||
|
||||
rules = auth->create_enumerator(auth);
|
||||
while (rules->enumerate(rules, &rule, &id))
|
||||
{
|
||||
if (rule == AUTH_RULE_AC_GROUP)
|
||||
{
|
||||
fprintf(out, "%12s: group: %D\n", name, id);
|
||||
}
|
||||
}
|
||||
rules->destroy(rules);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of stroke_list_t.status.
|
||||
*/
|
||||
@@ -313,138 +414,42 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
fprintf(out, "Connections:\n");
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
|
||||
while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
|
||||
enumerator = charon->backends->create_peer_cfg_enumerator(
|
||||
charon->backends, NULL, NULL, NULL, NULL);
|
||||
while (enumerator->enumerate(enumerator, &peer_cfg))
|
||||
{
|
||||
void *ptr;
|
||||
certificate_t *cert;
|
||||
auth_item_t item;
|
||||
auth_info_t *auth;
|
||||
enumerator_t *auth_enumerator;
|
||||
identification_t *my_ca = NULL, *other_ca = NULL;
|
||||
identification_t *eap_identity = NULL;
|
||||
u_int32_t *eap_type = NULL;
|
||||
bool ac_groups = FALSE;
|
||||
|
||||
if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
|
||||
(name && !streq(name, peer_cfg->get_name(peer_cfg))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* determine any required CAs, EAP type, EAP identity,
|
||||
* and the presence of AC groups
|
||||
*/
|
||||
auth = peer_cfg->get_auth(peer_cfg);
|
||||
auth_enumerator = auth->create_item_enumerator(auth);
|
||||
while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
|
||||
{
|
||||
switch (item)
|
||||
{
|
||||
case AUTHN_EAP_TYPE:
|
||||
eap_type = (u_int32_t *)ptr;
|
||||
break;
|
||||
case AUTHN_EAP_IDENTITY:
|
||||
eap_identity = (identification_t *)ptr;
|
||||
break;
|
||||
case AUTHN_CA_CERT:
|
||||
cert = (certificate_t *)ptr;
|
||||
my_ca = cert->get_subject(cert);
|
||||
break;
|
||||
case AUTHN_CA_CERT_NAME:
|
||||
my_ca = (identification_t *)ptr;
|
||||
break;
|
||||
case AUTHZ_CA_CERT:
|
||||
cert = (certificate_t *)ptr;
|
||||
other_ca = cert->get_subject(cert);
|
||||
break;
|
||||
case AUTHZ_CA_CERT_NAME:
|
||||
other_ca = (identification_t *)ptr;
|
||||
break;
|
||||
case AUTHZ_AC_GROUP:
|
||||
ac_groups = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
auth_enumerator->destroy(auth_enumerator);
|
||||
|
||||
ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
|
||||
fprintf(out, "%12s: %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg),
|
||||
ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
|
||||
ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
|
||||
if (my_ca || other_ca)
|
||||
{
|
||||
fprintf(out, "%12s: CAs: ", peer_cfg->get_name(peer_cfg));
|
||||
if (my_ca)
|
||||
{
|
||||
fprintf(out, "\"%D\"...", my_ca);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(out, "%%any...");
|
||||
}
|
||||
if (other_ca)
|
||||
{
|
||||
fprintf(out, "\"%D\"\n", other_ca);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(out, "%%any\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (ac_groups)
|
||||
{
|
||||
bool first = TRUE;
|
||||
|
||||
fprintf(out, "%12s: groups: ", peer_cfg->get_name(peer_cfg));
|
||||
auth_enumerator = auth->create_item_enumerator(auth);
|
||||
while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
|
||||
{
|
||||
if (item == AUTHZ_AC_GROUP)
|
||||
{
|
||||
identification_t *group = (identification_t *)ptr;
|
||||
|
||||
fprintf(out, "%s%D", first? "":", ", group);
|
||||
first = FALSE;
|
||||
}
|
||||
}
|
||||
auth_enumerator->destroy(auth_enumerator);
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
|
||||
fprintf(out, "%12s: %N ", peer_cfg->get_name(peer_cfg),
|
||||
auth_class_names, get_auth_class(peer_cfg));
|
||||
if (eap_type)
|
||||
{
|
||||
fprintf(out, "and %N ", eap_type_names, *eap_type);
|
||||
}
|
||||
fprintf(out, "authentication");
|
||||
if (eap_identity)
|
||||
{
|
||||
fprintf(out, ", EAP identity: '%D'", eap_identity);
|
||||
}
|
||||
fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg),
|
||||
ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg));
|
||||
|
||||
dpd = peer_cfg->get_dpd(peer_cfg);
|
||||
if (dpd)
|
||||
{
|
||||
fprintf(out, ", dpddelay=%us", dpd);
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
|
||||
|
||||
log_auth_cfgs(out, peer_cfg, TRUE);
|
||||
log_auth_cfgs(out, peer_cfg, FALSE);
|
||||
|
||||
children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
|
||||
while (children->enumerate(children, &child_cfg))
|
||||
{
|
||||
linked_list_t *my_ts, *other_ts;
|
||||
|
||||
|
||||
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
|
||||
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
|
||||
fprintf(out, "%12s: %#R=== %#R", child_cfg->get_name(child_cfg),
|
||||
fprintf(out, "%12s: child: %#R=== %#R", child_cfg->get_name(child_cfg),
|
||||
my_ts, other_ts);
|
||||
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
|
||||
other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
|
||||
|
||||
|
||||
if (dpd)
|
||||
{
|
||||
fprintf(out, ", dpdaction=%N", action_names,
|
||||
|
||||
@@ -143,18 +143,28 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
|
||||
pop_string(msg, &end->address);
|
||||
pop_string(msg, &end->subnets);
|
||||
pop_string(msg, &end->sourceip);
|
||||
pop_string(msg, &end->auth);
|
||||
pop_string(msg, &end->auth2);
|
||||
pop_string(msg, &end->id);
|
||||
pop_string(msg, &end->id2);
|
||||
pop_string(msg, &end->cert);
|
||||
pop_string(msg, &end->cert2);
|
||||
pop_string(msg, &end->ca);
|
||||
pop_string(msg, &end->ca2);
|
||||
pop_string(msg, &end->groups);
|
||||
pop_string(msg, &end->updown);
|
||||
|
||||
DBG2(DBG_CFG, " %s=%s", label, end->address);
|
||||
DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
|
||||
DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
|
||||
DBG2(DBG_CFG, " %sauth=%s", label, end->auth);
|
||||
DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
|
||||
DBG2(DBG_CFG, " %sid=%s", label, end->id);
|
||||
DBG2(DBG_CFG, " %sid2=%s", label, end->id2);
|
||||
DBG2(DBG_CFG, " %scert=%s", label, end->cert);
|
||||
DBG2(DBG_CFG, " %scert2=%s", label, end->cert2);
|
||||
DBG2(DBG_CFG, " %sca=%s", label, end->ca);
|
||||
DBG2(DBG_CFG, " %sca2=%s", label, end->ca2);
|
||||
DBG2(DBG_CFG, " %sgroups=%s", label, end->groups);
|
||||
DBG2(DBG_CFG, " %supdown=%s", label, end->updown);
|
||||
}
|
||||
|
||||
@@ -82,24 +82,6 @@ static proposal_t *create_proposal(char *string, protocol_id_t proto)
|
||||
return proposal;
|
||||
}
|
||||
|
||||
/**
|
||||
* create an identity, with fallback to %any
|
||||
*/
|
||||
static identification_t *create_id(char *string)
|
||||
{
|
||||
identification_t *id = NULL;
|
||||
|
||||
if (string)
|
||||
{
|
||||
id = identification_create_from_string(string);
|
||||
}
|
||||
if (!id)
|
||||
{
|
||||
id = identification_create_from_encoding(ID_ANY, chunk_empty);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* create an traffic selector, fallback to dynamic
|
||||
*/
|
||||
@@ -163,8 +145,7 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
|
||||
char *remote_id, *remote_addr, *remote_net;
|
||||
child_cfg_t *child_cfg;
|
||||
ike_cfg_t *ike_cfg;
|
||||
auth_info_t *auth;
|
||||
auth_class_t class;
|
||||
auth_cfg_t *auth;
|
||||
|
||||
/* defaults */
|
||||
name = "unnamed";
|
||||
@@ -187,16 +168,26 @@ static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg)
|
||||
ike_cfg = ike_cfg_create(FALSE, FALSE, local_addr, remote_addr);
|
||||
ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE));
|
||||
this->peer_cfg = peer_cfg_create(
|
||||
name, 2, ike_cfg, create_id(local_id), create_id(remote_id),
|
||||
CERT_SEND_IF_ASKED, UNIQUE_NO,
|
||||
name, 2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO,
|
||||
1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */
|
||||
1800, 900, /* jitter, overtime */
|
||||
TRUE, 60, /* mobike, dpddelay */
|
||||
NULL, NULL, /* vip, pool */
|
||||
FALSE, NULL, NULL); /* mediation, med by, peer id */
|
||||
auth = this->peer_cfg->get_auth(this->peer_cfg);
|
||||
class = AUTH_CLASS_PSK;
|
||||
auth->add_item(auth, AUTHN_AUTH_CLASS, &class);
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
|
||||
auth->add(auth, AUTH_RULE_IDENTITY,
|
||||
identification_create_from_string(local_id));
|
||||
this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, TRUE);
|
||||
|
||||
auth = auth_cfg_create();
|
||||
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
|
||||
if (remote_id)
|
||||
{
|
||||
auth->add(auth, AUTH_RULE_IDENTITY,
|
||||
identification_create_from_string(remote_id));
|
||||
}
|
||||
this->peer_cfg->add_auth_cfg(this->peer_cfg, auth, FALSE);
|
||||
child_cfg = child_cfg_create(name,
|
||||
create_rekey(esp_rekey) + 300, create_rekey(ike_rekey), 300,
|
||||
NULL, TRUE, MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE);
|
||||
|
||||
@@ -39,15 +39,15 @@ typedef struct private_uci_control_t private_uci_control_t;
|
||||
* private data of uci_control_t
|
||||
*/
|
||||
struct private_uci_control_t {
|
||||
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
* Public part
|
||||
*/
|
||||
uci_control_t public;
|
||||
|
||||
|
||||
/**
|
||||
* Job
|
||||
*/
|
||||
* Job
|
||||
*/
|
||||
callback_job_t *job;
|
||||
};
|
||||
|
||||
@@ -86,13 +86,14 @@ static void status(private_uci_control_t *this, char *name)
|
||||
char buf[2048];
|
||||
FILE *out = NULL;
|
||||
|
||||
configs = charon->backends->create_peer_cfg_enumerator(charon->backends);
|
||||
while (configs->enumerate(configs, &peer_cfg))
|
||||
{
|
||||
if (name && !streq(name, peer_cfg->get_name(peer_cfg)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
configs = charon->backends->create_peer_cfg_enumerator(charon->backends,
|
||||
NULL, NULL, NULL, NULL);
|
||||
while (configs->enumerate(configs, &peer_cfg))
|
||||
{
|
||||
if (name && !streq(name, peer_cfg->get_name(peer_cfg)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sas = charon->controller->create_ike_sa_enumerator(charon->controller);
|
||||
while (sas->enumerate(sas, &ike_sa))
|
||||
{
|
||||
@@ -108,9 +109,9 @@ static void status(private_uci_control_t *this, char *name)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(out, "%-8s %-20D %-16H ", ike_sa->get_name(ike_sa),
|
||||
ike_sa->get_other_id(ike_sa), ike_sa->get_other_host(ike_sa));
|
||||
|
||||
fprintf(out, "%-8s %-20D %-16H ", ike_sa->get_name(ike_sa),
|
||||
ike_sa->get_other_id(ike_sa), ike_sa->get_other_host(ike_sa));
|
||||
|
||||
children = ike_sa->create_child_sa_iterator(ike_sa);
|
||||
while (children->iterate(children, (void**)&child_sa))
|
||||
{
|
||||
@@ -118,7 +119,7 @@ static void status(private_uci_control_t *this, char *name)
|
||||
child_sa->get_traffic_selectors(child_sa, FALSE));
|
||||
}
|
||||
children->destroy(children);
|
||||
fprintf(out, "\n");
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
sas->destroy(sas);
|
||||
}
|
||||
@@ -142,7 +143,7 @@ static void initiate(private_uci_control_t *this, char *name)
|
||||
peer_cfg_t *peer_cfg;
|
||||
child_cfg_t *child_cfg;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
|
||||
peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
|
||||
if (peer_cfg)
|
||||
{
|
||||
@@ -174,7 +175,7 @@ static void terminate(private_uci_control_t *this, char *name)
|
||||
enumerator_t *enumerator;
|
||||
ike_sa_t *ike_sa;
|
||||
u_int id;
|
||||
|
||||
|
||||
enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
|
||||
while (enumerator->enumerate(enumerator, &ike_sa))
|
||||
{
|
||||
@@ -240,7 +241,7 @@ static job_requeue_t receive(private_uci_control_t *this)
|
||||
char message[128];
|
||||
int oldstate, len;
|
||||
FILE *in;
|
||||
|
||||
|
||||
memset(message, 0, sizeof(message));
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
||||
in = fopen(FIFO_FILE, "r");
|
||||
@@ -281,9 +282,9 @@ static void destroy(private_uci_control_t *this)
|
||||
uci_control_t *uci_control_create()
|
||||
{
|
||||
private_uci_control_t *this = malloc_thing(private_uci_control_t);
|
||||
|
||||
|
||||
this->public.destroy = (void(*)(uci_control_t*))destroy;
|
||||
|
||||
|
||||
unlink(FIFO_FILE);
|
||||
if (mkfifo(FIFO_FILE, S_IRUSR|S_IWUSR) != 0)
|
||||
{
|
||||
|
||||
@@ -81,10 +81,6 @@ static bool shared_enumerator_enumerate(shared_enumerator_t *this,
|
||||
if (me)
|
||||
{
|
||||
local = identification_create_from_string(local_id);
|
||||
if (!local)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
*me = this->me ? this->me->matches(this->me, local)
|
||||
: ID_MATCH_ANY;
|
||||
local->destroy(local);
|
||||
@@ -96,10 +92,6 @@ static bool shared_enumerator_enumerate(shared_enumerator_t *this,
|
||||
if (other)
|
||||
{
|
||||
remote = identification_create_from_string(remote_id);
|
||||
if (!remote)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
*other = this->other ? this->other->matches(this->other, remote)
|
||||
: ID_MATCH_ANY;
|
||||
remote->destroy(remote);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <library.h>
|
||||
#include <credentials/auth_info.h>
|
||||
#include <config/auth_cfg.h>
|
||||
|
||||
|
||||
char buf[] = {0x01,0x02,0x03,0x04};
|
||||
@@ -75,14 +75,14 @@ chunk_t certchunk = chunk_from_buf(certbuf);
|
||||
/*******************************************************************************
|
||||
* auth info test
|
||||
******************************************************************************/
|
||||
bool test_auth_info()
|
||||
bool test_auth_cfg()
|
||||
{
|
||||
auth_info_t *auth = auth_info_create(), *auth2;
|
||||
auth_cfg_t *auth = auth_cfg_create(), *auth2;
|
||||
certificate_t *c1, *c2;
|
||||
enumerator_t *enumerator;
|
||||
int round = 0;
|
||||
void *value;
|
||||
auth_item_t type;
|
||||
auth_rule_t type;
|
||||
|
||||
c1 = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_BLOB_ASN1_DER, certchunk,
|
||||
@@ -92,8 +92,9 @@ bool test_auth_info()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
auth->add_item(auth, AUTHN_SUBJECT_CERT, c1);
|
||||
if (!auth->get_item(auth, AUTHN_SUBJECT_CERT, (void**)&c2))
|
||||
auth->add(auth, AUTH_RULE_SUBJECT_CERT, c1->get_ref(c1));
|
||||
c2 = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!c2)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -102,11 +103,11 @@ bool test_auth_info()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
enumerator = auth->create_item_enumerator(auth);
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
round++;
|
||||
if (round == 1 && type == AUTHN_SUBJECT_CERT && value == c1)
|
||||
if (round == 1 && type == AUTH_RULE_SUBJECT_CERT && value == c1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -114,20 +115,20 @@ bool test_auth_info()
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
auth2 = auth_info_create();
|
||||
auth2->add_item(auth2, AUTHN_CA_CERT, c1);
|
||||
auth2->merge(auth2, auth);
|
||||
auth2 = auth_cfg_create();
|
||||
auth2->add(auth2, AUTH_RULE_CA_CERT, c1->get_ref(c1));
|
||||
auth2->merge(auth2, auth, FALSE);
|
||||
|
||||
round = 0;
|
||||
enumerator = auth2->create_item_enumerator(auth2);
|
||||
enumerator = auth2->create_enumerator(auth2);
|
||||
while (enumerator->enumerate(enumerator, &type, &value))
|
||||
{
|
||||
round++;
|
||||
if (round == 1 && type == AUTHN_CA_CERT && value == c1)
|
||||
if (round == 1 && type == AUTH_RULE_CA_CERT && value == c1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (round == 2 && type == AUTHN_SUBJECT_CERT && value == c1)
|
||||
if (round == 2 && type == AUTH_RULE_SUBJECT_CERT && value == c1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ bool test_med_db()
|
||||
chunk_t keyid = chunk_from_buf(keyid_buf);
|
||||
identification_t *id, *found;
|
||||
enumerator_t *enumerator;
|
||||
auth_info_t *auth;
|
||||
public_key_t *public;
|
||||
auth_cfg_t *auth;
|
||||
bool good = FALSE;
|
||||
|
||||
id = identification_create_from_encoding(ID_KEY_ID, keyid);
|
||||
|
||||
@@ -25,14 +25,10 @@
|
||||
|
||||
static void* testing(void *thread)
|
||||
{
|
||||
int i;
|
||||
auth_info_t *auth;
|
||||
int i;
|
||||
host_t *addr[ALLOCS];
|
||||
identification_t *id[ALLOCS];
|
||||
|
||||
|
||||
auth = auth_info_create();
|
||||
|
||||
/* prepare identities */
|
||||
for (i = 0; i < ALLOCS; i++)
|
||||
{
|
||||
@@ -40,17 +36,13 @@ static void* testing(void *thread)
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d-%[email protected]", (int)thread, i);
|
||||
id[i] = identification_create_from_string(buf);
|
||||
if (!id[i])
|
||||
{
|
||||
return (void*)FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate addresses */
|
||||
for (i = 0; i < ALLOCS; i++)
|
||||
{
|
||||
addr[i] = charon->attributes->acquire_address(charon->attributes,
|
||||
"test", id[i], auth, NULL);
|
||||
"test", id[i], NULL);
|
||||
if (!addr[i])
|
||||
{
|
||||
return (void*)FALSE;
|
||||
@@ -69,7 +61,6 @@ static void* testing(void *thread)
|
||||
addr[i]->destroy(addr[i]);
|
||||
id[i]->destroy(id[i]);
|
||||
}
|
||||
auth->destroy(auth);
|
||||
return (void*)TRUE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user