]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/charon-nm/nm/nm_service.c
Merge branch 'nm-ipv6'
[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 *address, *str;
385 bool virtual, encap, 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 peer_cfg_create_t peer = {
398 .cert_policy = CERT_SEND_IF_ASKED,
399 .unique = UNIQUE_REPLACE,
400 .keyingtries = 1,
401 .rekey_time = 36000, /* 10h */
402 .jitter_time = 600, /* 10min */
403 .over_time = 600, /* 10min */
404 };
405 child_cfg_create_t child = {
406 .lifetime = {
407 .time = {
408 .life = 10800 /* 3h */,
409 .rekey = 10200 /* 2h50min */,
410 .jitter = 300 /* 5min */
411 },
412 },
413 .mode = MODE_TUNNEL,
414 };
415
416 /**
417 * Read parameters
418 */
419 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
420 conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
421 NM_TYPE_SETTING_CONNECTION));
422 vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
423 NM_TYPE_SETTING_VPN));
424 if (priv->name)
425 {
426 free(priv->name);
427 }
428 priv->name = strdup(nm_setting_connection_get_id(conn));
429 DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
430 priv->name);
431 DBG4(DBG_CFG, "%s",
432 nm_setting_to_string(NM_SETTING(vpn)));
433 address = nm_setting_vpn_get_data_item(vpn, "address");
434 if (!address || !*address)
435 {
436 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
437 "Gateway address missing.");
438 return FALSE;
439 }
440 str = nm_setting_vpn_get_data_item(vpn, "virtual");
441 virtual = streq(str, "yes");
442 str = nm_setting_vpn_get_data_item(vpn, "encap");
443 encap = streq(str, "yes");
444 str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
445 child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
446 str = nm_setting_vpn_get_data_item(vpn, "method");
447 if (streq(str, "psk"))
448 {
449 auth_class = AUTH_CLASS_PSK;
450 }
451 else if (streq(str, "agent"))
452 {
453 auth_class = AUTH_CLASS_PUBKEY;
454 agent = TRUE;
455 }
456 else if (streq(str, "key"))
457 {
458 auth_class = AUTH_CLASS_PUBKEY;
459 }
460 else if (streq(str, "smartcard"))
461 {
462 auth_class = AUTH_CLASS_PUBKEY;
463 smartcard = TRUE;
464 }
465
466 /**
467 * Register credentials
468 */
469 priv->creds->clear(priv->creds);
470
471 /* gateway/CA cert */
472 str = nm_setting_vpn_get_data_item(vpn, "certificate");
473 if (str)
474 {
475 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
476 BUILD_FROM_FILE, str, BUILD_END);
477 if (!cert)
478 {
479 g_set_error(err, NM_VPN_PLUGIN_ERROR,
480 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
481 "Loading gateway certificate failed.");
482 return FALSE;
483 }
484 priv->creds->add_certificate(priv->creds, cert);
485
486 x509 = (x509_t*)cert;
487 if (!(x509->get_flags(x509) & X509_CA))
488 { /* For a gateway certificate, we use the cert subject as identity. */
489 gateway = cert->get_subject(cert);
490 gateway = gateway->clone(gateway);
491 DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway);
492 }
493 }
494 else
495 {
496 /* no certificate defined, fall back to system-wide CA certificates */
497 priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
498 lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
499 }
500 if (!gateway)
501 {
502 /* If the user configured a CA certificate, we use the IP/DNS
503 * of the gateway as its identity. This identity will be used for
504 * certificate lookup and requires the configured IP/DNS to be
505 * included in the gateway certificate. */
506 gateway = identification_create_from_string((char*)address);
507 DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
508 loose_gateway_id = TRUE;
509 }
510
511 if (auth_class == AUTH_CLASS_EAP ||
512 auth_class == AUTH_CLASS_PSK)
513 {
514 /* username/password or PSK authentication ... */
515 str = nm_setting_vpn_get_data_item(vpn, "user");
516 if (str)
517 {
518 user = identification_create_from_string((char*)str);
519 str = nm_setting_vpn_get_secret(vpn, "password");
520 if (auth_class == AUTH_CLASS_PSK &&
521 strlen(str) < 20)
522 {
523 g_set_error(err, NM_VPN_PLUGIN_ERROR,
524 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
525 "pre-shared key is too short.");
526 gateway->destroy(gateway);
527 user->destroy(user);
528 return FALSE;
529 }
530 priv->creds->set_username_password(priv->creds, user, (char*)str);
531 }
532 }
533
534 if (auth_class == AUTH_CLASS_PUBKEY)
535 {
536 if (smartcard)
537 {
538 char *pin;
539
540 pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
541 if (pin)
542 {
543 user = find_smartcard_key(priv, pin);
544 }
545 if (!user)
546 {
547 g_set_error(err, NM_VPN_PLUGIN_ERROR,
548 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
549 "no usable smartcard certificate found.");
550 gateway->destroy(gateway);
551 return FALSE;
552 }
553 }
554 /* ... or certificate/private key authenitcation */
555 else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
556 {
557 public_key_t *public;
558 private_key_t *private = NULL;
559
560 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
561 BUILD_FROM_FILE, str, BUILD_END);
562 if (!cert)
563 {
564 g_set_error(err, NM_VPN_PLUGIN_ERROR,
565 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
566 "Loading peer certificate failed.");
567 gateway->destroy(gateway);
568 return FALSE;
569 }
570 /* try agent */
571 str = nm_setting_vpn_get_secret(vpn, "agent");
572 if (agent && str)
573 {
574 public = cert->get_public_key(cert);
575 if (public)
576 {
577 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
578 public->get_type(public),
579 BUILD_AGENT_SOCKET, str,
580 BUILD_PUBLIC_KEY, public,
581 BUILD_END);
582 public->destroy(public);
583 }
584 if (!private)
585 {
586 g_set_error(err, NM_VPN_PLUGIN_ERROR,
587 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
588 "Connecting to SSH agent failed.");
589 }
590 }
591 /* ... or key file */
592 str = nm_setting_vpn_get_data_item(vpn, "userkey");
593 if (!agent && str)
594 {
595 char *secret;
596
597 secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
598 if (secret)
599 {
600 priv->creds->set_key_password(priv->creds, secret);
601 }
602 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
603 KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
604 if (!private)
605 {
606 g_set_error(err, NM_VPN_PLUGIN_ERROR,
607 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
608 "Loading private key failed.");
609 }
610 }
611 if (private)
612 {
613 user = cert->get_subject(cert);
614 user = user->clone(user);
615 priv->creds->set_cert_and_key(priv->creds, cert, private);
616 }
617 else
618 {
619 DESTROY_IF(cert);
620 gateway->destroy(gateway);
621 return FALSE;
622 }
623 }
624 }
625
626 if (!user)
627 {
628 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
629 "Configuration parameters missing.");
630 gateway->destroy(gateway);
631 return FALSE;
632 }
633
634 /**
635 * Set up configurations
636 */
637 ike_cfg = ike_cfg_create(IKEV2, TRUE, encap, "%any",
638 charon->socket->get_port(charon->socket, FALSE),
639 (char*)address, IKEV2_UDP_PORT,
640 FRAGMENTATION_YES, 0);
641
642 str = nm_setting_vpn_get_data_item(vpn, "proposal");
643 proposal = streq(str, "yes");
644 str = nm_setting_vpn_get_data_item(vpn, "ike");
645 if (proposal && str && strlen(str))
646 {
647 enumerator = enumerator_create_token(str, ";", "");
648 while (enumerator->enumerate(enumerator, &str))
649 {
650 prop = proposal_create_from_string(PROTO_IKE, str);
651 if (!prop)
652 {
653 g_set_error(err, NM_VPN_PLUGIN_ERROR,
654 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
655 "Invalid IKE proposal.");
656 enumerator->destroy(enumerator);
657 ike_cfg->destroy(ike_cfg);
658 gateway->destroy(gateway);
659 user->destroy(user);
660 return FALSE;
661 }
662 ike_cfg->add_proposal(ike_cfg, prop);
663 }
664 enumerator->destroy(enumerator);
665 }
666 else
667 {
668 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
669 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
670 }
671
672 peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
673 if (virtual)
674 {
675 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
676 peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
677 }
678 auth = auth_cfg_create();
679 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
680 auth->add(auth, AUTH_RULE_IDENTITY, user);
681 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
682 auth = auth_cfg_create();
683 if (auth_class == AUTH_CLASS_PSK)
684 {
685 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
686 }
687 else
688 {
689 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
690 }
691 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
692 auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
693 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
694
695 child_cfg = child_cfg_create(priv->name, &child);
696 str = nm_setting_vpn_get_data_item(vpn, "esp");
697 if (proposal && str && strlen(str))
698 {
699 enumerator = enumerator_create_token(str, ";", "");
700 while (enumerator->enumerate(enumerator, &str))
701 {
702 prop = proposal_create_from_string(PROTO_ESP, str);
703 if (!prop)
704 {
705 g_set_error(err, NM_VPN_PLUGIN_ERROR,
706 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
707 "Invalid ESP proposal.");
708 enumerator->destroy(enumerator);
709 child_cfg->destroy(child_cfg);
710 peer_cfg->destroy(peer_cfg);
711 return FALSE;
712 }
713 child_cfg->add_proposal(child_cfg, prop);
714 }
715 enumerator->destroy(enumerator);
716 }
717 else
718 {
719 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
720 child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
721 }
722 ts = traffic_selector_create_dynamic(0, 0, 65535);
723 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
724 ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
725 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
726 ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
727 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
728 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
729
730 /**
731 * Prepare IKE_SA
732 */
733 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
734 peer_cfg);
735 if (!ike_sa)
736 {
737 peer_cfg->destroy(peer_cfg);
738 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
739 "IKE version not supported.");
740 return FALSE;
741 }
742 if (!ike_sa->get_peer_cfg(ike_sa))
743 {
744 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
745 }
746 peer_cfg->destroy(peer_cfg);
747
748 /**
749 * Register listener, enable initiate-failure-detection hooks
750 */
751 priv->ike_sa = ike_sa;
752 priv->listener.ike_state_change = ike_state_change;
753 priv->listener.child_state_change = child_state_change;
754 charon->bus->add_listener(charon->bus, &priv->listener);
755
756 /**
757 * Initiate
758 */
759 child_cfg->get_ref(child_cfg);
760 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
761 {
762 charon->bus->remove_listener(charon->bus, &priv->listener);
763 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
764
765 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
766 "Initiating failed.");
767 return FALSE;
768 }
769 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
770 return TRUE;
771 }
772
773 /**
774 * NeedSecrets called from NM via DBUS
775 */
776 static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
777 const char **setting_name, GError **error)
778 {
779 NMSettingVpn *settings;
780 const char *method, *path;
781
782 settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
783 NM_TYPE_SETTING_VPN));
784 method = nm_setting_vpn_get_data_item(settings, "method");
785 if (method)
786 {
787 if (streq(method, "eap") || streq(method, "psk"))
788 {
789 if (nm_setting_vpn_get_secret(settings, "password"))
790 {
791 return FALSE;
792 }
793 }
794 else if (streq(method, "agent"))
795 {
796 if (nm_setting_vpn_get_secret(settings, "agent"))
797 {
798 return FALSE;
799 }
800 }
801 else if (streq(method, "key"))
802 {
803 path = nm_setting_vpn_get_data_item(settings, "userkey");
804 if (path)
805 {
806 private_key_t *key;
807
808 /* try to load/decrypt the private key */
809 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
810 KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
811 if (key)
812 {
813 key->destroy(key);
814 return FALSE;
815 }
816 else if (nm_setting_vpn_get_secret(settings, "password"))
817 {
818 return FALSE;
819 }
820 }
821 }
822 else if (streq(method, "smartcard"))
823 {
824 if (nm_setting_vpn_get_secret(settings, "password"))
825 {
826 return FALSE;
827 }
828 }
829 }
830 *setting_name = NM_SETTING_VPN_SETTING_NAME;
831 return TRUE;
832 }
833
834 /**
835 * The actual disconnection
836 */
837 static gboolean do_disconnect(gpointer plugin)
838 {
839 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
840 enumerator_t *enumerator;
841 ike_sa_t *ike_sa;
842 u_int id;
843
844 /* our ike_sa pointer might be invalid, lookup sa */
845 enumerator = charon->controller->create_ike_sa_enumerator(
846 charon->controller, TRUE);
847 while (enumerator->enumerate(enumerator, &ike_sa))
848 {
849 if (priv->ike_sa == ike_sa)
850 {
851 id = ike_sa->get_unique_id(ike_sa);
852 enumerator->destroy(enumerator);
853 charon->controller->terminate_ike(charon->controller, id, FALSE,
854 controller_cb_empty, NULL, 0);
855 return FALSE;
856 }
857 }
858 enumerator->destroy(enumerator);
859
860 g_debug("Connection not found.");
861 return FALSE;
862 }
863
864 /**
865 * Disconnect called from NM via DBUS
866 */
867 static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
868 {
869 /* enqueue the actual disconnection, because we may be called in
870 * response to a listener_t callback and the SA enumeration would
871 * possibly deadlock. */
872 g_idle_add(do_disconnect, plugin);
873
874 return TRUE;
875 }
876
877 /**
878 * Initializer
879 */
880 static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
881 {
882 NMStrongswanPluginPrivate *priv;
883
884 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
885 priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
886 memset(&priv->listener, 0, sizeof(listener_t));
887 priv->listener.child_updown = child_updown;
888 priv->listener.ike_rekey = ike_rekey;
889 priv->name = NULL;
890 }
891
892 /**
893 * Class constructor
894 */
895 static void nm_strongswan_plugin_class_init(
896 NMStrongswanPluginClass *strongswan_class)
897 {
898 NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
899
900 g_type_class_add_private(G_OBJECT_CLASS(strongswan_class),
901 sizeof(NMStrongswanPluginPrivate));
902 parent_class->connect = connect_;
903 parent_class->need_secrets = need_secrets;
904 parent_class->disconnect = disconnect;
905 }
906
907 /**
908 * Object constructor
909 */
910 NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
911 nm_handler_t *handler)
912 {
913 GError *error = NULL;
914
915 NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
916 NM_TYPE_STRONGSWAN_PLUGIN,
917 NULL,
918 &error,
919 NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
920 NULL);
921
922 if (plugin)
923 {
924 NMStrongswanPluginPrivate *priv;
925
926 /* the rest of the initialization happened in _init above */
927 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
928 priv->creds = creds;
929 priv->handler = handler;
930 }
931 else
932 {
933 g_warning ("Failed to initialize a plugin instance: %s", error->message);
934 g_error_free (error);
935 }
936
937 return plugin;
938 }