123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942 |
- /*
- * Copyright (C) 2017 Lubomir Rintel
- *
- * Copyright (C) 2013-2019 Tobias Brunner
- * Copyright (C) 2008-2009 Martin Willi
- * 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 "nm_service.h"
- #include <daemon.h>
- #include <networking/host.h>
- #include <utils/identification.h>
- #include <config/peer_cfg.h>
- #include <credentials/certificates/x509.h>
- #include <stdio.h>
- G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_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 */
- NMVpnServicePlugin *plugin;
- /* credentials to use for authentication */
- nm_creds_t *creds;
- /* attribute handler for DNS/NBNS server information */
- nm_handler_t *handler;
- /* name of the connection */
- char *name;
- } NMStrongswanPluginPrivate;
- #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
- NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
- /**
- * Convert an address chunk to a GValue
- */
- static GVariant *addr_to_variant(chunk_t addr)
- {
- GVariantBuilder builder;
- int i;
- switch (addr.len)
- {
- case 4:
- return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
- case 16:
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
- for (i = 0; i < addr.len; i++)
- {
- g_variant_builder_add (&builder, "y", addr.ptr[i]);
- }
- return g_variant_builder_end (&builder);
- default:
- return NULL;
- }
- }
- /**
- * Convert a host to a GValue
- */
- static GVariant *host_to_variant(host_t *host)
- {
- return addr_to_variant(host->get_address(host));
- }
- /**
- * Convert enumerated handler chunks to a GValue
- */
- static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
- configuration_attribute_type_t type)
- {
- GVariantBuilder builder;
- enumerator_t *enumerator;
- chunk_t *chunk;
- g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
- enumerator = handler->create_enumerator(handler, type);
- while (enumerator->enumerate(enumerator, &chunk))
- {
- g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
- }
- enumerator->destroy(enumerator);
- return g_variant_builder_end (&builder);
- }
- /**
- * Signal IP config to NM, set connection as established
- */
- static void signal_ip_config(NMVpnServicePlugin *plugin,
- ike_sa_t *ike_sa, child_sa_t *child_sa)
- {
- NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- GVariantBuilder builder, ip4builder, ip6builder;
- GVariant *ip4config, *ip6config;
- enumerator_t *enumerator;
- host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
- nm_handler_t *handler;
- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
- handler = priv->handler;
- /* NM apparently requires to know the gateway */
- other = ike_sa->get_other_host(ike_sa);
- g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
- host_to_variant(other));
- /* pass the first virtual IPs we got or use the physical IP */
- enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
- while (enumerator->enumerate(enumerator, &me))
- {
- switch (me->get_family(me))
- {
- case AF_INET:
- if (!vip4)
- {
- vip4 = me;
- }
- break;
- case AF_INET6:
- if (!vip6)
- {
- vip6 = me;
- }
- break;
- }
- }
- enumerator->destroy(enumerator);
- if (!vip4 && !vip6)
- {
- me = ike_sa->get_my_host(ike_sa);
- switch (me->get_family(me))
- {
- case AF_INET:
- vip4 = me;
- break;
- case AF_INET6:
- vip6 = me;
- break;
- }
- }
- if (vip4)
- {
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
- host_to_variant(vip4));
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
- g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
- /* prevent NM from changing the default route. we set our own route in our
- * own routing table
- */
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
- g_variant_new_boolean (TRUE));
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
- handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
- handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
- }
- if (vip6)
- {
- g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
- host_to_variant(vip6));
- g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
- g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
- g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
- g_variant_new_boolean (TRUE));
- g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
- handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
- /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
- }
- ip4config = g_variant_builder_end (&ip4builder);
- if (g_variant_n_children (ip4config))
- {
- g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
- g_variant_new_boolean (TRUE));
- }
- else
- {
- g_variant_unref (ip4config);
- ip4config = NULL;
- }
- ip6config = g_variant_builder_end (&ip6builder);
- if (g_variant_n_children (ip6config))
- {
- g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
- g_variant_new_boolean (TRUE));
- }
- else
- {
- g_variant_unref (ip6config);
- ip6config = NULL;
- }
- handler->reset(handler);
- nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
- if (ip4config)
- {
- nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
- }
- if (ip6config)
- {
- nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
- }
- }
- /**
- * signal failure to NM, connecting failed
- */
- static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure)
- {
- nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
- handler->reset(handler);
- nm_vpn_service_plugin_failure(plugin, failure);
- }
- /**
- * Implementation of listener_t.ike_state_change
- */
- static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa,
- ike_sa_state_t state)
- {
- NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
- if (private->ike_sa == ike_sa && state == IKE_DESTROYING)
- {
- signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
- return FALSE;
- }
- return TRUE;
- }
- /**
- * Implementation of listener_t.child_state_change
- */
- static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa,
- child_sa_t *child_sa, child_sa_state_t state)
- {
- NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
- if (private->ike_sa == ike_sa && state == CHILD_DESTROYING)
- {
- signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
- return FALSE;
- }
- return TRUE;
- }
- /**
- * Implementation of listener_t.child_updown
- */
- static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
- child_sa_t *child_sa, bool up)
- {
- NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
- if (private->ike_sa == ike_sa)
- {
- if (up)
- { /* disable initiate-failure-detection hooks */
- private->listener.ike_state_change = NULL;
- private->listener.child_state_change = NULL;
- signal_ip_config(private->plugin, ike_sa, child_sa);
- }
- else
- {
- signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
- return FALSE;
- }
- }
- return TRUE;
- }
- /**
- * Implementation of listener_t.ike_rekey
- */
- static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
- {
- NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
- if (private->ike_sa == old)
- { /* follow a rekeyed IKE_SA */
- private->ike_sa = new;
- }
- return TRUE;
- }
- /**
- * Find a certificate for which we have a private key on a smartcard
- */
- static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
- char *pin)
- {
- enumerator_t *enumerator, *sans;
- identification_t *id = NULL;
- certificate_t *cert;
- x509_t *x509;
- private_key_t *key;
- chunk_t keyid;
- enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
- CERT_X509, KEY_ANY, NULL, FALSE);
- while (enumerator->enumerate(enumerator, &cert))
- {
- x509 = (x509_t*)cert;
- /* there might be a lot of certificates, filter them by usage */
- if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
- !(x509->get_flags(x509) & X509_CA))
- {
- keyid = x509->get_subjectKeyIdentifier(x509);
- if (keyid.ptr)
- {
- /* try to find a private key by the certificate keyid */
- priv->creds->set_pin(priv->creds, keyid, pin);
- key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
- if (key)
- {
- /* prefer a more convenient subjectAltName */
- sans = x509->create_subjectAltName_enumerator(x509);
- if (!sans->enumerate(sans, &id))
- {
- id = cert->get_subject(cert);
- }
- id = id->clone(id);
- sans->destroy(sans);
- DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
- priv->creds->set_cert_and_key(priv->creds,
- cert->get_ref(cert), key);
- break;
- }
- }
- }
- }
- enumerator->destroy(enumerator);
- return id;
- }
- /**
- * Connect function called from NM via DBUS
- */
- static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
- GError **err)
- {
- NMStrongswanPluginPrivate *priv;
- NMSettingConnection *conn;
- NMSettingVpn *vpn;
- enumerator_t *enumerator;
- identification_t *user = NULL, *gateway = NULL;
- const char *str;
- bool virtual, proposal;
- proposal_t *prop;
- ike_cfg_t *ike_cfg;
- peer_cfg_t *peer_cfg;
- child_cfg_t *child_cfg;
- traffic_selector_t *ts;
- ike_sa_t *ike_sa;
- auth_cfg_t *auth;
- auth_class_t auth_class = AUTH_CLASS_EAP;
- certificate_t *cert = NULL;
- x509_t *x509;
- bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE;
- ike_cfg_create_t ike = {
- .version = IKEV2,
- .local = "%any",
- .local_port = charon->socket->get_port(charon->socket, FALSE),
- .remote_port = IKEV2_UDP_PORT,
- .fragmentation = FRAGMENTATION_YES,
- };
- peer_cfg_create_t peer = {
- .cert_policy = CERT_SEND_IF_ASKED,
- .unique = UNIQUE_REPLACE,
- .keyingtries = 1,
- .rekey_time = 36000, /* 10h */
- .jitter_time = 600, /* 10min */
- .over_time = 600, /* 10min */
- };
- child_cfg_create_t child = {
- .lifetime = {
- .time = {
- .life = 10800 /* 3h */,
- .rekey = 10200 /* 2h50min */,
- .jitter = 300 /* 5min */
- },
- },
- .mode = MODE_TUNNEL,
- };
- /**
- * Read parameters
- */
- priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
- NM_TYPE_SETTING_CONNECTION));
- vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
- NM_TYPE_SETTING_VPN));
- if (priv->name)
- {
- free(priv->name);
- }
- priv->name = strdup(nm_setting_connection_get_id(conn));
- DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
- priv->name);
- DBG4(DBG_CFG, "%s",
- nm_setting_to_string(NM_SETTING(vpn)));
- ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address");
- if (!ike.remote || !*ike.remote)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "Gateway address missing.");
- return FALSE;
- }
- str = nm_setting_vpn_get_data_item(vpn, "virtual");
- virtual = streq(str, "yes");
- str = nm_setting_vpn_get_data_item(vpn, "encap");
- ike.force_encap = streq(str, "yes");
- str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
- child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
- str = nm_setting_vpn_get_data_item(vpn, "method");
- if (streq(str, "psk"))
- {
- auth_class = AUTH_CLASS_PSK;
- }
- else if (streq(str, "agent"))
- {
- auth_class = AUTH_CLASS_PUBKEY;
- agent = TRUE;
- }
- else if (streq(str, "key"))
- {
- auth_class = AUTH_CLASS_PUBKEY;
- }
- else if (streq(str, "smartcard"))
- {
- auth_class = AUTH_CLASS_PUBKEY;
- smartcard = TRUE;
- }
- /**
- * Register credentials
- */
- priv->creds->clear(priv->creds);
- /* gateway/CA cert */
- str = nm_setting_vpn_get_data_item(vpn, "certificate");
- if (str)
- {
- cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
- BUILD_FROM_FILE, str, BUILD_END);
- if (!cert)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "Loading gateway certificate failed.");
- return FALSE;
- }
- priv->creds->add_certificate(priv->creds, cert);
- x509 = (x509_t*)cert;
- if (!(x509->get_flags(x509) & X509_CA))
- { /* 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);
- }
- }
- else
- {
- /* no certificate defined, fall back to system-wide CA certificates */
- priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
- lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
- }
- if (!gateway)
- {
- /* 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(ike.remote);
- DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
- loose_gateway_id = TRUE;
- }
- if (auth_class == AUTH_CLASS_EAP ||
- auth_class == AUTH_CLASS_PSK)
- {
- /* username/password or PSK authentication ... */
- str = nm_setting_vpn_get_data_item(vpn, "user");
- if (str)
- {
- user = identification_create_from_string((char*)str);
- str = nm_setting_vpn_get_secret(vpn, "password");
- if (auth_class == AUTH_CLASS_PSK &&
- strlen(str) < 20)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "pre-shared key is too short.");
- gateway->destroy(gateway);
- user->destroy(user);
- return FALSE;
- }
- priv->creds->set_username_password(priv->creds, user, (char*)str);
- }
- }
- if (auth_class == AUTH_CLASS_PUBKEY)
- {
- if (smartcard)
- {
- char *pin;
- pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
- if (pin)
- {
- user = find_smartcard_key(priv, pin);
- }
- if (!user)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "no usable smartcard certificate found.");
- gateway->destroy(gateway);
- return FALSE;
- }
- }
- /* ... or certificate/private key authenitcation */
- else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
- {
- public_key_t *public;
- private_key_t *private = NULL;
- cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
- 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 */
- str = nm_setting_vpn_get_secret(vpn, "agent");
- if (agent && str)
- {
- public = cert->get_public_key(cert);
- if (public)
- {
- private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- public->get_type(public),
- BUILD_AGENT_SOCKET, str,
- BUILD_PUBLIC_KEY, public,
- BUILD_END);
- public->destroy(public);
- }
- if (!private)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "Connecting to SSH agent failed.");
- }
- }
- /* ... or key file */
- str = nm_setting_vpn_get_data_item(vpn, "userkey");
- if (!agent && str)
- {
- char *secret;
- secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
- if (secret)
- {
- priv->creds->set_key_password(priv->creds, secret);
- }
- private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
- if (!private)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "Loading private key failed.");
- }
- }
- if (private)
- {
- user = cert->get_subject(cert);
- user = user->clone(user);
- priv->creds->set_cert_and_key(priv->creds, cert, private);
- }
- else
- {
- DESTROY_IF(cert);
- gateway->destroy(gateway);
- return FALSE;
- }
- }
- }
- if (!user)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "Configuration parameters missing.");
- gateway->destroy(gateway);
- return FALSE;
- }
- /**
- * Set up configurations
- */
- ike_cfg = ike_cfg_create(&ike);
- str = nm_setting_vpn_get_data_item(vpn, "proposal");
- proposal = streq(str, "yes");
- str = nm_setting_vpn_get_data_item(vpn, "ike");
- if (proposal && str && strlen(str))
- {
- enumerator = enumerator_create_token(str, ";", "");
- while (enumerator->enumerate(enumerator, &str))
- {
- prop = proposal_create_from_string(PROTO_IKE, str);
- if (!prop)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
- "Invalid IKE proposal.");
- enumerator->destroy(enumerator);
- ike_cfg->destroy(ike_cfg);
- gateway->destroy(gateway);
- user->destroy(user);
- return FALSE;
- }
- ike_cfg->add_proposal(ike_cfg, prop);
- }
- enumerator->destroy(enumerator);
- }
- else
- {
- ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
- ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
- }
- peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
- if (virtual)
- {
- peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
- peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
- }
- 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();
- if (auth_class == AUTH_CLASS_PSK)
- {
- auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
- }
- else
- {
- auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
- }
- auth->add(auth, AUTH_RULE_IDENTITY, gateway);
- auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
- peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
- child_cfg = child_cfg_create(priv->name, &child);
- str = nm_setting_vpn_get_data_item(vpn, "esp");
- if (proposal && str && strlen(str))
- {
- enumerator = enumerator_create_token(str, ";", "");
- while (enumerator->enumerate(enumerator, &str))
- {
- prop = proposal_create_from_string(PROTO_ESP, str);
- if (!prop)
- {
- g_set_error(err, NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
- "Invalid ESP proposal.");
- enumerator->destroy(enumerator);
- child_cfg->destroy(child_cfg);
- peer_cfg->destroy(peer_cfg);
- return FALSE;
- }
- child_cfg->add_proposal(child_cfg, prop);
- }
- enumerator->destroy(enumerator);
- }
- else
- {
- child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
- child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
- }
- ts = traffic_selector_create_dynamic(0, 0, 65535);
- child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
- ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
- child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
- ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
- child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
- peer_cfg->add_child_cfg(peer_cfg, child_cfg);
- /**
- * Prepare IKE_SA
- */
- ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
- peer_cfg);
- if (!ike_sa)
- {
- peer_cfg->destroy(peer_cfg);
- g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
- "IKE version not supported.");
- return FALSE;
- }
- if (!ike_sa->get_peer_cfg(ike_sa))
- {
- ike_sa->set_peer_cfg(ike_sa, peer_cfg);
- }
- peer_cfg->destroy(peer_cfg);
- /**
- * Register listener, enable initiate-failure-detection hooks
- */
- priv->ike_sa = ike_sa;
- priv->listener.ike_state_change = ike_state_change;
- priv->listener.child_state_change = child_state_change;
- charon->bus->add_listener(charon->bus, &priv->listener);
- /**
- * Initiate
- */
- child_cfg->get_ref(child_cfg);
- if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
- {
- charon->bus->remove_listener(charon->bus, &priv->listener);
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
- "Initiating failed.");
- return FALSE;
- }
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return TRUE;
- }
- /**
- * NeedSecrets called from NM via DBUS
- */
- static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
- const char **setting_name, GError **error)
- {
- NMSettingVpn *settings;
- const char *method, *path;
- settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
- NM_TYPE_SETTING_VPN));
- method = nm_setting_vpn_get_data_item(settings, "method");
- if (method)
- {
- if (streq(method, "eap") || streq(method, "psk"))
- {
- if (nm_setting_vpn_get_secret(settings, "password"))
- {
- return FALSE;
- }
- }
- else if (streq(method, "agent"))
- {
- if (nm_setting_vpn_get_secret(settings, "agent"))
- {
- return FALSE;
- }
- }
- else if (streq(method, "key"))
- {
- path = nm_setting_vpn_get_data_item(settings, "userkey");
- if (path)
- {
- private_key_t *key;
- /* try to load/decrypt the private key */
- key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
- KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
- if (key)
- {
- key->destroy(key);
- return FALSE;
- }
- else if (nm_setting_vpn_get_secret(settings, "password"))
- {
- return FALSE;
- }
- }
- }
- else if (streq(method, "smartcard"))
- {
- if (nm_setting_vpn_get_secret(settings, "password"))
- {
- return FALSE;
- }
- }
- }
- *setting_name = NM_SETTING_VPN_SETTING_NAME;
- return TRUE;
- }
- /**
- * The actual disconnection
- */
- static gboolean do_disconnect(gpointer plugin)
- {
- NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- enumerator_t *enumerator;
- ike_sa_t *ike_sa;
- u_int id;
- /* our ike_sa pointer might be invalid, lookup sa */
- enumerator = charon->controller->create_ike_sa_enumerator(
- charon->controller, TRUE);
- while (enumerator->enumerate(enumerator, &ike_sa))
- {
- if (priv->ike_sa == ike_sa)
- {
- id = ike_sa->get_unique_id(ike_sa);
- enumerator->destroy(enumerator);
- charon->controller->terminate_ike(charon->controller, id, FALSE,
- controller_cb_empty, NULL, 0);
- return FALSE;
- }
- }
- enumerator->destroy(enumerator);
- g_debug("Connection not found.");
- return FALSE;
- }
- /**
- * Disconnect called from NM via DBUS
- */
- static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
- {
- /* enqueue the actual disconnection, because we may be called in
- * response to a listener_t callback and the SA enumeration would
- * possibly deadlock. */
- g_idle_add(do_disconnect, plugin);
- return TRUE;
- }
- /**
- * Initializer
- */
- static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
- {
- NMStrongswanPluginPrivate *priv;
- priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
- memset(&priv->listener, 0, sizeof(listener_t));
- priv->listener.child_updown = child_updown;
- priv->listener.ike_rekey = ike_rekey;
- priv->name = NULL;
- }
- /**
- * Class constructor
- */
- static void nm_strongswan_plugin_class_init(
- NMStrongswanPluginClass *strongswan_class)
- {
- NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
- g_type_class_add_private(G_OBJECT_CLASS(strongswan_class),
- sizeof(NMStrongswanPluginPrivate));
- parent_class->connect = connect_;
- parent_class->need_secrets = need_secrets;
- parent_class->disconnect = disconnect;
- }
- /**
- * Object constructor
- */
- NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
- nm_handler_t *handler)
- {
- GError *error = NULL;
- NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
- NM_TYPE_STRONGSWAN_PLUGIN,
- NULL,
- &error,
- NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
- NULL);
- if (plugin)
- {
- NMStrongswanPluginPrivate *priv;
- /* the rest of the initialization happened in _init above */
- priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- priv->creds = creds;
- priv->handler = handler;
- }
- else
- {
- g_warning ("Failed to initialize a plugin instance: %s", error->message);
- g_error_free (error);
- }
- return plugin;
- }
|