]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/charon-nm/nm/nm_service.c
ike: Treat action_t as flags so 'start' and 'trap' can be combined
[thirdparty/strongswan.git] / src / charon-nm / nm / nm_service.c
CommitLineData
6dbce9c8 1/*
9a71b721
LR
2 * Copyright (C) 2017 Lubomir Rintel
3 *
bc3eda99 4 * Copyright (C) 2013-2020 Tobias Brunner
3ab0e8a0 5 * Copyright (C) 2008-2009 Martin Willi
1b671669 6 * HSR Hochschule fuer Technik Rapperswil
6dbce9c8
MW
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
6dbce9c8
MW
17 */
18
6dbce9c8
MW
19#include "nm_service.h"
20
21#include <daemon.h>
2e7cc07e 22#include <networking/host.h>
6dbce9c8
MW
23#include <utils/identification.h>
24#include <config/peer_cfg.h>
0ed6b7a7 25#include <credentials/certificates/x509.h>
aa3d5bf7 26#include <networking/tun_device.h>
6dbce9c8
MW
27
28#include <stdio.h>
29
6dbce9c8
MW
30/**
31 * Private data of NMStrongswanPlugin
32 */
33typedef struct {
3ab0e8a0 34 /* implements bus listener interface */
a985db3f 35 listener_t listener;
3ab0e8a0 36 /* IKE_SA we are listening on */
6dbce9c8 37 ike_sa_t *ike_sa;
3ab0e8a0 38 /* backref to public plugin */
9a71b721 39 NMVpnServicePlugin *plugin;
3ab0e8a0 40 /* credentials to use for authentication */
ec249871 41 nm_creds_t *creds;
3ab0e8a0
MW
42 /* attribute handler for DNS/NBNS server information */
43 nm_handler_t *handler;
aa3d5bf7
TB
44 /* dummy TUN device */
45 tun_device_t *tun;
69b80589
MW
46 /* name of the connection */
47 char *name;
6dbce9c8
MW
48} NMStrongswanPluginPrivate;
49
18bee930
TB
50G_DEFINE_TYPE_WITH_PRIVATE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
51
6dbce9c8 52#define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
18bee930
TB
53 ((NMStrongswanPluginPrivate*) \
54 nm_strongswan_plugin_get_instance_private (o))
6dbce9c8 55
3ab0e8a0 56/**
05b7f1cb 57 * Convert an address chunk to a GValue
3ab0e8a0 58 */
05b7f1cb
TB
59static GVariant *addr_to_variant(chunk_t addr)
60{
61 GVariantBuilder builder;
62 int i;
63
64 switch (addr.len)
65 {
66 case 4:
67 return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
68 case 16:
69 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
70 for (i = 0; i < addr.len; i++)
71 {
72 g_variant_builder_add (&builder, "y", addr.ptr[i]);
73
74 }
75 return g_variant_builder_end (&builder);
76 default:
77 return NULL;
78 }
79}
80
81/**
82 * Convert a host to a GValue
83 */
84static GVariant *host_to_variant(host_t *host)
85{
86 return addr_to_variant(host->get_address(host));
87}
88
89/**
90 * Convert enumerated handler chunks to a GValue
91 */
92static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
3ab0e8a0
MW
93 configuration_attribute_type_t type)
94{
9a71b721 95 GVariantBuilder builder;
3ab0e8a0 96 enumerator_t *enumerator;
0af3a4f1 97 chunk_t *chunk;
7daf5226 98
05b7f1cb 99 g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
9a71b721 100
3ab0e8a0 101 enumerator = handler->create_enumerator(handler, type);
3ab0e8a0
MW
102 while (enumerator->enumerate(enumerator, &chunk))
103 {
05b7f1cb 104 g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
3ab0e8a0
MW
105 }
106 enumerator->destroy(enumerator);
7daf5226 107
9a71b721 108 return g_variant_builder_end (&builder);
3ab0e8a0
MW
109}
110
6dbce9c8 111/**
05b7f1cb 112 * Signal IP config to NM, set connection as established
6dbce9c8 113 */
05b7f1cb
TB
114static void signal_ip_config(NMVpnServicePlugin *plugin,
115 ike_sa_t *ike_sa, child_sa_t *child_sa)
6dbce9c8 116{
18bee930
TB
117 NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
118 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
05b7f1cb
TB
119 GVariantBuilder builder, ip4builder, ip6builder;
120 GVariant *ip4config, *ip6config;
9cf09eca 121 enumerator_t *enumerator;
05b7f1cb 122 host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
3ab0e8a0 123 nm_handler_t *handler;
7daf5226 124
9a71b721 125 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
05b7f1cb
TB
126 g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
127 g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
9a71b721 128
c15eea73 129 handler = priv->handler;
7daf5226 130
f201d86d 131 /* NM apparently requires to know the gateway */
f201d86d 132 other = ike_sa->get_other_host(ike_sa);
05b7f1cb 133 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
aa3d5bf7
TB
134 host_to_variant(other));
135
136 /* systemd-resolved requires a device to properly install DNS servers, but
137 * Netkey does not use one. Passing the physical interface is not ideal,
138 * as NM fiddles around with it and systemd-resolved likes a separate
139 * device. So we pass a dummy TUN device along for NM etc. to play with...
140 */
141 if (priv->tun)
142 {
143 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV,
144 g_variant_new_string (priv->tun->get_name(priv->tun)));
145 }
f201d86d 146
05b7f1cb 147 /* pass the first virtual IPs we got or use the physical IP */
9cf09eca 148 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
05b7f1cb 149 while (enumerator->enumerate(enumerator, &me))
9cf09eca 150 {
05b7f1cb
TB
151 switch (me->get_family(me))
152 {
153 case AF_INET:
154 if (!vip4)
155 {
156 vip4 = me;
157 }
158 break;
159 case AF_INET6:
160 if (!vip6)
161 {
162 vip6 = me;
163 }
164 break;
165 }
9cf09eca
TB
166 }
167 enumerator->destroy(enumerator);
05b7f1cb
TB
168 if (!vip4 && !vip6)
169 {
170 me = ike_sa->get_my_host(ike_sa);
171 switch (me->get_family(me))
172 {
173 case AF_INET:
174 vip4 = me;
175 break;
176 case AF_INET6:
177 vip6 = me;
178 break;
179 }
180 }
7daf5226 181
05b7f1cb
TB
182 if (vip4)
183 {
184 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
185 host_to_variant(vip4));
186 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
187 g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
188
189 /* prevent NM from changing the default route. we set our own route in our
190 * own routing table
191 */
192 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
193 g_variant_new_boolean (TRUE));
194
195 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
196 handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
197
198 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
199 handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
200 }
3651c8dc 201
05b7f1cb
TB
202 if (vip6)
203 {
204 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
205 host_to_variant(vip6));
206 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
207 g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
208 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
209 g_variant_new_boolean (TRUE));
210 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
211 handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
212 /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
213 }
7daf5226 214
05b7f1cb
TB
215 ip4config = g_variant_builder_end (&ip4builder);
216 if (g_variant_n_children (ip4config))
217 {
218 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
219 g_variant_new_boolean (TRUE));
220 }
221 else
222 {
223 g_variant_unref (ip4config);
224 ip4config = NULL;
225 }
9a71b721 226
05b7f1cb
TB
227 ip6config = g_variant_builder_end (&ip6builder);
228 if (g_variant_n_children (ip6config))
229 {
230 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
231 g_variant_new_boolean (TRUE));
232 }
233 else
234 {
235 g_variant_unref (ip6config);
236 ip6config = NULL;
237 }
7daf5226 238
3ab0e8a0 239 handler->reset(handler);
7daf5226 240
05b7f1cb
TB
241 nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
242 if (ip4config)
243 {
244 nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
245 }
246 if (ip6config)
247 {
248 nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
249 }
6dbce9c8
MW
250}
251
252/**
a985db3f 253 * signal failure to NM, connecting failed
6dbce9c8 254 */
9a71b721 255static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure)
a985db3f 256{
18bee930
TB
257 NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
258 nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub)->handler;
7daf5226 259
3ab0e8a0 260 handler->reset(handler);
7daf5226 261
9a71b721 262 nm_vpn_service_plugin_failure(plugin, failure);
a985db3f
MW
263}
264
3d2f5ae0
TB
265METHOD(listener_t, ike_state_change, bool,
266 NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, ike_sa_state_t state)
6dbce9c8 267{
3d2f5ae0 268 if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
6dbce9c8 269 {
3d2f5ae0 270 signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
a985db3f
MW
271 }
272 return TRUE;
273}
274
3d2f5ae0
TB
275METHOD(listener_t, child_state_change, bool,
276 NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
277 child_sa_state_t state)
a985db3f 278{
3d2f5ae0 279 if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
bad99d5a 280 {
3d2f5ae0 281 signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
bad99d5a
MW
282 }
283 return TRUE;
284}
a985db3f 285
3d2f5ae0
TB
286METHOD(listener_t, ike_rekey, bool,
287 NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
bad99d5a 288{
3d2f5ae0
TB
289 if (this->ike_sa == old)
290 { /* follow a rekeyed IKE_SA */
291 this->ike_sa = new;
292 }
293 return TRUE;
294}
295
296METHOD(listener_t, ike_reestablish_pre, bool,
297 NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
298{
299 if (this->ike_sa == old)
300 { /* ignore child state changes during redirects etc. (task migration) */
301 this->listener.child_state_change = NULL;
302 }
303 return TRUE;
304}
7daf5226 305
3d2f5ae0
TB
306METHOD(listener_t, ike_reestablish_post, bool,
307 NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new,
308 bool initiated)
309{
310 if (this->ike_sa == old && initiated)
311 { /* if we get redirected during IKE_AUTH we just migrate to the new SA */
312 this->ike_sa = new;
313 /* re-register hooks to detect initiation failures */
314 this->listener.ike_state_change = _ike_state_change;
315 this->listener.child_state_change = _child_state_change;
316 }
317 return TRUE;
318}
319
320METHOD(listener_t, child_updown, bool,
321 NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
322 bool up)
323{
10a91368 324 if (this->ike_sa == ike_sa && up)
a985db3f 325 {
10a91368
TB
326 /* disable initiate-failure-detection hooks */
327 this->listener.ike_state_change = NULL;
328 this->listener.child_state_change = NULL;
329 signal_ip_config(this->plugin, ike_sa, child_sa);
6dbce9c8
MW
330 }
331 return TRUE;
332}
333
8bec0f51
MW
334/**
335 * Find a certificate for which we have a private key on a smartcard
336 */
337static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
338 char *pin)
339{
340 enumerator_t *enumerator, *sans;
341 identification_t *id = NULL;
342 certificate_t *cert;
343 x509_t *x509;
344 private_key_t *key;
345 chunk_t keyid;
346
347 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
348 CERT_X509, KEY_ANY, NULL, FALSE);
349 while (enumerator->enumerate(enumerator, &cert))
350 {
351 x509 = (x509_t*)cert;
352
353 /* there might be a lot of certificates, filter them by usage */
354 if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
355 !(x509->get_flags(x509) & X509_CA))
356 {
357 keyid = x509->get_subjectKeyIdentifier(x509);
358 if (keyid.ptr)
359 {
360 /* try to find a private key by the certificate keyid */
361 priv->creds->set_pin(priv->creds, keyid, pin);
362 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
363 KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
364 if (key)
365 {
366 /* prefer a more convenient subjectAltName */
367 sans = x509->create_subjectAltName_enumerator(x509);
368 if (!sans->enumerate(sans, &id))
369 {
370 id = cert->get_subject(cert);
371 }
372 id = id->clone(id);
373 sans->destroy(sans);
374
375 DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
376 priv->creds->set_cert_and_key(priv->creds,
377 cert->get_ref(cert), key);
378 break;
379 }
380 }
381 }
382 }
383 enumerator->destroy(enumerator);
384 return id;
385}
386
bc3eda99
TB
387/**
388 * Add a client auth config for certificate authentication
389 */
390static bool add_auth_cfg_cert(NMStrongswanPluginPrivate *priv,
391 NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
392 GError **err)
393{
ff8f6b15 394 identification_t *id = NULL;
bc3eda99
TB
395 certificate_t *cert = NULL;
396 auth_cfg_t *auth;
397 const char *str, *method, *cert_source;
398
399 method = nm_setting_vpn_get_data_item(vpn, "method");
400 cert_source = nm_setting_vpn_get_data_item(vpn, "cert-source") ?: method;
401
402 if (streq(cert_source, "smartcard"))
403 {
404 char *pin;
405
406 pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
407 if (pin)
408 {
ff8f6b15 409 id = find_smartcard_key(priv, pin);
bc3eda99 410 }
ff8f6b15 411 if (!id)
bc3eda99
TB
412 {
413 g_set_error(err, NM_VPN_PLUGIN_ERROR,
414 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
ff8f6b15 415 "No usable smartcard certificate found.");
bc3eda99
TB
416 return FALSE;
417 }
418 }
419 /* ... or certificate/private key authentication */
420 else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
421 {
422 public_key_t *public;
423 private_key_t *private = NULL;
424
425 bool agent = streq(cert_source, "agent");
426
427 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
428 BUILD_FROM_FILE, str, BUILD_END);
429 if (!cert)
430 {
431 g_set_error(err, NM_VPN_PLUGIN_ERROR,
432 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
433 "Loading peer certificate failed.");
434 return FALSE;
435 }
436 /* try agent */
437 str = nm_setting_vpn_get_secret(vpn, "agent");
438 if (agent && str)
439 {
440 public = cert->get_public_key(cert);
441 if (public)
442 {
443 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
444 public->get_type(public),
445 BUILD_AGENT_SOCKET, str,
446 BUILD_PUBLIC_KEY, public,
447 BUILD_END);
448 public->destroy(public);
449 }
450 if (!private)
451 {
452 g_set_error(err, NM_VPN_PLUGIN_ERROR,
453 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
454 "Connecting to SSH agent failed.");
455 }
456 }
457 /* ... or key file */
458 str = nm_setting_vpn_get_data_item(vpn, "userkey");
459 if (!agent && str)
460 {
461 char *secret;
462
463 secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
464 if (secret)
465 {
466 priv->creds->set_key_password(priv->creds, secret);
467 }
468 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
469 KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
470 if (!private)
471 {
472 g_set_error(err, NM_VPN_PLUGIN_ERROR,
473 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
474 "Loading private key failed.");
475 }
476 }
477 if (private)
478 {
ff8f6b15
TB
479 id = cert->get_subject(cert);
480 id = id->clone(id);
bc3eda99
TB
481 priv->creds->set_cert_and_key(priv->creds, cert, private);
482 }
483 else
484 {
485 DESTROY_IF(cert);
486 return FALSE;
487 }
488 }
ff8f6b15
TB
489 else
490 {
491 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
492 "Certificate is missing.");
493 return FALSE;
494 }
bc3eda99
TB
495
496 auth = auth_cfg_create();
497 if (streq(method, "eap-tls"))
498 {
499 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
500 auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_TLS);
501 auth->add(auth, AUTH_RULE_AAA_IDENTITY,
502 identification_create_from_string("%any"));
503 }
504 else
505 {
506 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
507 }
508 if (cert)
509 {
510 auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
511 }
ff8f6b15
TB
512 str = nm_setting_vpn_get_data_item(vpn, "local-identity");
513 if (str)
514 {
515 identification_t *local_id;
516
517 local_id = identification_create_from_string((char*)str);
518 if (local_id)
519 {
520 id->destroy(id);
521 id = local_id;
522 }
523 }
524 auth->add(auth, AUTH_RULE_IDENTITY, id);
bc3eda99
TB
525 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
526 return TRUE;
527}
528
529/**
530 * Add a client auth config for username/password authentication
531 */
532static bool add_auth_cfg_pw(NMStrongswanPluginPrivate *priv,
533 NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
534 GError **err)
535{
ff8f6b15 536 identification_t *user = NULL, *id = NULL;
bc3eda99
TB
537 auth_cfg_t *auth;
538 const char *str, *method;
539
540 method = nm_setting_vpn_get_data_item(vpn, "method");
541
542 str = nm_setting_vpn_get_data_item(vpn, "user");
543 if (str)
544 {
545 user = identification_create_from_string((char*)str);
ff8f6b15
TB
546 }
547 else
548 {
549 user = identification_create_from_string("%any");
550 }
551 str = nm_setting_vpn_get_data_item(vpn, "local-identity");
552 if (str)
553 {
554 id = identification_create_from_string((char*)str);
555 }
556 else
557 {
558 id = user->clone(user);
559 }
560 str = nm_setting_vpn_get_secret(vpn, "password");
561 if (streq(method, "psk"))
562 {
563 if (strlen(str) < 20)
bc3eda99
TB
564 {
565 g_set_error(err, NM_VPN_PLUGIN_ERROR,
566 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
567 "Pre-shared key is too short.");
568 user->destroy(user);
ff8f6b15 569 id->destroy(id);
bc3eda99
TB
570 return FALSE;
571 }
ff8f6b15 572 priv->creds->set_username_password(priv->creds, id, (char*)str);
bc3eda99
TB
573 }
574 else
575 {
ff8f6b15 576 priv->creds->set_username_password(priv->creds, user, (char*)str);
bc3eda99
TB
577 }
578
579 auth = auth_cfg_create();
580 auth->add(auth, AUTH_RULE_AUTH_CLASS,
581 streq(method, "psk") ? AUTH_CLASS_PSK : AUTH_CLASS_EAP);
582 /* in case EAP-PEAP or EAP-TTLS is used we currently accept any identity */
583 auth->add(auth, AUTH_RULE_AAA_IDENTITY,
584 identification_create_from_string("%any"));
ff8f6b15
TB
585 auth->add(auth, AUTH_RULE_EAP_IDENTITY, user);
586 auth->add(auth, AUTH_RULE_IDENTITY, id);
bc3eda99
TB
587 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
588 return TRUE;
589}
590
6dbce9c8
MW
591/**
592 * Connect function called from NM via DBUS
593 */
9a71b721 594static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
6dbce9c8
MW
595 GError **err)
596{
18bee930 597 NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
69b80589
MW
598 NMStrongswanPluginPrivate *priv;
599 NMSettingConnection *conn;
9a71b721 600 NMSettingVpn *vpn;
4ac68f02 601 enumerator_t *enumerator;
bc3eda99
TB
602 identification_t *gateway = NULL;
603 const char *str, *method;
9486a2e5 604 bool virtual, proposal;
4ac68f02 605 proposal_t *prop;
6dbce9c8
MW
606 ike_cfg_t *ike_cfg;
607 peer_cfg_t *peer_cfg;
608 child_cfg_t *child_cfg;
609 traffic_selector_t *ts;
610 ike_sa_t *ike_sa;
a44bb934 611 auth_cfg_t *auth;
a88aae3d 612 certificate_t *cert = NULL;
0ed6b7a7 613 x509_t *x509;
bc3eda99 614 bool loose_gateway_id = FALSE;
9486a2e5
TB
615 ike_cfg_create_t ike = {
616 .version = IKEV2,
617 .local = "%any",
618 .local_port = charon->socket->get_port(charon->socket, FALSE),
619 .remote_port = IKEV2_UDP_PORT,
620 .fragmentation = FRAGMENTATION_YES,
621 };
2ba5dadb
TB
622 peer_cfg_create_t peer = {
623 .cert_policy = CERT_SEND_IF_ASKED,
624 .unique = UNIQUE_REPLACE,
2ba5dadb
TB
625 .rekey_time = 36000, /* 10h */
626 .jitter_time = 600, /* 10min */
627 .over_time = 600, /* 10min */
628 };
8a00a845
TB
629 child_cfg_create_t child = {
630 .lifetime = {
631 .time = {
632 .life = 10800 /* 3h */,
633 .rekey = 10200 /* 2h50min */,
634 .jitter = 300 /* 5min */
635 },
636 },
637 .mode = MODE_TUNNEL,
4f4d4021
TB
638 .dpd_action = ACTION_START,
639 .close_action = ACTION_START,
e75f4237 640 };
7daf5226 641
6dbce9c8
MW
642 /**
643 * Read parameters
644 */
18bee930 645 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
69b80589
MW
646 conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
647 NM_TYPE_SETTING_CONNECTION));
648 vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
649 NM_TYPE_SETTING_VPN));
650 if (priv->name)
651 {
652 free(priv->name);
653 }
654 priv->name = strdup(nm_setting_connection_get_id(conn));
655 DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
656 priv->name);
657 DBG4(DBG_CFG, "%s",
658 nm_setting_to_string(NM_SETTING(vpn)));
aa3d5bf7
TB
659 if (!priv->tun)
660 {
661 DBG1(DBG_CFG, "failed to create dummy TUN device, might affect DNS "
662 "server installation negatively");
663 }
9486a2e5
TB
664 ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address");
665 if (!ike.remote || !*ike.remote)
6dbce9c8
MW
666 {
667 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
323f9f99 668 "Gateway address missing.");
6dbce9c8
MW
669 return FALSE;
670 }
60777574
TB
671 str = nm_setting_vpn_get_data_item(vpn, "server-port");
672 if (str && strlen(str))
673 {
674 ike.remote_port = settings_value_as_int((char*)str, ike.remote_port);
675 }
69b80589 676 str = nm_setting_vpn_get_data_item(vpn, "virtual");
8a00a845 677 virtual = streq(str, "yes");
69b80589 678 str = nm_setting_vpn_get_data_item(vpn, "encap");
9486a2e5 679 ike.force_encap = streq(str, "yes");
69b80589 680 str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
749ac175 681 child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
7daf5226 682
ec249871
MW
683 /**
684 * Register credentials
685 */
69b80589 686 priv->creds->clear(priv->creds);
7daf5226 687
0ed6b7a7 688 /* gateway/CA cert */
69b80589 689 str = nm_setting_vpn_get_data_item(vpn, "certificate");
ec249871
MW
690 if (str)
691 {
ec249871
MW
692 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
693 BUILD_FROM_FILE, str, BUILD_END);
85af7a89
MW
694 if (!cert)
695 {
696 g_set_error(err, NM_VPN_PLUGIN_ERROR,
697 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
698 "Loading gateway certificate failed.");
699 return FALSE;
700 }
701 priv->creds->add_certificate(priv->creds, cert);
ec249871 702 }
85af7a89 703 else
a88aae3d 704 {
85af7a89 705 /* no certificate defined, fall back to system-wide CA certificates */
97c74b56
TB
706 priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
707 lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
a88aae3d 708 }
19e64e10
TB
709
710 str = nm_setting_vpn_get_data_item(vpn, "remote-identity");
711 if (str)
712 {
713 gateway = identification_create_from_string((char*)str);
714 }
715 else if (cert)
716 {
717 x509 = (x509_t*)cert;
718 if (!(x509->get_flags(x509) & X509_CA))
719 { /* for server certificates, we use the subject as identity */
720 gateway = cert->get_subject(cert);
721 gateway = gateway->clone(gateway);
722 }
723 }
724 if (!gateway || gateway->get_type(gateway) == ID_ANY)
85af7a89 725 {
19e64e10
TB
726 /* if the user configured a CA certificate (or an invalid identity),
727 * we use the IP/hostname of the server */
9486a2e5 728 gateway = identification_create_from_string(ike.remote);
e6fcc172 729 loose_gateway_id = TRUE;
0ed6b7a7 730 }
19e64e10 731 DBG1(DBG_CFG, "using gateway identity '%Y'", gateway);
7daf5226 732
6dbce9c8
MW
733 /**
734 * Set up configurations
735 */
9486a2e5 736 ike_cfg = ike_cfg_create(&ike);
4ac68f02
D
737
738 str = nm_setting_vpn_get_data_item(vpn, "proposal");
739 proposal = streq(str, "yes");
740 str = nm_setting_vpn_get_data_item(vpn, "ike");
741 if (proposal && str && strlen(str))
742 {
743 enumerator = enumerator_create_token(str, ";", "");
744 while (enumerator->enumerate(enumerator, &str))
745 {
746 prop = proposal_create_from_string(PROTO_IKE, str);
747 if (!prop)
748 {
749 g_set_error(err, NM_VPN_PLUGIN_ERROR,
750 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
751 "Invalid IKE proposal.");
752 enumerator->destroy(enumerator);
753 ike_cfg->destroy(ike_cfg);
754 gateway->destroy(gateway);
4ac68f02
D
755 return FALSE;
756 }
757 ike_cfg->add_proposal(ike_cfg, prop);
758 }
759 enumerator->destroy(enumerator);
760 }
761 else
762 {
763 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
764 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
765 }
2ba5dadb
TB
766
767 peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
101d26ba
MW
768 if (virtual)
769 {
5538e290
TB
770 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
771 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
101d26ba 772 }
bc3eda99
TB
773
774 method = nm_setting_vpn_get_data_item(vpn, "method");
775 if (streq(method, "cert") ||
776 streq(method, "eap-tls") ||
777 streq(method, "key") ||
778 streq(method, "agent") ||
779 streq(method, "smartcard"))
780 {
781 if (!add_auth_cfg_cert (priv, vpn, peer_cfg, err))
782 {
783 peer_cfg->destroy(peer_cfg);
784 ike_cfg->destroy(ike_cfg);
785 gateway->destroy(gateway);
786 return FALSE;
787 }
788 }
789 else if (streq(method, "eap") ||
790 streq(method, "psk"))
791 {
792 if (!add_auth_cfg_pw(priv, vpn, peer_cfg, err))
793 {
794 peer_cfg->destroy(peer_cfg);
795 ike_cfg->destroy(ike_cfg);
796 gateway->destroy(gateway);
797 return FALSE;
798 }
799 }
800 else
801 {
802 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
803 "Configuration parameters missing.");
804 peer_cfg->destroy(peer_cfg);
805 ike_cfg->destroy(ike_cfg);
806 gateway->destroy(gateway);
807 return FALSE;
808 }
809
a44bb934 810 auth = auth_cfg_create();
393e0167 811 if (streq(method, "psk"))
5ae822cf
TB
812 {
813 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
814 }
815 else
816 {
817 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
818 }
0ed6b7a7 819 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
e6fcc172 820 auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
a44bb934 821 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
7daf5226 822
8a00a845 823 child_cfg = child_cfg_create(priv->name, &child);
4ac68f02
D
824 str = nm_setting_vpn_get_data_item(vpn, "esp");
825 if (proposal && str && strlen(str))
826 {
827 enumerator = enumerator_create_token(str, ";", "");
828 while (enumerator->enumerate(enumerator, &str))
829 {
830 prop = proposal_create_from_string(PROTO_ESP, str);
831 if (!prop)
832 {
833 g_set_error(err, NM_VPN_PLUGIN_ERROR,
834 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
835 "Invalid ESP proposal.");
836 enumerator->destroy(enumerator);
837 child_cfg->destroy(child_cfg);
838 peer_cfg->destroy(peer_cfg);
839 return FALSE;
840 }
841 child_cfg->add_proposal(child_cfg, prop);
842 }
843 enumerator->destroy(enumerator);
844 }
845 else
846 {
4ac68f02 847 child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
33412158 848 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
4ac68f02 849 }
b81d8cd3 850 ts = traffic_selector_create_dynamic(0, 0, 65535);
6dbce9c8 851 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
04db34a3
T
852 str = nm_setting_vpn_get_data_item(vpn, "remote-ts");
853 if (str && strlen(str))
854 {
855 enumerator = enumerator_create_token(str, ";", "");
856 while (enumerator->enumerate(enumerator, &str))
857 {
858 ts = traffic_selector_create_from_cidr((char*)str, 0, 0, 65535);
859 if (!ts)
860 {
861 g_set_error(err, NM_VPN_PLUGIN_ERROR,
862 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
863 "Invalid remote traffic selector.");
864 enumerator->destroy(enumerator);
865 child_cfg->destroy(child_cfg);
866 peer_cfg->destroy(peer_cfg);
867 return FALSE;
868 }
869 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
870 }
871 enumerator->destroy(enumerator);
872 }
873 else
874 {
875 ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
876 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
877 ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
878 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
879 }
6dbce9c8 880 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
7daf5226 881
6dbce9c8 882 /**
bad99d5a 883 * Prepare IKE_SA
6dbce9c8
MW
884 */
885 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
886 peer_cfg);
7f6386af 887 peer_cfg->destroy(peer_cfg);
3d54ae94
MW
888 if (!ike_sa)
889 {
3d54ae94
MW
890 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
891 "IKE version not supported.");
892 return FALSE;
893 }
7daf5226 894
bad99d5a
MW
895 /**
896 * Register listener, enable initiate-failure-detection hooks
897 */
69b80589 898 priv->ike_sa = ike_sa;
3d2f5ae0
TB
899 priv->listener.ike_state_change = _ike_state_change;
900 priv->listener.child_state_change = _child_state_change;
7daf5226 901
bad99d5a
MW
902 /**
903 * Initiate
904 */
3d54ae94 905 child_cfg->get_ref(child_cfg);
7f30e1ae 906 if (ike_sa->initiate(ike_sa, child_cfg, NULL) != SUCCESS)
6dbce9c8
MW
907 {
908 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
7daf5226 909
6dbce9c8 910 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
323f9f99 911 "Initiating failed.");
6dbce9c8
MW
912 return FALSE;
913 }
6dbce9c8
MW
914 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
915 return TRUE;
916}
917
918/**
7daf5226 919 * NeedSecrets called from NM via DBUS
6dbce9c8 920 */
9a71b721
LR
921static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
922 const char **setting_name, GError **error)
6dbce9c8 923{
9a71b721 924 NMSettingVpn *settings;
bc3eda99
TB
925 const char *method, *cert_source, *path;
926 bool need_secret = FALSE;
7daf5226 927
ec249871
MW
928 settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
929 NM_TYPE_SETTING_VPN));
d7625f09 930 method = nm_setting_vpn_get_data_item(settings, "method");
aff26a62 931 if (method)
ec249871 932 {
bc3eda99
TB
933 if (streq(method, "cert") ||
934 streq(method, "eap-tls") ||
935 streq(method, "key") ||
936 streq(method, "agent") ||
937 streq(method, "smartcard"))
aff26a62 938 {
bc3eda99
TB
939 cert_source = nm_setting_vpn_get_data_item(settings, "cert-source");
940 if (!cert_source)
aff26a62 941 {
bc3eda99 942 cert_source = method;
aff26a62 943 }
bc3eda99 944 if (streq(cert_source, "agent"))
aff26a62 945 {
bc3eda99 946 need_secret = !nm_setting_vpn_get_secret(settings, "agent");
aff26a62 947 }
bc3eda99 948 else if (streq(cert_source, "smartcard"))
1d03954a 949 {
bc3eda99
TB
950 need_secret = !nm_setting_vpn_get_secret(settings, "password");
951 }
952 else
953 {
954 need_secret = TRUE;
955 path = nm_setting_vpn_get_data_item(settings, "userkey");
956 if (path)
c489c588 957 {
bc3eda99
TB
958 private_key_t *key;
959
960 /* try to load/decrypt the private key */
961 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
962 KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
963 if (key)
964 {
965 key->destroy(key);
966 need_secret = FALSE;
967 }
968 else if (nm_setting_vpn_get_secret(settings, "password"))
969 {
970 need_secret = FALSE;
971 }
c489c588 972 }
1d03954a
MW
973 }
974 }
bc3eda99
TB
975 else if (streq(method, "eap") ||
976 streq(method, "psk"))
8bec0f51 977 {
bc3eda99 978 need_secret = !nm_setting_vpn_get_secret(settings, "password");
8bec0f51 979 }
ec249871 980 }
aff26a62 981 *setting_name = NM_SETTING_VPN_SETTING_NAME;
bc3eda99 982 return need_secret;
6dbce9c8
MW
983}
984
985/**
9a71b721 986 * The actual disconnection
6dbce9c8 987 */
9a71b721 988static gboolean do_disconnect(gpointer plugin)
6dbce9c8 989{
69b80589 990 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
6dbce9c8
MW
991 enumerator_t *enumerator;
992 ike_sa_t *ike_sa;
993 u_int id;
7daf5226 994
69b80589 995 /* our ike_sa pointer might be invalid, lookup sa */
69c3eca0
MW
996 enumerator = charon->controller->create_ike_sa_enumerator(
997 charon->controller, TRUE);
6dbce9c8
MW
998 while (enumerator->enumerate(enumerator, &ike_sa))
999 {
69b80589 1000 if (priv->ike_sa == ike_sa)
6dbce9c8
MW
1001 {
1002 id = ike_sa->get_unique_id(ike_sa);
1003 enumerator->destroy(enumerator);
7b729097 1004 charon->controller->terminate_ike(charon->controller, id, FALSE,
8e3f14ba 1005 controller_cb_empty, NULL, 0);
d5d83756
TB
1006
1007 /* clear secrets as we are asked for new secrets (where we'd find
1008 * the cached secrets from earlier connections) before we clear
1009 * them in connect() */
1010 priv->creds->clear(priv->creds);
9a71b721 1011 return FALSE;
6dbce9c8
MW
1012 }
1013 }
1014 enumerator->destroy(enumerator);
7daf5226 1015
9a71b721 1016 g_debug("Connection not found.");
6dbce9c8
MW
1017 return FALSE;
1018}
1019
9a71b721
LR
1020/**
1021 * Disconnect called from NM via DBUS
1022 */
1023static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
1024{
9a71b721
LR
1025 /* enqueue the actual disconnection, because we may be called in
1026 * response to a listener_t callback and the SA enumeration would
1027 * possibly deadlock. */
1028 g_idle_add(do_disconnect, plugin);
1029
1030 return TRUE;
1031}
1032
6dbce9c8
MW
1033/**
1034 * Initializer
1035 */
1036static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
1037{
69b80589 1038 NMStrongswanPluginPrivate *priv;
7daf5226 1039
69b80589 1040 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
9a71b721 1041 priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
b64f3336 1042 memset(&priv->listener, 0, sizeof(listener_t));
3d2f5ae0
TB
1043 priv->listener.child_updown = _child_updown;
1044 priv->listener.ike_rekey = _ike_rekey;
1045 priv->listener.ike_reestablish_pre = _ike_reestablish_pre;
1046 priv->listener.ike_reestablish_post = _ike_reestablish_post;
5575aaf5 1047 charon->bus->add_listener(charon->bus, &priv->listener);
aa3d5bf7 1048 priv->tun = tun_device_create(NULL);
c15eea73
TB
1049 priv->name = NULL;
1050}
1051
aa3d5bf7
TB
1052/**
1053 * Destructor
1054 */
1055static void nm_strongswan_plugin_dispose(GObject *obj)
1056{
1057 NMStrongswanPlugin *plugin;
1058 NMStrongswanPluginPrivate *priv;
1059
1060 plugin = NM_STRONGSWAN_PLUGIN(obj);
1061 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
1062 if (priv->tun)
1063 {
1064 priv->tun->destroy(priv->tun);
1065 priv->tun = NULL;
1066 }
1067 G_OBJECT_CLASS (nm_strongswan_plugin_parent_class)->dispose (obj);
1068}
1069
6dbce9c8
MW
1070/**
1071 * Class constructor
1072 */
1073static void nm_strongswan_plugin_class_init(
1074 NMStrongswanPluginClass *strongswan_class)
1075{
9a71b721 1076 NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
7daf5226 1077
6dbce9c8
MW
1078 parent_class->connect = connect_;
1079 parent_class->need_secrets = need_secrets;
1080 parent_class->disconnect = disconnect;
aa3d5bf7 1081 G_OBJECT_CLASS(strongswan_class)->dispose = nm_strongswan_plugin_dispose;
6dbce9c8
MW
1082}
1083
1084/**
1085 * Object constructor
1086 */
3ab0e8a0
MW
1087NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
1088 nm_handler_t *handler)
6dbce9c8 1089{
9a71b721
LR
1090 GError *error = NULL;
1091
1092 NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
ec249871 1093 NM_TYPE_STRONGSWAN_PLUGIN,
9a71b721
LR
1094 NULL,
1095 &error,
1096 NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
ec249871 1097 NULL);
9a71b721 1098
1b9f6c24
MW
1099 if (plugin)
1100 {
69b80589 1101 NMStrongswanPluginPrivate *priv;
7daf5226 1102
c15eea73 1103 /* the rest of the initialization happened in _init above */
69b80589
MW
1104 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
1105 priv->creds = creds;
1106 priv->handler = handler;
1b9f6c24 1107 }
9a71b721
LR
1108 else
1109 {
1110 g_warning ("Failed to initialize a plugin instance: %s", error->message);
1111 g_error_free (error);
1112 }
1113
ec249871 1114 return plugin;
6dbce9c8 1115}