charon-nm: Prevent NM from changing the default route
[strongswan.git] / src / charon-nm / nm / nm_service.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2008-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <nm-setting-vpn.h>
18 #include <nm-setting-connection.h>
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 #include <networking/tun_device.h>
27
28 #include <stdio.h>
29
30 G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_PLUGIN)
31
32 /**
33 * Private data of NMStrongswanPlugin
34 */
35 typedef struct {
36 /* implements bus listener interface */
37 listener_t listener;
38 /* IKE_SA we are listening on */
39 ike_sa_t *ike_sa;
40 /* backref to public plugin */
41 NMVPNPlugin *plugin;
42 /* credentials to use for authentication */
43 nm_creds_t *creds;
44 /* attribute handler for DNS/NBNS server information */
45 nm_handler_t *handler;
46 /* dummy TUN device */
47 tun_device_t *tun;
48 /* name of the connection */
49 char *name;
50 } NMStrongswanPluginPrivate;
51
52 #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
53 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
54 NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
55
56 /**
57 * convert enumerated handler chunks to a UINT_ARRAY GValue
58 */
59 static GValue* handler_to_val(nm_handler_t *handler,
60 configuration_attribute_type_t type)
61 {
62 GValue *val;
63 GArray *array;
64 enumerator_t *enumerator;
65 chunk_t chunk;
66
67 enumerator = handler->create_enumerator(handler, type);
68 array = g_array_new (FALSE, TRUE, sizeof (guint32));
69 while (enumerator->enumerate(enumerator, &chunk))
70 {
71 g_array_append_val (array, *(u_int32_t*)chunk.ptr);
72 }
73 enumerator->destroy(enumerator);
74 val = g_slice_new0 (GValue);
75 g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
76 g_value_set_boxed (val, array);
77
78 return val;
79 }
80
81 /**
82 * signal IPv4 config to NM, set connection as established
83 */
84 static void signal_ipv4_config(NMVPNPlugin *plugin,
85 ike_sa_t *ike_sa, child_sa_t *child_sa)
86 {
87 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
88 GValue *val;
89 GHashTable *config;
90 enumerator_t *enumerator;
91 host_t *me;
92 nm_handler_t *handler;
93
94 config = g_hash_table_new(g_str_hash, g_str_equal);
95 handler = priv->handler;
96
97 /* NM requires a tundev, but netkey does not use one. Passing the physical
98 * interface does not work, as NM fiddles around with it. So we pass a dummy
99 * TUN device along for NM to play with... */
100 val = g_slice_new0 (GValue);
101 g_value_init (val, G_TYPE_STRING);
102 g_value_set_string (val, priv->tun->get_name(priv->tun));
103 g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, val);
104
105 /* NM installs this IP address on the interface above, so we use the VIP if
106 * we got one.
107 */
108 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
109 if (!enumerator->enumerate(enumerator, &me))
110 {
111 me = ike_sa->get_my_host(ike_sa);
112 }
113 enumerator->destroy(enumerator);
114 val = g_slice_new0(GValue);
115 g_value_init(val, G_TYPE_UINT);
116 g_value_set_uint(val, *(u_int32_t*)me->get_address(me).ptr);
117 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val);
118
119 val = g_slice_new0(GValue);
120 g_value_init(val, G_TYPE_UINT);
121 g_value_set_uint(val, me->get_address(me).len * 8);
122 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val);
123
124 /* prevent NM from changing the default route. we set our own route in our
125 * own routing table
126 */
127 val = g_slice_new0(GValue);
128 g_value_init(val, G_TYPE_BOOLEAN);
129 g_value_set_boolean(val, TRUE);
130 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, val);
131
132 val = handler_to_val(handler, INTERNAL_IP4_DNS);
133 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
134
135 val = handler_to_val(handler, INTERNAL_IP4_NBNS);
136 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val);
137
138 handler->reset(handler);
139
140 nm_vpn_plugin_set_ip4_config(plugin, config);
141 }
142
143 /**
144 * signal failure to NM, connecting failed
145 */
146 static void signal_failure(NMVPNPlugin *plugin, NMVPNPluginFailure failure)
147 {
148 nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
149
150 handler->reset(handler);
151
152 /* TODO: NM does not handle this failure!? */
153 nm_vpn_plugin_failure(plugin, failure);
154 nm_vpn_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STOPPED);
155 }
156
157 /**
158 * Implementation of listener_t.ike_state_change
159 */
160 static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa,
161 ike_sa_state_t state)
162 {
163 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
164
165 if (private->ike_sa == ike_sa && state == IKE_DESTROYING)
166 {
167 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
168 return FALSE;
169 }
170 return TRUE;
171 }
172
173 /**
174 * Implementation of listener_t.child_state_change
175 */
176 static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa,
177 child_sa_t *child_sa, child_sa_state_t state)
178 {
179 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
180
181 if (private->ike_sa == ike_sa && state == CHILD_DESTROYING)
182 {
183 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
184 return FALSE;
185 }
186 return TRUE;
187 }
188
189 /**
190 * Implementation of listener_t.child_updown
191 */
192 static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
193 child_sa_t *child_sa, bool up)
194 {
195 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
196
197 if (private->ike_sa == ike_sa)
198 {
199 if (up)
200 { /* disable initiate-failure-detection hooks */
201 private->listener.ike_state_change = NULL;
202 private->listener.child_state_change = NULL;
203 signal_ipv4_config(private->plugin, ike_sa, child_sa);
204 }
205 else
206 {
207 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
208 return FALSE;
209 }
210 }
211 return TRUE;
212 }
213
214 /**
215 * Implementation of listener_t.ike_rekey
216 */
217 static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
218 {
219 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
220
221 if (private->ike_sa == old)
222 { /* follow a rekeyed IKE_SA */
223 private->ike_sa = new;
224 }
225 return TRUE;
226 }
227
228 /**
229 * Find a certificate for which we have a private key on a smartcard
230 */
231 static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
232 char *pin)
233 {
234 enumerator_t *enumerator, *sans;
235 identification_t *id = NULL;
236 certificate_t *cert;
237 x509_t *x509;
238 private_key_t *key;
239 chunk_t keyid;
240
241 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
242 CERT_X509, KEY_ANY, NULL, FALSE);
243 while (enumerator->enumerate(enumerator, &cert))
244 {
245 x509 = (x509_t*)cert;
246
247 /* there might be a lot of certificates, filter them by usage */
248 if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
249 !(x509->get_flags(x509) & X509_CA))
250 {
251 keyid = x509->get_subjectKeyIdentifier(x509);
252 if (keyid.ptr)
253 {
254 /* try to find a private key by the certificate keyid */
255 priv->creds->set_pin(priv->creds, keyid, pin);
256 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
257 KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
258 if (key)
259 {
260 /* prefer a more convenient subjectAltName */
261 sans = x509->create_subjectAltName_enumerator(x509);
262 if (!sans->enumerate(sans, &id))
263 {
264 id = cert->get_subject(cert);
265 }
266 id = id->clone(id);
267 sans->destroy(sans);
268
269 DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
270 priv->creds->set_cert_and_key(priv->creds,
271 cert->get_ref(cert), key);
272 break;
273 }
274 }
275 }
276 }
277 enumerator->destroy(enumerator);
278 return id;
279 }
280
281 /**
282 * Connect function called from NM via DBUS
283 */
284 static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
285 GError **err)
286 {
287 NMStrongswanPluginPrivate *priv;
288 NMSettingConnection *conn;
289 NMSettingVPN *vpn;
290 identification_t *user = NULL, *gateway = NULL;
291 const char *address, *str;
292 bool virtual, encap, ipcomp;
293 ike_cfg_t *ike_cfg;
294 peer_cfg_t *peer_cfg;
295 child_cfg_t *child_cfg;
296 traffic_selector_t *ts;
297 ike_sa_t *ike_sa;
298 auth_cfg_t *auth;
299 auth_class_t auth_class = AUTH_CLASS_EAP;
300 certificate_t *cert = NULL;
301 x509_t *x509;
302 bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE;
303 lifetime_cfg_t lifetime = {
304 .time = {
305 .life = 10800 /* 3h */,
306 .rekey = 10200 /* 2h50min */,
307 .jitter = 300 /* 5min */
308 }
309 };
310
311 /**
312 * Read parameters
313 */
314 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
315 conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
316 NM_TYPE_SETTING_CONNECTION));
317 vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
318 NM_TYPE_SETTING_VPN));
319 if (priv->name)
320 {
321 free(priv->name);
322 }
323 priv->name = strdup(nm_setting_connection_get_id(conn));
324 DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
325 priv->name);
326 DBG4(DBG_CFG, "%s",
327 nm_setting_to_string(NM_SETTING(vpn)));
328 if (!priv->tun)
329 {
330 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
331 "Failed to create dummy TUN device.");
332 gateway->destroy(gateway);
333 return FALSE;
334 }
335 address = nm_setting_vpn_get_data_item(vpn, "address");
336 if (!address || !*address)
337 {
338 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
339 "Gateway address missing.");
340 return FALSE;
341 }
342 str = nm_setting_vpn_get_data_item(vpn, "virtual");
343 virtual = str && streq(str, "yes");
344 str = nm_setting_vpn_get_data_item(vpn, "encap");
345 encap = str && streq(str, "yes");
346 str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
347 ipcomp = str && streq(str, "yes");
348 str = nm_setting_vpn_get_data_item(vpn, "method");
349 if (str)
350 {
351 if (streq(str, "psk"))
352 {
353 auth_class = AUTH_CLASS_PSK;
354 }
355 else if (streq(str, "agent"))
356 {
357 auth_class = AUTH_CLASS_PUBKEY;
358 agent = TRUE;
359 }
360 else if (streq(str, "key"))
361 {
362 auth_class = AUTH_CLASS_PUBKEY;
363 }
364 else if (streq(str, "smartcard"))
365 {
366 auth_class = AUTH_CLASS_PUBKEY;
367 smartcard = TRUE;
368 }
369 }
370
371 /**
372 * Register credentials
373 */
374 priv->creds->clear(priv->creds);
375
376 /* gateway/CA cert */
377 str = nm_setting_vpn_get_data_item(vpn, "certificate");
378 if (str)
379 {
380 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
381 BUILD_FROM_FILE, str, BUILD_END);
382 if (!cert)
383 {
384 g_set_error(err, NM_VPN_PLUGIN_ERROR,
385 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
386 "Loading gateway certificate failed.");
387 return FALSE;
388 }
389 priv->creds->add_certificate(priv->creds, cert);
390
391 x509 = (x509_t*)cert;
392 if (!(x509->get_flags(x509) & X509_CA))
393 { /* For a gateway certificate, we use the cert subject as identity. */
394 gateway = cert->get_subject(cert);
395 gateway = gateway->clone(gateway);
396 DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway);
397 }
398 }
399 else
400 {
401 /* no certificate defined, fall back to system-wide CA certificates */
402 priv->creds->load_ca_dir(priv->creds, NM_CA_DIR);
403 }
404 if (!gateway)
405 {
406 /* If the user configured a CA certificate, we use the IP/DNS
407 * of the gateway as its identity. This identity will be used for
408 * certificate lookup and requires the configured IP/DNS to be
409 * included in the gateway certificate. */
410 gateway = identification_create_from_string((char*)address);
411 DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
412 loose_gateway_id = TRUE;
413 }
414
415 if (auth_class == AUTH_CLASS_EAP)
416 {
417 /* username/password authentication ... */
418 str = nm_setting_vpn_get_data_item(vpn, "user");
419 if (str)
420 {
421 user = identification_create_from_string((char*)str);
422 str = nm_setting_vpn_get_secret(vpn, "password");
423 priv->creds->set_username_password(priv->creds, user, (char*)str);
424 }
425 }
426
427 if (auth_class == AUTH_CLASS_PUBKEY)
428 {
429 if (smartcard)
430 {
431 char *pin;
432
433 pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
434 if (pin)
435 {
436 user = find_smartcard_key(priv, pin);
437 }
438 if (!user)
439 {
440 g_set_error(err, NM_VPN_PLUGIN_ERROR,
441 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
442 "no usable smartcard certificate found.");
443 gateway->destroy(gateway);
444 return FALSE;
445 }
446 }
447 /* ... or certificate/private key authenitcation */
448 else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
449 {
450 public_key_t *public;
451 private_key_t *private = NULL;
452
453 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
454 BUILD_FROM_FILE, str, BUILD_END);
455 if (!cert)
456 {
457 g_set_error(err, NM_VPN_PLUGIN_ERROR,
458 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
459 "Loading peer certificate failed.");
460 gateway->destroy(gateway);
461 return FALSE;
462 }
463 /* try agent */
464 str = nm_setting_vpn_get_secret(vpn, "agent");
465 if (agent && str)
466 {
467 public = cert->get_public_key(cert);
468 if (public)
469 {
470 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
471 public->get_type(public),
472 BUILD_AGENT_SOCKET, str,
473 BUILD_PUBLIC_KEY, public,
474 BUILD_END);
475 public->destroy(public);
476 }
477 if (!private)
478 {
479 g_set_error(err, NM_VPN_PLUGIN_ERROR,
480 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
481 "Connecting to SSH agent failed.");
482 }
483 }
484 /* ... or key file */
485 str = nm_setting_vpn_get_data_item(vpn, "userkey");
486 if (!agent && str)
487 {
488 char *secret;
489
490 secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
491 if (secret)
492 {
493 priv->creds->set_key_password(priv->creds, secret);
494 }
495 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
496 KEY_RSA, BUILD_FROM_FILE, str, BUILD_END);
497 if (!private)
498 {
499 g_set_error(err, NM_VPN_PLUGIN_ERROR,
500 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
501 "Loading private key failed.");
502 }
503 }
504 if (private)
505 {
506 user = cert->get_subject(cert);
507 user = user->clone(user);
508 priv->creds->set_cert_and_key(priv->creds, cert, private);
509 }
510 else
511 {
512 DESTROY_IF(cert);
513 gateway->destroy(gateway);
514 return FALSE;
515 }
516 }
517 }
518
519 if (!user)
520 {
521 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
522 "Configuration parameters missing.");
523 gateway->destroy(gateway);
524 return FALSE;
525 }
526
527 /**
528 * Set up configurations
529 */
530 ike_cfg = ike_cfg_create(IKEV2, TRUE, encap, "0.0.0.0", FALSE,
531 charon->socket->get_port(charon->socket, FALSE),
532 (char*)address, FALSE, IKEV2_UDP_PORT,
533 FRAGMENTATION_NO, 0);
534 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
535 peer_cfg = peer_cfg_create(priv->name, ike_cfg,
536 CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
537 36000, 0, /* rekey 10h, reauth none */
538 600, 600, /* jitter, over 10min */
539 TRUE, FALSE, /* mobike, aggressive */
540 0, 0, /* DPD delay, timeout */
541 FALSE, NULL, NULL); /* mediation */
542 if (virtual)
543 {
544 peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
545 }
546 auth = auth_cfg_create();
547 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
548 auth->add(auth, AUTH_RULE_IDENTITY, user);
549 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
550 auth = auth_cfg_create();
551 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
552 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
553 auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
554 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
555
556 child_cfg = child_cfg_create(priv->name, &lifetime,
557 NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */
558 ACTION_NONE, ACTION_NONE, ACTION_NONE, ipcomp,
559 0, 0, NULL, NULL, 0);
560 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
561 ts = traffic_selector_create_dynamic(0, 0, 65535);
562 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
563 ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
564 "0.0.0.0", 0,
565 "255.255.255.255", 65535);
566 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
567 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
568
569 /**
570 * Prepare IKE_SA
571 */
572 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
573 peer_cfg);
574 if (!ike_sa)
575 {
576 peer_cfg->destroy(peer_cfg);
577 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
578 "IKE version not supported.");
579 return FALSE;
580 }
581 if (!ike_sa->get_peer_cfg(ike_sa))
582 {
583 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
584 }
585 peer_cfg->destroy(peer_cfg);
586
587 /**
588 * Register listener, enable initiate-failure-detection hooks
589 */
590 priv->ike_sa = ike_sa;
591 priv->listener.ike_state_change = ike_state_change;
592 priv->listener.child_state_change = child_state_change;
593 charon->bus->add_listener(charon->bus, &priv->listener);
594
595 /**
596 * Initiate
597 */
598 child_cfg->get_ref(child_cfg);
599 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
600 {
601 charon->bus->remove_listener(charon->bus, &priv->listener);
602 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
603
604 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
605 "Initiating failed.");
606 return FALSE;
607 }
608 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
609 return TRUE;
610 }
611
612 /**
613 * NeedSecrets called from NM via DBUS
614 */
615 static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection,
616 char **setting_name, GError **error)
617 {
618 NMSettingVPN *settings;
619 const char *method, *path;
620
621 settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
622 NM_TYPE_SETTING_VPN));
623 method = nm_setting_vpn_get_data_item(settings, "method");
624 if (method)
625 {
626 if (streq(method, "eap"))
627 {
628 if (nm_setting_vpn_get_secret(settings, "password"))
629 {
630 return FALSE;
631 }
632 }
633 else if (streq(method, "agent"))
634 {
635 if (nm_setting_vpn_get_secret(settings, "agent"))
636 {
637 return FALSE;
638 }
639 }
640 else if (streq(method, "key"))
641 {
642 path = nm_setting_vpn_get_data_item(settings, "userkey");
643 if (path)
644 {
645 private_key_t *key;
646
647 /* try to load/decrypt the private key */
648 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
649 KEY_RSA, BUILD_FROM_FILE, path, BUILD_END);
650 if (key)
651 {
652 key->destroy(key);
653 return FALSE;
654 }
655 }
656 }
657 else if (streq(method, "smartcard"))
658 {
659 if (nm_setting_vpn_get_secret(settings, "password"))
660 {
661 return FALSE;
662 }
663 }
664 }
665 *setting_name = NM_SETTING_VPN_SETTING_NAME;
666 return TRUE;
667 }
668
669 /**
670 * Disconnect called from NM via DBUS
671 */
672 static gboolean disconnect(NMVPNPlugin *plugin, GError **err)
673 {
674 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
675 enumerator_t *enumerator;
676 ike_sa_t *ike_sa;
677 u_int id;
678
679 /* our ike_sa pointer might be invalid, lookup sa */
680 enumerator = charon->controller->create_ike_sa_enumerator(
681 charon->controller, TRUE);
682 while (enumerator->enumerate(enumerator, &ike_sa))
683 {
684 if (priv->ike_sa == ike_sa)
685 {
686 id = ike_sa->get_unique_id(ike_sa);
687 enumerator->destroy(enumerator);
688 charon->controller->terminate_ike(charon->controller, id,
689 controller_cb_empty, NULL, 0);
690 return TRUE;
691 }
692 }
693 enumerator->destroy(enumerator);
694
695 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_GENERAL,
696 "Connection not found.");
697 return FALSE;
698 }
699
700 /**
701 * Initializer
702 */
703 static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
704 {
705 NMStrongswanPluginPrivate *priv;
706
707 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
708 priv->plugin = NM_VPN_PLUGIN(plugin);
709 memset(&priv->listener, 0, sizeof(listener_t));
710 priv->listener.child_updown = child_updown;
711 priv->listener.ike_rekey = ike_rekey;
712 priv->tun = tun_device_create(NULL);
713 priv->name = NULL;
714 }
715
716 /**
717 * Destructor
718 */
719 static void nm_strongswan_plugin_dispose(GObject *obj)
720 {
721 NMStrongswanPlugin *plugin;
722 NMStrongswanPluginPrivate *priv;
723
724 plugin = NM_STRONGSWAN_PLUGIN(obj);
725 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
726 if (priv->tun)
727 {
728 priv->tun->destroy(priv->tun);
729 priv->tun = NULL;
730 }
731 }
732
733 /**
734 * Class constructor
735 */
736 static void nm_strongswan_plugin_class_init(
737 NMStrongswanPluginClass *strongswan_class)
738 {
739 NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS(strongswan_class);
740
741 g_type_class_add_private(G_OBJECT_CLASS(strongswan_class),
742 sizeof(NMStrongswanPluginPrivate));
743 parent_class->connect = connect_;
744 parent_class->need_secrets = need_secrets;
745 parent_class->disconnect = disconnect;
746 G_OBJECT_CLASS(strongswan_class)->dispose = nm_strongswan_plugin_dispose;
747 }
748
749 /**
750 * Object constructor
751 */
752 NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
753 nm_handler_t *handler)
754 {
755 NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_object_new (
756 NM_TYPE_STRONGSWAN_PLUGIN,
757 NM_VPN_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
758 NULL);
759 if (plugin)
760 {
761 NMStrongswanPluginPrivate *priv;
762
763 /* the rest of the initialization happened in _init above */
764 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
765 priv->creds = creds;
766 priv->handler = handler;
767 }
768 return plugin;
769 }