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