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