]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/charon-nm/nm/nm_service.c
Merge branch 'childless'
[thirdparty/strongswan.git] / src / charon-nm / nm / nm_service.c
1 /*
2 * Copyright (C) 2017 Lubomir Rintel
3 *
4 * Copyright (C) 2013-2019 Tobias Brunner
5 * Copyright (C) 2008-2009 Martin Willi
6 * HSR Hochschule fuer Technik Rapperswil
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.
17 */
18
19 #include "nm_service.h"
20
21 #include <daemon.h>
22 #include <networking/host.h>
23 #include <utils/identification.h>
24 #include <config/peer_cfg.h>
25 #include <credentials/certificates/x509.h>
26
27 #include <stdio.h>
28
29 G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
30
31 /**
32 * Private data of NMStrongswanPlugin
33 */
34 typedef struct {
35 /* implements bus listener interface */
36 listener_t listener;
37 /* IKE_SA we are listening on */
38 ike_sa_t *ike_sa;
39 /* backref to public plugin */
40 NMVpnServicePlugin *plugin;
41 /* credentials to use for authentication */
42 nm_creds_t *creds;
43 /* attribute handler for DNS/NBNS server information */
44 nm_handler_t *handler;
45 /* name of the connection */
46 char *name;
47 } NMStrongswanPluginPrivate;
48
49 #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
50 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
51 NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
52
53 /**
54 * Convert an address chunk to a GValue
55 */
56 static GVariant *addr_to_variant(chunk_t addr)
57 {
58 GVariantBuilder builder;
59 int i;
60
61 switch (addr.len)
62 {
63 case 4:
64 return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
65 case 16:
66 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
67 for (i = 0; i < addr.len; i++)
68 {
69 g_variant_builder_add (&builder, "y", addr.ptr[i]);
70
71 }
72 return g_variant_builder_end (&builder);
73 default:
74 return NULL;
75 }
76 }
77
78 /**
79 * Convert a host to a GValue
80 */
81 static GVariant *host_to_variant(host_t *host)
82 {
83 return addr_to_variant(host->get_address(host));
84 }
85
86 /**
87 * Convert enumerated handler chunks to a GValue
88 */
89 static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
90 configuration_attribute_type_t type)
91 {
92 GVariantBuilder builder;
93 enumerator_t *enumerator;
94 chunk_t *chunk;
95
96 g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
97
98 enumerator = handler->create_enumerator(handler, type);
99 while (enumerator->enumerate(enumerator, &chunk))
100 {
101 g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
102 }
103 enumerator->destroy(enumerator);
104
105 return g_variant_builder_end (&builder);
106 }
107
108 /**
109 * Signal IP config to NM, set connection as established
110 */
111 static void signal_ip_config(NMVpnServicePlugin *plugin,
112 ike_sa_t *ike_sa, child_sa_t *child_sa)
113 {
114 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
115 GVariantBuilder builder, ip4builder, ip6builder;
116 GVariant *ip4config, *ip6config;
117 enumerator_t *enumerator;
118 host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
119 nm_handler_t *handler;
120
121 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
122 g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
123 g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
124
125 handler = priv->handler;
126
127 /* NM apparently requires to know the gateway */
128 other = ike_sa->get_other_host(ike_sa);
129 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
130 host_to_variant(other));
131
132 /* pass the first virtual IPs we got or use the physical IP */
133 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
134 while (enumerator->enumerate(enumerator, &me))
135 {
136 switch (me->get_family(me))
137 {
138 case AF_INET:
139 if (!vip4)
140 {
141 vip4 = me;
142 }
143 break;
144 case AF_INET6:
145 if (!vip6)
146 {
147 vip6 = me;
148 }
149 break;
150 }
151 }
152 enumerator->destroy(enumerator);
153 if (!vip4 && !vip6)
154 {
155 me = ike_sa->get_my_host(ike_sa);
156 switch (me->get_family(me))
157 {
158 case AF_INET:
159 vip4 = me;
160 break;
161 case AF_INET6:
162 vip6 = me;
163 break;
164 }
165 }
166
167 if (vip4)
168 {
169 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
170 host_to_variant(vip4));
171 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
172 g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
173
174 /* prevent NM from changing the default route. we set our own route in our
175 * own routing table
176 */
177 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
178 g_variant_new_boolean (TRUE));
179
180 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
181 handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
182
183 g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
184 handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
185 }
186
187 if (vip6)
188 {
189 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
190 host_to_variant(vip6));
191 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
192 g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
193 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
194 g_variant_new_boolean (TRUE));
195 g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
196 handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
197 /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
198 }
199
200 ip4config = g_variant_builder_end (&ip4builder);
201 if (g_variant_n_children (ip4config))
202 {
203 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
204 g_variant_new_boolean (TRUE));
205 }
206 else
207 {
208 g_variant_unref (ip4config);
209 ip4config = NULL;
210 }
211
212 ip6config = g_variant_builder_end (&ip6builder);
213 if (g_variant_n_children (ip6config))
214 {
215 g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
216 g_variant_new_boolean (TRUE));
217 }
218 else
219 {
220 g_variant_unref (ip6config);
221 ip6config = NULL;
222 }
223
224 handler->reset(handler);
225
226 nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
227 if (ip4config)
228 {
229 nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
230 }
231 if (ip6config)
232 {
233 nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
234 }
235 }
236
237 /**
238 * signal failure to NM, connecting failed
239 */
240 static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure)
241 {
242 nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
243
244 handler->reset(handler);
245
246 nm_vpn_service_plugin_failure(plugin, failure);
247 }
248
249 /**
250 * Implementation of listener_t.ike_state_change
251 */
252 static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa,
253 ike_sa_state_t state)
254 {
255 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
256
257 if (private->ike_sa == ike_sa && state == IKE_DESTROYING)
258 {
259 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
260 return FALSE;
261 }
262 return TRUE;
263 }
264
265 /**
266 * Implementation of listener_t.child_state_change
267 */
268 static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa,
269 child_sa_t *child_sa, child_sa_state_t state)
270 {
271 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
272
273 if (private->ike_sa == ike_sa && state == CHILD_DESTROYING)
274 {
275 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
276 return FALSE;
277 }
278 return TRUE;
279 }
280
281 /**
282 * Implementation of listener_t.child_updown
283 */
284 static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
285 child_sa_t *child_sa, bool up)
286 {
287 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
288
289 if (private->ike_sa == ike_sa)
290 {
291 if (up)
292 { /* disable initiate-failure-detection hooks */
293 private->listener.ike_state_change = NULL;
294 private->listener.child_state_change = NULL;
295 signal_ip_config(private->plugin, ike_sa, child_sa);
296 }
297 else
298 {
299 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
300 return FALSE;
301 }
302 }
303 return TRUE;
304 }
305
306 /**
307 * Implementation of listener_t.ike_rekey
308 */
309 static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
310 {
311 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
312
313 if (private->ike_sa == old)
314 { /* follow a rekeyed IKE_SA */
315 private->ike_sa = new;
316 }
317 return TRUE;
318 }
319
320 /**
321 * Find a certificate for which we have a private key on a smartcard
322 */
323 static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
324 char *pin)
325 {
326 enumerator_t *enumerator, *sans;
327 identification_t *id = NULL;
328 certificate_t *cert;
329 x509_t *x509;
330 private_key_t *key;
331 chunk_t keyid;
332
333 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
334 CERT_X509, KEY_ANY, NULL, FALSE);
335 while (enumerator->enumerate(enumerator, &cert))
336 {
337 x509 = (x509_t*)cert;
338
339 /* there might be a lot of certificates, filter them by usage */
340 if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
341 !(x509->get_flags(x509) & X509_CA))
342 {
343 keyid = x509->get_subjectKeyIdentifier(x509);
344 if (keyid.ptr)
345 {
346 /* try to find a private key by the certificate keyid */
347 priv->creds->set_pin(priv->creds, keyid, pin);
348 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
349 KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
350 if (key)
351 {
352 /* prefer a more convenient subjectAltName */
353 sans = x509->create_subjectAltName_enumerator(x509);
354 if (!sans->enumerate(sans, &id))
355 {
356 id = cert->get_subject(cert);
357 }
358 id = id->clone(id);
359 sans->destroy(sans);
360
361 DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
362 priv->creds->set_cert_and_key(priv->creds,
363 cert->get_ref(cert), key);
364 break;
365 }
366 }
367 }
368 }
369 enumerator->destroy(enumerator);
370 return id;
371 }
372
373 /**
374 * Connect function called from NM via DBUS
375 */
376 static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
377 GError **err)
378 {
379 NMStrongswanPluginPrivate *priv;
380 NMSettingConnection *conn;
381 NMSettingVpn *vpn;
382 enumerator_t *enumerator;
383 identification_t *user = NULL, *gateway = NULL;
384 const char *str;
385 bool virtual, proposal;
386 proposal_t *prop;
387 ike_cfg_t *ike_cfg;
388 peer_cfg_t *peer_cfg;
389 child_cfg_t *child_cfg;
390 traffic_selector_t *ts;
391 ike_sa_t *ike_sa;
392 auth_cfg_t *auth;
393 auth_class_t auth_class = AUTH_CLASS_EAP;
394 certificate_t *cert = NULL;
395 x509_t *x509;
396 bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE;
397 ike_cfg_create_t ike = {
398 .version = IKEV2,
399 .local = "%any",
400 .local_port = charon->socket->get_port(charon->socket, FALSE),
401 .remote_port = IKEV2_UDP_PORT,
402 .fragmentation = FRAGMENTATION_YES,
403 };
404 peer_cfg_create_t peer = {
405 .cert_policy = CERT_SEND_IF_ASKED,
406 .unique = UNIQUE_REPLACE,
407 .keyingtries = 1,
408 .rekey_time = 36000, /* 10h */
409 .jitter_time = 600, /* 10min */
410 .over_time = 600, /* 10min */
411 };
412 child_cfg_create_t child = {
413 .lifetime = {
414 .time = {
415 .life = 10800 /* 3h */,
416 .rekey = 10200 /* 2h50min */,
417 .jitter = 300 /* 5min */
418 },
419 },
420 .mode = MODE_TUNNEL,
421 };
422
423 /**
424 * Read parameters
425 */
426 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
427 conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
428 NM_TYPE_SETTING_CONNECTION));
429 vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
430 NM_TYPE_SETTING_VPN));
431 if (priv->name)
432 {
433 free(priv->name);
434 }
435 priv->name = strdup(nm_setting_connection_get_id(conn));
436 DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
437 priv->name);
438 DBG4(DBG_CFG, "%s",
439 nm_setting_to_string(NM_SETTING(vpn)));
440 ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address");
441 if (!ike.remote || !*ike.remote)
442 {
443 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
444 "Gateway address missing.");
445 return FALSE;
446 }
447 str = nm_setting_vpn_get_data_item(vpn, "virtual");
448 virtual = streq(str, "yes");
449 str = nm_setting_vpn_get_data_item(vpn, "encap");
450 ike.force_encap = streq(str, "yes");
451 str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
452 child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
453 str = nm_setting_vpn_get_data_item(vpn, "method");
454 if (streq(str, "psk"))
455 {
456 auth_class = AUTH_CLASS_PSK;
457 }
458 else if (streq(str, "agent"))
459 {
460 auth_class = AUTH_CLASS_PUBKEY;
461 agent = TRUE;
462 }
463 else if (streq(str, "key"))
464 {
465 auth_class = AUTH_CLASS_PUBKEY;
466 }
467 else if (streq(str, "smartcard"))
468 {
469 auth_class = AUTH_CLASS_PUBKEY;
470 smartcard = TRUE;
471 }
472
473 /**
474 * Register credentials
475 */
476 priv->creds->clear(priv->creds);
477
478 /* gateway/CA cert */
479 str = nm_setting_vpn_get_data_item(vpn, "certificate");
480 if (str)
481 {
482 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
483 BUILD_FROM_FILE, str, BUILD_END);
484 if (!cert)
485 {
486 g_set_error(err, NM_VPN_PLUGIN_ERROR,
487 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
488 "Loading gateway certificate failed.");
489 return FALSE;
490 }
491 priv->creds->add_certificate(priv->creds, cert);
492
493 x509 = (x509_t*)cert;
494 if (!(x509->get_flags(x509) & X509_CA))
495 { /* For a gateway certificate, we use the cert subject as identity. */
496 gateway = cert->get_subject(cert);
497 gateway = gateway->clone(gateway);
498 DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway);
499 }
500 }
501 else
502 {
503 /* no certificate defined, fall back to system-wide CA certificates */
504 priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
505 lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
506 }
507 if (!gateway)
508 {
509 /* If the user configured a CA certificate, we use the IP/DNS
510 * of the gateway as its identity. This identity will be used for
511 * certificate lookup and requires the configured IP/DNS to be
512 * included in the gateway certificate. */
513 gateway = identification_create_from_string(ike.remote);
514 DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
515 loose_gateway_id = TRUE;
516 }
517
518 if (auth_class == AUTH_CLASS_EAP ||
519 auth_class == AUTH_CLASS_PSK)
520 {
521 /* username/password or PSK authentication ... */
522 str = nm_setting_vpn_get_data_item(vpn, "user");
523 if (str)
524 {
525 user = identification_create_from_string((char*)str);
526 str = nm_setting_vpn_get_secret(vpn, "password");
527 if (auth_class == AUTH_CLASS_PSK &&
528 strlen(str) < 20)
529 {
530 g_set_error(err, NM_VPN_PLUGIN_ERROR,
531 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
532 "pre-shared key is too short.");
533 gateway->destroy(gateway);
534 user->destroy(user);
535 return FALSE;
536 }
537 priv->creds->set_username_password(priv->creds, user, (char*)str);
538 }
539 }
540
541 if (auth_class == AUTH_CLASS_PUBKEY)
542 {
543 if (smartcard)
544 {
545 char *pin;
546
547 pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
548 if (pin)
549 {
550 user = find_smartcard_key(priv, pin);
551 }
552 if (!user)
553 {
554 g_set_error(err, NM_VPN_PLUGIN_ERROR,
555 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
556 "no usable smartcard certificate found.");
557 gateway->destroy(gateway);
558 return FALSE;
559 }
560 }
561 /* ... or certificate/private key authenitcation */
562 else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
563 {
564 public_key_t *public;
565 private_key_t *private = NULL;
566
567 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
568 BUILD_FROM_FILE, str, BUILD_END);
569 if (!cert)
570 {
571 g_set_error(err, NM_VPN_PLUGIN_ERROR,
572 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
573 "Loading peer certificate failed.");
574 gateway->destroy(gateway);
575 return FALSE;
576 }
577 /* try agent */
578 str = nm_setting_vpn_get_secret(vpn, "agent");
579 if (agent && str)
580 {
581 public = cert->get_public_key(cert);
582 if (public)
583 {
584 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
585 public->get_type(public),
586 BUILD_AGENT_SOCKET, str,
587 BUILD_PUBLIC_KEY, public,
588 BUILD_END);
589 public->destroy(public);
590 }
591 if (!private)
592 {
593 g_set_error(err, NM_VPN_PLUGIN_ERROR,
594 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
595 "Connecting to SSH agent failed.");
596 }
597 }
598 /* ... or key file */
599 str = nm_setting_vpn_get_data_item(vpn, "userkey");
600 if (!agent && str)
601 {
602 char *secret;
603
604 secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
605 if (secret)
606 {
607 priv->creds->set_key_password(priv->creds, secret);
608 }
609 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
610 KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
611 if (!private)
612 {
613 g_set_error(err, NM_VPN_PLUGIN_ERROR,
614 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
615 "Loading private key failed.");
616 }
617 }
618 if (private)
619 {
620 user = cert->get_subject(cert);
621 user = user->clone(user);
622 priv->creds->set_cert_and_key(priv->creds, cert, private);
623 }
624 else
625 {
626 DESTROY_IF(cert);
627 gateway->destroy(gateway);
628 return FALSE;
629 }
630 }
631 }
632
633 if (!user)
634 {
635 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
636 "Configuration parameters missing.");
637 gateway->destroy(gateway);
638 return FALSE;
639 }
640
641 /**
642 * Set up configurations
643 */
644 ike_cfg = ike_cfg_create(&ike);
645
646 str = nm_setting_vpn_get_data_item(vpn, "proposal");
647 proposal = streq(str, "yes");
648 str = nm_setting_vpn_get_data_item(vpn, "ike");
649 if (proposal && str && strlen(str))
650 {
651 enumerator = enumerator_create_token(str, ";", "");
652 while (enumerator->enumerate(enumerator, &str))
653 {
654 prop = proposal_create_from_string(PROTO_IKE, str);
655 if (!prop)
656 {
657 g_set_error(err, NM_VPN_PLUGIN_ERROR,
658 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
659 "Invalid IKE proposal.");
660 enumerator->destroy(enumerator);
661 ike_cfg->destroy(ike_cfg);
662 gateway->destroy(gateway);
663 user->destroy(user);
664 return FALSE;
665 }
666 ike_cfg->add_proposal(ike_cfg, prop);
667 }
668 enumerator->destroy(enumerator);
669 }
670 else
671 {
672 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
673 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
674 }
675
676 peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
677 if (virtual)
678 {
679 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
680 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
681 }
682 auth = auth_cfg_create();
683 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
684 auth->add(auth, AUTH_RULE_IDENTITY, user);
685 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
686 auth = auth_cfg_create();
687 if (auth_class == AUTH_CLASS_PSK)
688 {
689 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
690 }
691 else
692 {
693 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
694 }
695 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
696 auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
697 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
698
699 child_cfg = child_cfg_create(priv->name, &child);
700 str = nm_setting_vpn_get_data_item(vpn, "esp");
701 if (proposal && str && strlen(str))
702 {
703 enumerator = enumerator_create_token(str, ";", "");
704 while (enumerator->enumerate(enumerator, &str))
705 {
706 prop = proposal_create_from_string(PROTO_ESP, str);
707 if (!prop)
708 {
709 g_set_error(err, NM_VPN_PLUGIN_ERROR,
710 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
711 "Invalid ESP proposal.");
712 enumerator->destroy(enumerator);
713 child_cfg->destroy(child_cfg);
714 peer_cfg->destroy(peer_cfg);
715 return FALSE;
716 }
717 child_cfg->add_proposal(child_cfg, prop);
718 }
719 enumerator->destroy(enumerator);
720 }
721 else
722 {
723 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
724 child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
725 }
726 ts = traffic_selector_create_dynamic(0, 0, 65535);
727 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
728 ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
729 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
730 ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
731 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
732 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
733
734 /**
735 * Prepare IKE_SA
736 */
737 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
738 peer_cfg);
739 if (!ike_sa)
740 {
741 peer_cfg->destroy(peer_cfg);
742 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
743 "IKE version not supported.");
744 return FALSE;
745 }
746 if (!ike_sa->get_peer_cfg(ike_sa))
747 {
748 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
749 }
750 peer_cfg->destroy(peer_cfg);
751
752 /**
753 * Register listener, enable initiate-failure-detection hooks
754 */
755 priv->ike_sa = ike_sa;
756 priv->listener.ike_state_change = ike_state_change;
757 priv->listener.child_state_change = child_state_change;
758 charon->bus->add_listener(charon->bus, &priv->listener);
759
760 /**
761 * Initiate
762 */
763 child_cfg->get_ref(child_cfg);
764 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
765 {
766 charon->bus->remove_listener(charon->bus, &priv->listener);
767 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
768
769 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
770 "Initiating failed.");
771 return FALSE;
772 }
773 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
774 return TRUE;
775 }
776
777 /**
778 * NeedSecrets called from NM via DBUS
779 */
780 static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
781 const char **setting_name, GError **error)
782 {
783 NMSettingVpn *settings;
784 const char *method, *path;
785
786 settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
787 NM_TYPE_SETTING_VPN));
788 method = nm_setting_vpn_get_data_item(settings, "method");
789 if (method)
790 {
791 if (streq(method, "eap") || streq(method, "psk"))
792 {
793 if (nm_setting_vpn_get_secret(settings, "password"))
794 {
795 return FALSE;
796 }
797 }
798 else if (streq(method, "agent"))
799 {
800 if (nm_setting_vpn_get_secret(settings, "agent"))
801 {
802 return FALSE;
803 }
804 }
805 else if (streq(method, "key"))
806 {
807 path = nm_setting_vpn_get_data_item(settings, "userkey");
808 if (path)
809 {
810 private_key_t *key;
811
812 /* try to load/decrypt the private key */
813 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
814 KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
815 if (key)
816 {
817 key->destroy(key);
818 return FALSE;
819 }
820 else if (nm_setting_vpn_get_secret(settings, "password"))
821 {
822 return FALSE;
823 }
824 }
825 }
826 else if (streq(method, "smartcard"))
827 {
828 if (nm_setting_vpn_get_secret(settings, "password"))
829 {
830 return FALSE;
831 }
832 }
833 }
834 *setting_name = NM_SETTING_VPN_SETTING_NAME;
835 return TRUE;
836 }
837
838 /**
839 * The actual disconnection
840 */
841 static gboolean do_disconnect(gpointer plugin)
842 {
843 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
844 enumerator_t *enumerator;
845 ike_sa_t *ike_sa;
846 u_int id;
847
848 /* our ike_sa pointer might be invalid, lookup sa */
849 enumerator = charon->controller->create_ike_sa_enumerator(
850 charon->controller, TRUE);
851 while (enumerator->enumerate(enumerator, &ike_sa))
852 {
853 if (priv->ike_sa == ike_sa)
854 {
855 id = ike_sa->get_unique_id(ike_sa);
856 enumerator->destroy(enumerator);
857 charon->controller->terminate_ike(charon->controller, id, FALSE,
858 controller_cb_empty, NULL, 0);
859 return FALSE;
860 }
861 }
862 enumerator->destroy(enumerator);
863
864 g_debug("Connection not found.");
865 return FALSE;
866 }
867
868 /**
869 * Disconnect called from NM via DBUS
870 */
871 static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
872 {
873 /* enqueue the actual disconnection, because we may be called in
874 * response to a listener_t callback and the SA enumeration would
875 * possibly deadlock. */
876 g_idle_add(do_disconnect, plugin);
877
878 return TRUE;
879 }
880
881 /**
882 * Initializer
883 */
884 static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
885 {
886 NMStrongswanPluginPrivate *priv;
887
888 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
889 priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
890 memset(&priv->listener, 0, sizeof(listener_t));
891 priv->listener.child_updown = child_updown;
892 priv->listener.ike_rekey = ike_rekey;
893 priv->name = NULL;
894 }
895
896 /**
897 * Class constructor
898 */
899 static void nm_strongswan_plugin_class_init(
900 NMStrongswanPluginClass *strongswan_class)
901 {
902 NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
903
904 g_type_class_add_private(G_OBJECT_CLASS(strongswan_class),
905 sizeof(NMStrongswanPluginPrivate));
906 parent_class->connect = connect_;
907 parent_class->need_secrets = need_secrets;
908 parent_class->disconnect = disconnect;
909 }
910
911 /**
912 * Object constructor
913 */
914 NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
915 nm_handler_t *handler)
916 {
917 GError *error = NULL;
918
919 NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
920 NM_TYPE_STRONGSWAN_PLUGIN,
921 NULL,
922 &error,
923 NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
924 NULL);
925
926 if (plugin)
927 {
928 NMStrongswanPluginPrivate *priv;
929
930 /* the rest of the initialization happened in _init above */
931 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
932 priv->creds = creds;
933 priv->handler = handler;
934 }
935 else
936 {
937 g_warning ("Failed to initialize a plugin instance: %s", error->message);
938 g_error_free (error);
939 }
940
941 return plugin;
942 }