2 * Copyright (C) 2017 Lubomir Rintel
4 * Copyright (C) 2013-2019 Tobias Brunner
5 * Copyright (C) 2008-2009 Martin Willi
6 * HSR Hochschule fuer Technik Rapperswil
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>.
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
19 #include "nm_service.h"
22 #include <networking/host.h>
23 #include <utils/identification.h>
24 #include <config/peer_cfg.h>
25 #include <credentials/certificates/x509.h>
29 G_DEFINE_TYPE(NMStrongswanPlugin
, nm_strongswan_plugin
, NM_TYPE_VPN_SERVICE_PLUGIN
)
32 * Private data of NMStrongswanPlugin
35 /* implements bus listener interface */
37 /* IKE_SA we are listening on */
39 /* backref to public plugin */
40 NMVpnServicePlugin
*plugin
;
41 /* credentials to use for authentication */
43 /* attribute handler for DNS/NBNS server information */
44 nm_handler_t
*handler
;
45 /* name of the connection */
47 } NMStrongswanPluginPrivate
;
49 #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
50 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
51 NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
54 * Convert an address chunk to a GValue
56 static GVariant
*addr_to_variant(chunk_t addr
)
58 GVariantBuilder builder
;
64 return g_variant_new_uint32 (*(uint32_t*)addr
.ptr
);
66 g_variant_builder_init (&builder
, G_VARIANT_TYPE ("ay"));
67 for (i
= 0; i
< addr
.len
; i
++)
69 g_variant_builder_add (&builder
, "y", addr
.ptr
[i
]);
72 return g_variant_builder_end (&builder
);
79 * Convert a host to a GValue
81 static GVariant
*host_to_variant(host_t
*host
)
83 return addr_to_variant(host
->get_address(host
));
87 * Convert enumerated handler chunks to a GValue
89 static GVariant
* handler_to_variant(nm_handler_t
*handler
, char *variant_type
,
90 configuration_attribute_type_t type
)
92 GVariantBuilder builder
;
93 enumerator_t
*enumerator
;
96 g_variant_builder_init (&builder
, G_VARIANT_TYPE (variant_type
));
98 enumerator
= handler
->create_enumerator(handler
, type
);
99 while (enumerator
->enumerate(enumerator
, &chunk
))
101 g_variant_builder_add_value (&builder
, addr_to_variant(*chunk
));
103 enumerator
->destroy(enumerator
);
105 return g_variant_builder_end (&builder
);
109 * Signal IP config to NM, set connection as established
111 static void signal_ip_config(NMVpnServicePlugin
*plugin
,
112 ike_sa_t
*ike_sa
, child_sa_t
*child_sa
)
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
;
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
);
125 handler
= priv
->handler
;
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
));
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
))
136 switch (me
->get_family(me
))
152 enumerator
->destroy(enumerator
);
155 me
= ike_sa
->get_my_host(ike_sa
);
156 switch (me
->get_family(me
))
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));
174 /* prevent NM from changing the default route. we set our own route in our
177 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT
,
178 g_variant_new_boolean (TRUE
));
180 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS
,
181 handler_to_variant(handler
, "au", INTERNAL_IP4_DNS
));
183 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS
,
184 handler_to_variant(handler
, "au", INTERNAL_IP4_NBNS
));
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 */
200 ip4config
= g_variant_builder_end (&ip4builder
);
201 if (g_variant_n_children (ip4config
))
203 g_variant_builder_add (&builder
, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4
,
204 g_variant_new_boolean (TRUE
));
208 g_variant_unref (ip4config
);
212 ip6config
= g_variant_builder_end (&ip6builder
);
213 if (g_variant_n_children (ip6config
))
215 g_variant_builder_add (&builder
, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6
,
216 g_variant_new_boolean (TRUE
));
220 g_variant_unref (ip6config
);
224 handler
->reset(handler
);
226 nm_vpn_service_plugin_set_config (plugin
, g_variant_builder_end (&builder
));
229 nm_vpn_service_plugin_set_ip4_config (plugin
, ip4config
);
233 nm_vpn_service_plugin_set_ip6_config (plugin
, ip6config
);
238 * signal failure to NM, connecting failed
240 static void signal_failure(NMVpnServicePlugin
*plugin
, NMVpnPluginFailure failure
)
242 nm_handler_t
*handler
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
)->handler
;
244 handler
->reset(handler
);
246 nm_vpn_service_plugin_failure(plugin
, failure
);
250 * Implementation of listener_t.ike_state_change
252 static bool ike_state_change(listener_t
*listener
, ike_sa_t
*ike_sa
,
253 ike_sa_state_t state
)
255 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
257 if (private->ike_sa
== ike_sa
&& state
== IKE_DESTROYING
)
259 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED
);
266 * Implementation of listener_t.child_state_change
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
)
271 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
273 if (private->ike_sa
== ike_sa
&& state
== CHILD_DESTROYING
)
275 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
282 * Implementation of listener_t.child_updown
284 static bool child_updown(listener_t
*listener
, ike_sa_t
*ike_sa
,
285 child_sa_t
*child_sa
, bool up
)
287 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
289 if (private->ike_sa
== ike_sa
)
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
);
299 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
307 * Implementation of listener_t.ike_rekey
309 static bool ike_rekey(listener_t
*listener
, ike_sa_t
*old
, ike_sa_t
*new)
311 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
313 if (private->ike_sa
== old
)
314 { /* follow a rekeyed IKE_SA */
315 private->ike_sa
= new;
321 * Find a certificate for which we have a private key on a smartcard
323 static identification_t
*find_smartcard_key(NMStrongswanPluginPrivate
*priv
,
326 enumerator_t
*enumerator
, *sans
;
327 identification_t
*id
= NULL
;
333 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
334 CERT_X509
, KEY_ANY
, NULL
, FALSE
);
335 while (enumerator
->enumerate(enumerator
, &cert
))
337 x509
= (x509_t
*)cert
;
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
))
343 keyid
= x509
->get_subjectKeyIdentifier(x509
);
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
);
352 /* prefer a more convenient subjectAltName */
353 sans
= x509
->create_subjectAltName_enumerator(x509
);
354 if (!sans
->enumerate(sans
, &id
))
356 id
= cert
->get_subject(cert
);
361 DBG1(DBG_CFG
, "using smartcard certificate '%Y'", id
);
362 priv
->creds
->set_cert_and_key(priv
->creds
,
363 cert
->get_ref(cert
), key
);
369 enumerator
->destroy(enumerator
);
374 * Connect function called from NM via DBUS
376 static gboolean
connect_(NMVpnServicePlugin
*plugin
, NMConnection
*connection
,
379 NMStrongswanPluginPrivate
*priv
;
380 NMSettingConnection
*conn
;
382 enumerator_t
*enumerator
;
383 identification_t
*user
= NULL
, *gateway
= NULL
;
385 bool virtual, proposal
;
388 peer_cfg_t
*peer_cfg
;
389 child_cfg_t
*child_cfg
;
390 traffic_selector_t
*ts
;
393 auth_class_t auth_class
= AUTH_CLASS_EAP
;
394 certificate_t
*cert
= NULL
;
396 bool agent
= FALSE
, smartcard
= FALSE
, loose_gateway_id
= FALSE
;
397 ike_cfg_create_t ike
= {
400 .local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
),
401 .remote_port
= IKEV2_UDP_PORT
,
402 .fragmentation
= FRAGMENTATION_YES
,
404 peer_cfg_create_t peer
= {
405 .cert_policy
= CERT_SEND_IF_ASKED
,
406 .unique
= UNIQUE_REPLACE
,
408 .rekey_time
= 36000, /* 10h */
409 .jitter_time
= 600, /* 10min */
410 .over_time
= 600, /* 10min */
412 child_cfg_create_t child
= {
415 .life
= 10800 /* 3h */,
416 .rekey
= 10200 /* 2h50min */,
417 .jitter
= 300 /* 5min */
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
));
435 priv
->name
= strdup(nm_setting_connection_get_id(conn
));
436 DBG1(DBG_CFG
, "received initiate for NetworkManager connection %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
)
443 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
444 "Gateway address missing.");
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"))
456 auth_class
= AUTH_CLASS_PSK
;
458 else if (streq(str
, "agent"))
460 auth_class
= AUTH_CLASS_PUBKEY
;
463 else if (streq(str
, "key"))
465 auth_class
= AUTH_CLASS_PUBKEY
;
467 else if (streq(str
, "smartcard"))
469 auth_class
= AUTH_CLASS_PUBKEY
;
474 * Register credentials
476 priv
->creds
->clear(priv
->creds
);
478 /* gateway/CA cert */
479 str
= nm_setting_vpn_get_data_item(vpn
, "certificate");
482 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
483 BUILD_FROM_FILE
, str
, BUILD_END
);
486 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
487 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
488 "Loading gateway certificate failed.");
491 priv
->creds
->add_certificate(priv
->creds
, cert
);
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
);
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
));
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
;
518 if (auth_class
== AUTH_CLASS_EAP
||
519 auth_class
== AUTH_CLASS_PSK
)
521 /* username/password or PSK authentication ... */
522 str
= nm_setting_vpn_get_data_item(vpn
, "user");
525 user
= identification_create_from_string((char*)str
);
526 str
= nm_setting_vpn_get_secret(vpn
, "password");
527 if (auth_class
== AUTH_CLASS_PSK
&&
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
);
537 priv
->creds
->set_username_password(priv
->creds
, user
, (char*)str
);
541 if (auth_class
== AUTH_CLASS_PUBKEY
)
547 pin
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
550 user
= find_smartcard_key(priv
, pin
);
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
);
561 /* ... or certificate/private key authenitcation */
562 else if ((str
= nm_setting_vpn_get_data_item(vpn
, "usercert")))
564 public_key_t
*public;
565 private_key_t
*private = NULL
;
567 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
568 BUILD_FROM_FILE
, str
, BUILD_END
);
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
);
578 str
= nm_setting_vpn_get_secret(vpn
, "agent");
581 public = cert
->get_public_key(cert
);
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,
589 public->destroy(public);
593 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
594 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
595 "Connecting to SSH agent failed.");
598 /* ... or key file */
599 str
= nm_setting_vpn_get_data_item(vpn
, "userkey");
604 secret
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
607 priv
->creds
->set_key_password(priv
->creds
, secret
);
609 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
610 KEY_ANY
, BUILD_FROM_FILE
, str
, BUILD_END
);
613 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
614 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
615 "Loading private key failed.");
620 user
= cert
->get_subject(cert
);
621 user
= user
->clone(user
);
622 priv
->creds
->set_cert_and_key(priv
->creds
, cert
, private);
627 gateway
->destroy(gateway
);
635 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
636 "Configuration parameters missing.");
637 gateway
->destroy(gateway
);
642 * Set up configurations
644 ike_cfg
= ike_cfg_create(&ike
);
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
))
651 enumerator
= enumerator_create_token(str
, ";", "");
652 while (enumerator
->enumerate(enumerator
, &str
))
654 prop
= proposal_create_from_string(PROTO_IKE
, str
);
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
);
666 ike_cfg
->add_proposal(ike_cfg
, prop
);
668 enumerator
->destroy(enumerator
);
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
));
676 peer_cfg
= peer_cfg_create(priv
->name
, ike_cfg
, &peer
);
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
));
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
)
689 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
693 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
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
);
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
))
703 enumerator
= enumerator_create_token(str
, ";", "");
704 while (enumerator
->enumerate(enumerator
, &str
))
706 prop
= proposal_create_from_string(PROTO_ESP
, str
);
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
);
717 child_cfg
->add_proposal(child_cfg
, prop
);
719 enumerator
->destroy(enumerator
);
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
));
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
);
737 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(charon
->ike_sa_manager
,
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.");
746 if (!ike_sa
->get_peer_cfg(ike_sa
))
748 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
750 peer_cfg
->destroy(peer_cfg
);
753 * Register listener, enable initiate-failure-detection hooks
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
);
763 child_cfg
->get_ref(child_cfg
);
764 if (ike_sa
->initiate(ike_sa
, child_cfg
, 0, NULL
, NULL
) != SUCCESS
)
766 charon
->bus
->remove_listener(charon
->bus
, &priv
->listener
);
767 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
769 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
770 "Initiating failed.");
773 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
778 * NeedSecrets called from NM via DBUS
780 static gboolean
need_secrets(NMVpnServicePlugin
*plugin
, NMConnection
*connection
,
781 const char **setting_name
, GError
**error
)
783 NMSettingVpn
*settings
;
784 const char *method
, *path
;
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");
791 if (streq(method
, "eap") || streq(method
, "psk"))
793 if (nm_setting_vpn_get_secret(settings
, "password"))
798 else if (streq(method
, "agent"))
800 if (nm_setting_vpn_get_secret(settings
, "agent"))
805 else if (streq(method
, "key"))
807 path
= nm_setting_vpn_get_data_item(settings
, "userkey");
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
);
820 else if (nm_setting_vpn_get_secret(settings
, "password"))
826 else if (streq(method
, "smartcard"))
828 if (nm_setting_vpn_get_secret(settings
, "password"))
834 *setting_name
= NM_SETTING_VPN_SETTING_NAME
;
839 * The actual disconnection
841 static gboolean
do_disconnect(gpointer plugin
)
843 NMStrongswanPluginPrivate
*priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
844 enumerator_t
*enumerator
;
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
))
853 if (priv
->ike_sa
== ike_sa
)
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);
862 enumerator
->destroy(enumerator
);
864 g_debug("Connection not found.");
869 * Disconnect called from NM via DBUS
871 static gboolean
disconnect(NMVpnServicePlugin
*plugin
, GError
**err
)
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
);
884 static void nm_strongswan_plugin_init(NMStrongswanPlugin
*plugin
)
886 NMStrongswanPluginPrivate
*priv
;
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
;
899 static void nm_strongswan_plugin_class_init(
900 NMStrongswanPluginClass
*strongswan_class
)
902 NMVpnServicePluginClass
*parent_class
= NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class
);
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
;
914 NMStrongswanPlugin
*nm_strongswan_plugin_new(nm_creds_t
*creds
,
915 nm_handler_t
*handler
)
917 GError
*error
= NULL
;
919 NMStrongswanPlugin
*plugin
= (NMStrongswanPlugin
*)g_initable_new (
920 NM_TYPE_STRONGSWAN_PLUGIN
,
923 NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME
, NM_DBUS_SERVICE_STRONGSWAN
,
928 NMStrongswanPluginPrivate
*priv
;
930 /* the rest of the initialization happened in _init above */
931 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
933 priv
->handler
= handler
;
937 g_warning ("Failed to initialize a plugin instance: %s", error
->message
);
938 g_error_free (error
);