2 * Copyright (C) 2017 Lubomir Rintel
4 * Copyright (C) 2013-2020 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>
30 * Private data of NMStrongswanPlugin
33 /* implements bus listener interface */
35 /* IKE_SA we are listening on */
37 /* backref to public plugin */
38 NMVpnServicePlugin
*plugin
;
39 /* credentials to use for authentication */
41 /* attribute handler for DNS/NBNS server information */
42 nm_handler_t
*handler
;
43 /* name of the connection */
45 } NMStrongswanPluginPrivate
;
47 G_DEFINE_TYPE_WITH_PRIVATE(NMStrongswanPlugin
, nm_strongswan_plugin
, NM_TYPE_VPN_SERVICE_PLUGIN
)
49 #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
50 ((NMStrongswanPluginPrivate*) \
51 nm_strongswan_plugin_get_instance_private (o))
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 NMStrongswanPlugin
*pub
= (NMStrongswanPlugin
*)plugin
;
115 NMStrongswanPluginPrivate
*priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub
);
116 GVariantBuilder builder
, ip4builder
, ip6builder
;
117 GVariant
*ip4config
, *ip6config
;
118 enumerator_t
*enumerator
;
119 host_t
*me
, *other
, *vip4
= NULL
, *vip6
= NULL
;
120 nm_handler_t
*handler
;
122 g_variant_builder_init (&builder
, G_VARIANT_TYPE_VARDICT
);
123 g_variant_builder_init (&ip4builder
, G_VARIANT_TYPE_VARDICT
);
124 g_variant_builder_init (&ip6builder
, G_VARIANT_TYPE_VARDICT
);
126 handler
= priv
->handler
;
128 /* NM apparently requires to know the gateway */
129 other
= ike_sa
->get_other_host(ike_sa
);
130 g_variant_builder_add (&builder
, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY
,
131 host_to_variant(other
));
133 /* pass the first virtual IPs we got or use the physical IP */
134 enumerator
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, TRUE
);
135 while (enumerator
->enumerate(enumerator
, &me
))
137 switch (me
->get_family(me
))
153 enumerator
->destroy(enumerator
);
156 me
= ike_sa
->get_my_host(ike_sa
);
157 switch (me
->get_family(me
))
170 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS
,
171 host_to_variant(vip4
));
172 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX
,
173 g_variant_new_uint32 (vip4
->get_address(vip4
).len
* 8));
175 /* prevent NM from changing the default route. we set our own route in our
178 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT
,
179 g_variant_new_boolean (TRUE
));
181 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS
,
182 handler_to_variant(handler
, "au", INTERNAL_IP4_DNS
));
184 g_variant_builder_add (&ip4builder
, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS
,
185 handler_to_variant(handler
, "au", INTERNAL_IP4_NBNS
));
190 g_variant_builder_add (&ip6builder
, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS
,
191 host_to_variant(vip6
));
192 g_variant_builder_add (&ip6builder
, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX
,
193 g_variant_new_uint32 (vip6
->get_address(vip6
).len
* 8));
194 g_variant_builder_add (&ip6builder
, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT
,
195 g_variant_new_boolean (TRUE
));
196 g_variant_builder_add (&ip6builder
, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS
,
197 handler_to_variant(handler
, "aay", INTERNAL_IP6_DNS
));
198 /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
201 ip4config
= g_variant_builder_end (&ip4builder
);
202 if (g_variant_n_children (ip4config
))
204 g_variant_builder_add (&builder
, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4
,
205 g_variant_new_boolean (TRUE
));
209 g_variant_unref (ip4config
);
213 ip6config
= g_variant_builder_end (&ip6builder
);
214 if (g_variant_n_children (ip6config
))
216 g_variant_builder_add (&builder
, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6
,
217 g_variant_new_boolean (TRUE
));
221 g_variant_unref (ip6config
);
225 handler
->reset(handler
);
227 nm_vpn_service_plugin_set_config (plugin
, g_variant_builder_end (&builder
));
230 nm_vpn_service_plugin_set_ip4_config (plugin
, ip4config
);
234 nm_vpn_service_plugin_set_ip6_config (plugin
, ip6config
);
239 * signal failure to NM, connecting failed
241 static void signal_failure(NMVpnServicePlugin
*plugin
, NMVpnPluginFailure failure
)
243 NMStrongswanPlugin
*pub
= (NMStrongswanPlugin
*)plugin
;
244 nm_handler_t
*handler
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub
)->handler
;
246 handler
->reset(handler
);
248 nm_vpn_service_plugin_failure(plugin
, failure
);
251 METHOD(listener_t
, ike_state_change
, bool,
252 NMStrongswanPluginPrivate
*this, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
254 if (this->ike_sa
== ike_sa
&& state
== IKE_DESTROYING
)
256 signal_failure(this->plugin
, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED
);
261 METHOD(listener_t
, child_state_change
, bool,
262 NMStrongswanPluginPrivate
*this, ike_sa_t
*ike_sa
, child_sa_t
*child_sa
,
263 child_sa_state_t state
)
265 if (this->ike_sa
== ike_sa
&& state
== CHILD_DESTROYING
)
267 signal_failure(this->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
272 METHOD(listener_t
, ike_rekey
, bool,
273 NMStrongswanPluginPrivate
*this, ike_sa_t
*old
, ike_sa_t
*new)
275 if (this->ike_sa
== old
)
276 { /* follow a rekeyed IKE_SA */
282 METHOD(listener_t
, ike_reestablish_pre
, bool,
283 NMStrongswanPluginPrivate
*this, ike_sa_t
*old
, ike_sa_t
*new)
285 if (this->ike_sa
== old
)
286 { /* ignore child state changes during redirects etc. (task migration) */
287 this->listener
.child_state_change
= NULL
;
292 METHOD(listener_t
, ike_reestablish_post
, bool,
293 NMStrongswanPluginPrivate
*this, ike_sa_t
*old
, ike_sa_t
*new,
296 if (this->ike_sa
== old
&& initiated
)
297 { /* if we get redirected during IKE_AUTH we just migrate to the new SA */
299 /* re-register hooks to detect initiation failures */
300 this->listener
.ike_state_change
= _ike_state_change
;
301 this->listener
.child_state_change
= _child_state_change
;
306 METHOD(listener_t
, child_updown
, bool,
307 NMStrongswanPluginPrivate
*this, ike_sa_t
*ike_sa
, child_sa_t
*child_sa
,
310 if (this->ike_sa
== ike_sa
)
313 { /* disable initiate-failure-detection hooks */
314 this->listener
.ike_state_change
= NULL
;
315 this->listener
.child_state_change
= NULL
;
316 signal_ip_config(this->plugin
, ike_sa
, child_sa
);
320 if (ike_sa
->has_condition(ike_sa
, COND_REAUTHENTICATING
))
321 { /* we ignore this during reauthentication */
324 signal_failure(this->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
331 * Find a certificate for which we have a private key on a smartcard
333 static identification_t
*find_smartcard_key(NMStrongswanPluginPrivate
*priv
,
336 enumerator_t
*enumerator
, *sans
;
337 identification_t
*id
= NULL
;
343 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
344 CERT_X509
, KEY_ANY
, NULL
, FALSE
);
345 while (enumerator
->enumerate(enumerator
, &cert
))
347 x509
= (x509_t
*)cert
;
349 /* there might be a lot of certificates, filter them by usage */
350 if ((x509
->get_flags(x509
) & X509_CLIENT_AUTH
) &&
351 !(x509
->get_flags(x509
) & X509_CA
))
353 keyid
= x509
->get_subjectKeyIdentifier(x509
);
356 /* try to find a private key by the certificate keyid */
357 priv
->creds
->set_pin(priv
->creds
, keyid
, pin
);
358 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
359 KEY_ANY
, BUILD_PKCS11_KEYID
, keyid
, BUILD_END
);
362 /* prefer a more convenient subjectAltName */
363 sans
= x509
->create_subjectAltName_enumerator(x509
);
364 if (!sans
->enumerate(sans
, &id
))
366 id
= cert
->get_subject(cert
);
371 DBG1(DBG_CFG
, "using smartcard certificate '%Y'", id
);
372 priv
->creds
->set_cert_and_key(priv
->creds
,
373 cert
->get_ref(cert
), key
);
379 enumerator
->destroy(enumerator
);
384 * Add a client auth config for certificate authentication
386 static bool add_auth_cfg_cert(NMStrongswanPluginPrivate
*priv
,
387 NMSettingVpn
*vpn
, peer_cfg_t
*peer_cfg
,
390 identification_t
*id
= NULL
;
391 certificate_t
*cert
= NULL
;
393 const char *str
, *method
, *cert_source
;
395 method
= nm_setting_vpn_get_data_item(vpn
, "method");
396 cert_source
= nm_setting_vpn_get_data_item(vpn
, "cert-source") ?: method
;
398 if (streq(cert_source
, "smartcard"))
402 pin
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
405 id
= find_smartcard_key(priv
, pin
);
409 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
410 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
411 "No usable smartcard certificate found.");
415 /* ... or certificate/private key authentication */
416 else if ((str
= nm_setting_vpn_get_data_item(vpn
, "usercert")))
418 public_key_t
*public;
419 private_key_t
*private = NULL
;
421 bool agent
= streq(cert_source
, "agent");
423 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
424 BUILD_FROM_FILE
, str
, BUILD_END
);
427 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
428 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
429 "Loading peer certificate failed.");
433 str
= nm_setting_vpn_get_secret(vpn
, "agent");
436 public = cert
->get_public_key(cert
);
439 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
440 public->get_type(public),
441 BUILD_AGENT_SOCKET
, str
,
442 BUILD_PUBLIC_KEY
, public,
444 public->destroy(public);
448 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
449 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
450 "Connecting to SSH agent failed.");
453 /* ... or key file */
454 str
= nm_setting_vpn_get_data_item(vpn
, "userkey");
459 secret
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
462 priv
->creds
->set_key_password(priv
->creds
, secret
);
464 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
465 KEY_ANY
, BUILD_FROM_FILE
, str
, BUILD_END
);
468 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
469 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
470 "Loading private key failed.");
475 id
= cert
->get_subject(cert
);
477 priv
->creds
->set_cert_and_key(priv
->creds
, cert
, private);
487 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
488 "Certificate is missing.");
492 auth
= auth_cfg_create();
493 if (streq(method
, "eap-tls"))
495 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
496 auth
->add(auth
, AUTH_RULE_EAP_TYPE
, EAP_TLS
);
497 auth
->add(auth
, AUTH_RULE_AAA_IDENTITY
,
498 identification_create_from_string("%any"));
502 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
506 auth
->add(auth
, AUTH_RULE_SUBJECT_CERT
, cert
->get_ref(cert
));
508 str
= nm_setting_vpn_get_data_item(vpn
, "local-identity");
511 identification_t
*local_id
;
513 local_id
= identification_create_from_string((char*)str
);
520 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
521 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, TRUE
);
526 * Add a client auth config for username/password authentication
528 static bool add_auth_cfg_pw(NMStrongswanPluginPrivate
*priv
,
529 NMSettingVpn
*vpn
, peer_cfg_t
*peer_cfg
,
532 identification_t
*user
= NULL
, *id
= NULL
;
534 const char *str
, *method
;
536 method
= nm_setting_vpn_get_data_item(vpn
, "method");
538 str
= nm_setting_vpn_get_data_item(vpn
, "user");
541 user
= identification_create_from_string((char*)str
);
545 user
= identification_create_from_string("%any");
547 str
= nm_setting_vpn_get_data_item(vpn
, "local-identity");
550 id
= identification_create_from_string((char*)str
);
554 id
= user
->clone(user
);
556 str
= nm_setting_vpn_get_secret(vpn
, "password");
557 if (streq(method
, "psk"))
559 if (strlen(str
) < 20)
561 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
562 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
563 "Pre-shared key is too short.");
568 priv
->creds
->set_username_password(priv
->creds
, id
, (char*)str
);
572 priv
->creds
->set_username_password(priv
->creds
, user
, (char*)str
);
575 auth
= auth_cfg_create();
576 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
,
577 streq(method
, "psk") ? AUTH_CLASS_PSK
: AUTH_CLASS_EAP
);
578 /* in case EAP-PEAP or EAP-TTLS is used we currently accept any identity */
579 auth
->add(auth
, AUTH_RULE_AAA_IDENTITY
,
580 identification_create_from_string("%any"));
581 auth
->add(auth
, AUTH_RULE_EAP_IDENTITY
, user
);
582 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
583 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, TRUE
);
588 * Connect function called from NM via DBUS
590 static gboolean
connect_(NMVpnServicePlugin
*plugin
, NMConnection
*connection
,
593 NMStrongswanPlugin
*pub
= (NMStrongswanPlugin
*)plugin
;
594 NMStrongswanPluginPrivate
*priv
;
595 NMSettingConnection
*conn
;
597 enumerator_t
*enumerator
;
598 identification_t
*gateway
= NULL
;
599 const char *str
, *method
;
600 bool virtual, proposal
;
603 peer_cfg_t
*peer_cfg
;
604 child_cfg_t
*child_cfg
;
605 traffic_selector_t
*ts
;
608 auth_class_t auth_class
= AUTH_CLASS_EAP
;
609 certificate_t
*cert
= NULL
;
611 bool loose_gateway_id
= FALSE
;
612 ike_cfg_create_t ike
= {
615 .local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
),
616 .remote_port
= IKEV2_UDP_PORT
,
617 .fragmentation
= FRAGMENTATION_YES
,
619 peer_cfg_create_t peer
= {
620 .cert_policy
= CERT_SEND_IF_ASKED
,
621 .unique
= UNIQUE_REPLACE
,
623 .rekey_time
= 36000, /* 10h */
624 .jitter_time
= 600, /* 10min */
625 .over_time
= 600, /* 10min */
627 child_cfg_create_t child
= {
630 .life
= 10800 /* 3h */,
631 .rekey
= 10200 /* 2h50min */,
632 .jitter
= 300 /* 5min */
641 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub
);
642 conn
= NM_SETTING_CONNECTION(nm_connection_get_setting(connection
,
643 NM_TYPE_SETTING_CONNECTION
));
644 vpn
= NM_SETTING_VPN(nm_connection_get_setting(connection
,
645 NM_TYPE_SETTING_VPN
));
650 priv
->name
= strdup(nm_setting_connection_get_id(conn
));
651 DBG1(DBG_CFG
, "received initiate for NetworkManager connection %s",
654 nm_setting_to_string(NM_SETTING(vpn
)));
655 ike
.remote
= (char*)nm_setting_vpn_get_data_item(vpn
, "address");
656 if (!ike
.remote
|| !*ike
.remote
)
658 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
659 "Gateway address missing.");
662 str
= nm_setting_vpn_get_data_item(vpn
, "server-port");
663 if (str
&& strlen(str
))
665 ike
.remote_port
= settings_value_as_int((char*)str
, ike
.remote_port
);
667 str
= nm_setting_vpn_get_data_item(vpn
, "virtual");
668 virtual = streq(str
, "yes");
669 str
= nm_setting_vpn_get_data_item(vpn
, "encap");
670 ike
.force_encap
= streq(str
, "yes");
671 str
= nm_setting_vpn_get_data_item(vpn
, "ipcomp");
672 child
.options
|= streq(str
, "yes") ? OPT_IPCOMP
: 0;
675 * Register credentials
677 priv
->creds
->clear(priv
->creds
);
679 /* gateway/CA cert */
680 str
= nm_setting_vpn_get_data_item(vpn
, "certificate");
683 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
684 BUILD_FROM_FILE
, str
, BUILD_END
);
687 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
688 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
689 "Loading gateway certificate failed.");
692 priv
->creds
->add_certificate(priv
->creds
, cert
);
696 /* no certificate defined, fall back to system-wide CA certificates */
697 priv
->creds
->load_ca_dir(priv
->creds
, lib
->settings
->get_str(
698 lib
->settings
, "charon-nm.ca_dir", NM_CA_DIR
));
701 str
= nm_setting_vpn_get_data_item(vpn
, "remote-identity");
704 gateway
= identification_create_from_string((char*)str
);
708 x509
= (x509_t
*)cert
;
709 if (!(x509
->get_flags(x509
) & X509_CA
))
710 { /* for server certificates, we use the subject as identity */
711 gateway
= cert
->get_subject(cert
);
712 gateway
= gateway
->clone(gateway
);
715 if (!gateway
|| gateway
->get_type(gateway
) == ID_ANY
)
717 /* if the user configured a CA certificate (or an invalid identity),
718 * we use the IP/hostname of the server */
719 gateway
= identification_create_from_string(ike
.remote
);
720 loose_gateway_id
= TRUE
;
722 DBG1(DBG_CFG
, "using gateway identity '%Y'", gateway
);
725 * Set up configurations
727 ike_cfg
= ike_cfg_create(&ike
);
729 str
= nm_setting_vpn_get_data_item(vpn
, "proposal");
730 proposal
= streq(str
, "yes");
731 str
= nm_setting_vpn_get_data_item(vpn
, "ike");
732 if (proposal
&& str
&& strlen(str
))
734 enumerator
= enumerator_create_token(str
, ";", "");
735 while (enumerator
->enumerate(enumerator
, &str
))
737 prop
= proposal_create_from_string(PROTO_IKE
, str
);
740 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
741 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
742 "Invalid IKE proposal.");
743 enumerator
->destroy(enumerator
);
744 ike_cfg
->destroy(ike_cfg
);
745 gateway
->destroy(gateway
);
748 ike_cfg
->add_proposal(ike_cfg
, prop
);
750 enumerator
->destroy(enumerator
);
754 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
755 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default_aead(PROTO_IKE
));
758 peer_cfg
= peer_cfg_create(priv
->name
, ike_cfg
, &peer
);
761 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_any(AF_INET
));
762 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_any(AF_INET6
));
765 method
= nm_setting_vpn_get_data_item(vpn
, "method");
766 if (streq(method
, "cert") ||
767 streq(method
, "eap-tls") ||
768 streq(method
, "key") ||
769 streq(method
, "agent") ||
770 streq(method
, "smartcard"))
772 if (!add_auth_cfg_cert (priv
, vpn
, peer_cfg
, err
))
774 peer_cfg
->destroy(peer_cfg
);
775 ike_cfg
->destroy(ike_cfg
);
776 gateway
->destroy(gateway
);
780 else if (streq(method
, "eap") ||
781 streq(method
, "psk"))
783 if (!add_auth_cfg_pw(priv
, vpn
, peer_cfg
, err
))
785 peer_cfg
->destroy(peer_cfg
);
786 ike_cfg
->destroy(ike_cfg
);
787 gateway
->destroy(gateway
);
793 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
794 "Configuration parameters missing.");
795 peer_cfg
->destroy(peer_cfg
);
796 ike_cfg
->destroy(ike_cfg
);
797 gateway
->destroy(gateway
);
801 auth
= auth_cfg_create();
802 if (auth_class
== AUTH_CLASS_PSK
)
804 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
808 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
810 auth
->add(auth
, AUTH_RULE_IDENTITY
, gateway
);
811 auth
->add(auth
, AUTH_RULE_IDENTITY_LOOSE
, loose_gateway_id
);
812 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, FALSE
);
814 child_cfg
= child_cfg_create(priv
->name
, &child
);
815 str
= nm_setting_vpn_get_data_item(vpn
, "esp");
816 if (proposal
&& str
&& strlen(str
))
818 enumerator
= enumerator_create_token(str
, ";", "");
819 while (enumerator
->enumerate(enumerator
, &str
))
821 prop
= proposal_create_from_string(PROTO_ESP
, str
);
824 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
825 NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
826 "Invalid ESP proposal.");
827 enumerator
->destroy(enumerator
);
828 child_cfg
->destroy(child_cfg
);
829 peer_cfg
->destroy(peer_cfg
);
832 child_cfg
->add_proposal(child_cfg
, prop
);
834 enumerator
->destroy(enumerator
);
838 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
839 child_cfg
->add_proposal(child_cfg
, proposal_create_default_aead(PROTO_ESP
));
841 ts
= traffic_selector_create_dynamic(0, 0, 65535);
842 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
843 ts
= traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
844 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
845 ts
= traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
846 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
847 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
852 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(charon
->ike_sa_manager
,
856 peer_cfg
->destroy(peer_cfg
);
857 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
858 "IKE version not supported.");
861 if (!ike_sa
->get_peer_cfg(ike_sa
))
863 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
865 peer_cfg
->destroy(peer_cfg
);
868 * Register listener, enable initiate-failure-detection hooks
870 priv
->ike_sa
= ike_sa
;
871 priv
->listener
.ike_state_change
= _ike_state_change
;
872 priv
->listener
.child_state_change
= _child_state_change
;
877 child_cfg
->get_ref(child_cfg
);
878 if (ike_sa
->initiate(ike_sa
, child_cfg
, 0, NULL
, NULL
) != SUCCESS
)
880 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
882 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
883 "Initiating failed.");
886 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
891 * NeedSecrets called from NM via DBUS
893 static gboolean
need_secrets(NMVpnServicePlugin
*plugin
, NMConnection
*connection
,
894 const char **setting_name
, GError
**error
)
896 NMSettingVpn
*settings
;
897 const char *method
, *cert_source
, *path
;
898 bool need_secret
= FALSE
;
900 settings
= NM_SETTING_VPN(nm_connection_get_setting(connection
,
901 NM_TYPE_SETTING_VPN
));
902 method
= nm_setting_vpn_get_data_item(settings
, "method");
905 if (streq(method
, "cert") ||
906 streq(method
, "eap-tls") ||
907 streq(method
, "key") ||
908 streq(method
, "agent") ||
909 streq(method
, "smartcard"))
911 cert_source
= nm_setting_vpn_get_data_item(settings
, "cert-source");
914 cert_source
= method
;
916 if (streq(cert_source
, "agent"))
918 need_secret
= !nm_setting_vpn_get_secret(settings
, "agent");
920 else if (streq(cert_source
, "smartcard"))
922 need_secret
= !nm_setting_vpn_get_secret(settings
, "password");
927 path
= nm_setting_vpn_get_data_item(settings
, "userkey");
932 /* try to load/decrypt the private key */
933 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
934 KEY_ANY
, BUILD_FROM_FILE
, path
, BUILD_END
);
940 else if (nm_setting_vpn_get_secret(settings
, "password"))
947 else if (streq(method
, "eap") ||
948 streq(method
, "psk"))
950 need_secret
= !nm_setting_vpn_get_secret(settings
, "password");
953 *setting_name
= NM_SETTING_VPN_SETTING_NAME
;
958 * The actual disconnection
960 static gboolean
do_disconnect(gpointer plugin
)
962 NMStrongswanPluginPrivate
*priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
963 enumerator_t
*enumerator
;
967 /* our ike_sa pointer might be invalid, lookup sa */
968 enumerator
= charon
->controller
->create_ike_sa_enumerator(
969 charon
->controller
, TRUE
);
970 while (enumerator
->enumerate(enumerator
, &ike_sa
))
972 if (priv
->ike_sa
== ike_sa
)
974 id
= ike_sa
->get_unique_id(ike_sa
);
975 enumerator
->destroy(enumerator
);
976 charon
->controller
->terminate_ike(charon
->controller
, id
, FALSE
,
977 controller_cb_empty
, NULL
, 0);
981 enumerator
->destroy(enumerator
);
983 g_debug("Connection not found.");
988 * Disconnect called from NM via DBUS
990 static gboolean
disconnect(NMVpnServicePlugin
*plugin
, GError
**err
)
992 /* enqueue the actual disconnection, because we may be called in
993 * response to a listener_t callback and the SA enumeration would
994 * possibly deadlock. */
995 g_idle_add(do_disconnect
, plugin
);
1003 static void nm_strongswan_plugin_init(NMStrongswanPlugin
*plugin
)
1005 NMStrongswanPluginPrivate
*priv
;
1007 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
1008 priv
->plugin
= NM_VPN_SERVICE_PLUGIN(plugin
);
1009 memset(&priv
->listener
, 0, sizeof(listener_t
));
1010 priv
->listener
.child_updown
= _child_updown
;
1011 priv
->listener
.ike_rekey
= _ike_rekey
;
1012 priv
->listener
.ike_reestablish_pre
= _ike_reestablish_pre
;
1013 priv
->listener
.ike_reestablish_post
= _ike_reestablish_post
;
1014 charon
->bus
->add_listener(charon
->bus
, &priv
->listener
);
1021 static void nm_strongswan_plugin_class_init(
1022 NMStrongswanPluginClass
*strongswan_class
)
1024 NMVpnServicePluginClass
*parent_class
= NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class
);
1026 parent_class
->connect
= connect_
;
1027 parent_class
->need_secrets
= need_secrets
;
1028 parent_class
->disconnect
= disconnect
;
1032 * Object constructor
1034 NMStrongswanPlugin
*nm_strongswan_plugin_new(nm_creds_t
*creds
,
1035 nm_handler_t
*handler
)
1037 GError
*error
= NULL
;
1039 NMStrongswanPlugin
*plugin
= (NMStrongswanPlugin
*)g_initable_new (
1040 NM_TYPE_STRONGSWAN_PLUGIN
,
1043 NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME
, NM_DBUS_SERVICE_STRONGSWAN
,
1048 NMStrongswanPluginPrivate
*priv
;
1050 /* the rest of the initialization happened in _init above */
1051 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
1052 priv
->creds
= creds
;
1053 priv
->handler
= handler
;
1057 g_warning ("Failed to initialize a plugin instance: %s", error
->message
);
1058 g_error_free (error
);