summaryrefslogtreecommitdiff
path: root/src/charon/plugins/nm/nm_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/plugins/nm/nm_service.c')
-rw-r--r--src/charon/plugins/nm/nm_service.c97
1 files changed, 83 insertions, 14 deletions
diff --git a/src/charon/plugins/nm/nm_service.c b/src/charon/plugins/nm/nm_service.c
index 72744b784..bca4d9e09 100644
--- a/src/charon/plugins/nm/nm_service.c
+++ b/src/charon/plugins/nm/nm_service.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Martin Willi
+ * Copyright (C) 2008-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -11,8 +11,6 @@
* 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.
- *
- * $Id$
*/
#include <nm-setting-vpn.h>
@@ -23,6 +21,7 @@
#include <utils/host.h>
#include <utils/identification.h>
#include <config/peer_cfg.h>
+#include <credentials/certificates/x509.h>
#include <stdio.h>
@@ -34,10 +33,16 @@ G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_PLUGIN)
* Private data of NMStrongswanPlugin
*/
typedef struct {
+ /* implements bus listener interface */
listener_t listener;
+ /* IKE_SA we are listening on */
ike_sa_t *ike_sa;
+ /* backref to public plugin */
NMVPNPlugin *plugin;
+ /* credentials to use for authentication */
nm_creds_t *creds;
+ /* attribute handler for DNS/NBNS server information */
+ nm_handler_t *handler;
} NMStrongswanPluginPrivate;
#define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
@@ -45,6 +50,31 @@ typedef struct {
NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
/**
+ * convert enumerated handler chunks to a UINT_ARRAY GValue
+ */
+static GValue* handler_to_val(nm_handler_t *handler,
+ configuration_attribute_type_t type)
+{
+ GValue *val;
+ GArray *array;
+ enumerator_t *enumerator;
+ chunk_t chunk;
+
+ enumerator = handler->create_enumerator(handler, type);
+ array = g_array_new (FALSE, TRUE, sizeof (guint32));
+ while (enumerator->enumerate(enumerator, &chunk))
+ {
+ g_array_append_val (array, *(u_int32_t*)chunk.ptr);
+ }
+ enumerator->destroy(enumerator);
+ val = g_slice_new0 (GValue);
+ g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
+ g_value_set_boxed (val, array);
+
+ return val;
+}
+
+/**
* signal IPv4 config to NM, set connection as established
*/
static void signal_ipv4_config(NMVPNPlugin *plugin,
@@ -53,10 +83,12 @@ static void signal_ipv4_config(NMVPNPlugin *plugin,
GValue *val;
GHashTable *config;
host_t *me, *other;
+ nm_handler_t *handler;
config = g_hash_table_new(g_str_hash, g_str_equal);
me = ike_sa->get_my_host(ike_sa);
other = ike_sa->get_other_host(ike_sa);
+ handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
/* NM requires a tundev, but netkey does not use one. Passing an invalid
* iface makes NM complain, but it accepts it without fiddling on eth0. */
@@ -75,6 +107,14 @@ static void signal_ipv4_config(NMVPNPlugin *plugin,
g_value_set_uint(val, me->get_address(me).len * 8);
g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val);
+ val = handler_to_val(handler, INTERNAL_IP4_DNS);
+ g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
+
+ val = handler_to_val(handler, INTERNAL_IP4_NBNS);
+ g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val);
+
+ handler->reset(handler);
+
nm_vpn_plugin_set_ip4_config(plugin, config);
}
@@ -83,6 +123,10 @@ static void signal_ipv4_config(NMVPNPlugin *plugin,
*/
static void signal_failure(NMVPNPlugin *plugin)
{
+ nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
+
+ handler->reset(handler);
+
/* TODO: NM does not handle this failure!? */
nm_vpn_plugin_failure(plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
nm_vpn_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STOPPED);
@@ -151,9 +195,10 @@ 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;
+ x509_t *x509;
bool agent = FALSE;
/**
@@ -201,7 +246,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
creds = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->creds;
creds->clear(creds);
- /* gateway cert */
+ /* gateway/CA cert */
str = nm_setting_vpn_get_data_item(settings, "certificate");
if (str)
{
@@ -215,7 +260,21 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
"Loading gateway certificate failed.");
return FALSE;
}
- gateway = cert->get_subject(cert);
+ x509 = (x509_t*)cert;
+ if (x509->get_flags(x509) & X509_CA)
+ { /* If the user configured a CA certificate, we use the IP/DNS
+ * of the gateway as its identity. This identity will be used for
+ * certificate lookup and requires the configured IP/DNS to be
+ * included in the gateway certificate. */
+ gateway = identification_create_from_string((char*)address);
+ DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
+ }
+ else
+ { /* For a gateway certificate, we use the cert subject as identity. */
+ gateway = cert->get_subject(cert);
+ gateway = gateway->clone(gateway);
+ DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway);
+ }
if (auth_class == AUTH_CLASS_EAP)
{
@@ -223,8 +282,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((char*)str);
str = nm_setting_vpn_get_secret(settings, "password");
creds->set_username_password(creds, user, (char*)str);
}
@@ -240,12 +298,13 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
private_key_t *private = NULL;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, str, BUILD_END);
+ BUILD_FROM_FILE, str, BUILD_END);
if (!cert)
{
g_set_error(err, NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"Loading peer certificate failed.");
+ gateway->destroy(gateway);
return FALSE;
}
/* try agent */
@@ -304,6 +363,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
else
{
DESTROY_IF(cert);
+ gateway->destroy(gateway);
return FALSE;
}
}
@@ -313,6 +373,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
{
g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
"Configuration parameters missing.");
+ gateway->destroy(gateway);
return FALSE;
}
@@ -322,15 +383,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);
+ 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 */
@@ -358,7 +425,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
{
peer_cfg->destroy(peer_cfg);
}
- if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS)
+ if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
@@ -489,7 +556,8 @@ static void nm_strongswan_plugin_class_init(
/**
* Object constructor
*/
-NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds)
+NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
+ nm_handler_t *handler)
{
NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_object_new (
NM_TYPE_STRONGSWAN_PLUGIN,
@@ -498,6 +566,7 @@ NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds)
if (plugin)
{
NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->creds = creds;
+ NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler = handler;
}
return plugin;
}