use the configured NM connection id as configuration/IKE_SA name
[strongswan.git] / src / charon / plugins / nm / nm_service.c
1 /*
2 * Copyright (C) 2008-2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <nm-setting-vpn.h>
17 #include <nm-setting-connection.h>
18 #include "nm_service.h"
19
20 #include <daemon.h>
21 #include <asn1/pem.h>
22 #include <utils/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, *(u_int32_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 GValue *val;
85 GHashTable *config;
86 host_t *me, *other;
87 nm_handler_t *handler;
88
89 config = g_hash_table_new(g_str_hash, g_str_equal);
90 me = ike_sa->get_my_host(ike_sa);
91 other = ike_sa->get_other_host(ike_sa);
92 handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
93
94 /* NM requires a tundev, but netkey does not use one. Passing an invalid
95 * iface makes NM complain, but it accepts it without fiddling on eth0. */
96 val = g_slice_new0 (GValue);
97 g_value_init (val, G_TYPE_STRING);
98 g_value_set_string (val, "none");
99 g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, val);
100
101 val = g_slice_new0(GValue);
102 g_value_init(val, G_TYPE_UINT);
103 g_value_set_uint(val, *(u_int32_t*)me->get_address(me).ptr);
104 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val);
105
106 val = g_slice_new0(GValue);
107 g_value_init(val, G_TYPE_UINT);
108 g_value_set_uint(val, me->get_address(me).len * 8);
109 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val);
110
111 val = handler_to_val(handler, INTERNAL_IP4_DNS);
112 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
113
114 val = handler_to_val(handler, INTERNAL_IP4_NBNS);
115 g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val);
116
117 handler->reset(handler);
118
119 nm_vpn_plugin_set_ip4_config(plugin, config);
120 }
121
122 /**
123 * signal failure to NM, connecting failed
124 */
125 static void signal_failure(NMVPNPlugin *plugin, NMVPNPluginFailure failure)
126 {
127 nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler;
128
129 handler->reset(handler);
130
131 /* TODO: NM does not handle this failure!? */
132 nm_vpn_plugin_failure(plugin, failure);
133 nm_vpn_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STOPPED);
134 }
135
136 /**
137 * Implementation of listener_t.ike_state_change
138 */
139 static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa,
140 ike_sa_state_t state)
141 {
142 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
143
144 if (private->ike_sa == ike_sa && state == IKE_DESTROYING)
145 {
146 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
147 return FALSE;
148 }
149 return TRUE;
150 }
151
152 /**
153 * Implementation of listener_t.child_state_change
154 */
155 static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa,
156 child_sa_t *child_sa, child_sa_state_t state)
157 {
158 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
159
160 if (private->ike_sa == ike_sa && state == CHILD_DESTROYING)
161 {
162 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
163 return FALSE;
164 }
165 return TRUE;
166 }
167
168 /**
169 * Implementation of listener_t.child_updown
170 */
171 static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
172 child_sa_t *child_sa, bool up)
173 {
174 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
175
176 if (private->ike_sa == ike_sa)
177 {
178 if (up)
179 { /* disable initiate-failure-detection hooks */
180 private->listener.ike_state_change = NULL;
181 private->listener.child_state_change = NULL;
182 signal_ipv4_config(private->plugin, ike_sa, child_sa);
183 }
184 else
185 {
186 signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
187 return FALSE;
188 }
189 }
190 return TRUE;
191 }
192
193 /**
194 * Implementation of listener_t.ike_rekey
195 */
196 static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
197 {
198 NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
199
200 if (private->ike_sa == old)
201 { /* follow a rekeyed IKE_SA */
202 private->ike_sa = new;
203 }
204 return TRUE;
205 }
206
207 /**
208 * Connect function called from NM via DBUS
209 */
210 static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
211 GError **err)
212 {
213 NMStrongswanPluginPrivate *priv;
214 NMSettingConnection *conn;
215 NMSettingVPN *vpn;
216 identification_t *user = NULL, *gateway;
217 const char *address, *str;
218 bool virtual, encap, ipcomp;
219 ike_cfg_t *ike_cfg;
220 peer_cfg_t *peer_cfg;
221 child_cfg_t *child_cfg;
222 traffic_selector_t *ts;
223 ike_sa_t *ike_sa;
224 auth_cfg_t *auth;
225 auth_class_t auth_class = AUTH_CLASS_EAP;
226 certificate_t *cert = NULL;
227 x509_t *x509;
228 bool agent = FALSE;
229
230 /**
231 * Read parameters
232 */
233 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
234 conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
235 NM_TYPE_SETTING_CONNECTION));
236 vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
237 NM_TYPE_SETTING_VPN));
238 if (priv->name)
239 {
240 free(priv->name);
241 }
242 priv->name = strdup(nm_setting_connection_get_id(conn));
243 DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
244 priv->name);
245 DBG4(DBG_CFG, "%s",
246 nm_setting_to_string(NM_SETTING(vpn)));
247 address = nm_setting_vpn_get_data_item(vpn, "address");
248 if (!address || !*address)
249 {
250 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
251 "Gateway address missing.");
252 return FALSE;
253 }
254 str = nm_setting_vpn_get_data_item(vpn, "virtual");
255 virtual = str && streq(str, "yes");
256 str = nm_setting_vpn_get_data_item(vpn, "encap");
257 encap = str && streq(str, "yes");
258 str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
259 ipcomp = str && streq(str, "yes");
260 str = nm_setting_vpn_get_data_item(vpn, "method");
261 if (str)
262 {
263 if (streq(str, "psk"))
264 {
265 auth_class = AUTH_CLASS_PSK;
266 }
267 else if (streq(str, "agent"))
268 {
269 auth_class = AUTH_CLASS_PUBKEY;
270 agent = TRUE;
271 }
272 else if (streq(str, "key"))
273 {
274 auth_class = AUTH_CLASS_PUBKEY;
275 }
276 }
277
278 /**
279 * Register credentials
280 */
281 priv->creds->clear(priv->creds);
282
283 /* gateway/CA cert */
284 str = nm_setting_vpn_get_data_item(vpn, "certificate");
285 if (str)
286 {
287 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
288 BUILD_FROM_FILE, str, BUILD_END);
289 priv->creds->set_certificate(priv->creds, cert);
290 }
291 if (!cert)
292 {
293 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
294 "Loading gateway certificate failed.");
295 return FALSE;
296 }
297 x509 = (x509_t*)cert;
298 if (x509->get_flags(x509) & X509_CA)
299 { /* If the user configured a CA certificate, we use the IP/DNS
300 * of the gateway as its identity. This identity will be used for
301 * certificate lookup and requires the configured IP/DNS to be
302 * included in the gateway certificate. */
303 gateway = identification_create_from_string((char*)address);
304 DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway);
305 }
306 else
307 { /* For a gateway certificate, we use the cert subject as identity. */
308 gateway = cert->get_subject(cert);
309 gateway = gateway->clone(gateway);
310 DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway);
311 }
312
313 if (auth_class == AUTH_CLASS_EAP)
314 {
315 /* username/password authentication ... */
316 str = nm_setting_vpn_get_data_item(vpn, "user");
317 if (str)
318 {
319 user = identification_create_from_string((char*)str);
320 str = nm_setting_vpn_get_secret(vpn, "password");
321 priv->creds->set_username_password(priv->creds, user, (char*)str);
322 }
323 }
324
325 if (auth_class == AUTH_CLASS_PUBKEY)
326 {
327 /* ... or certificate/private key authenitcation */
328 str = nm_setting_vpn_get_data_item(vpn, "usercert");
329 if (str)
330 {
331 public_key_t *public;
332 private_key_t *private = NULL;
333
334 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
335 BUILD_FROM_FILE, str, BUILD_END);
336 if (!cert)
337 {
338 g_set_error(err, NM_VPN_PLUGIN_ERROR,
339 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
340 "Loading peer certificate failed.");
341 gateway->destroy(gateway);
342 return FALSE;
343 }
344 /* try agent */
345 str = nm_setting_vpn_get_secret(vpn, "agent");
346 if (agent && str)
347 {
348 public = cert->get_public_key(cert);
349 if (public)
350 {
351 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
352 public->get_type(public),
353 BUILD_AGENT_SOCKET, str,
354 BUILD_PUBLIC_KEY, public,
355 BUILD_END);
356 public->destroy(public);
357 }
358 if (!private)
359 {
360 g_set_error(err, NM_VPN_PLUGIN_ERROR,
361 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
362 "Connecting to SSH agent failed.");
363 }
364 }
365 /* ... or key file */
366 str = nm_setting_vpn_get_data_item(vpn, "userkey");
367 if (!agent && str)
368 {
369 chunk_t secret, chunk;
370 bool pgp = FALSE;
371
372 secret.ptr = (char*)nm_setting_vpn_get_secret(vpn, "password");
373 if (secret.ptr)
374 {
375 secret.len = strlen(secret.ptr);
376 }
377 if (pem_asn1_load_file((char*)str, &secret, &chunk, &pgp))
378 {
379 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
380 KEY_RSA, BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
381 free(chunk.ptr);
382 }
383 if (!private)
384 {
385 g_set_error(err, NM_VPN_PLUGIN_ERROR,
386 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
387 "Loading private key failed.");
388 }
389 }
390 if (private)
391 {
392 user = cert->get_subject(cert);
393 user = user->clone(user);
394 priv->creds->set_cert_and_key(priv->creds, cert, private);
395 }
396 else
397 {
398 DESTROY_IF(cert);
399 gateway->destroy(gateway);
400 return FALSE;
401 }
402 }
403 }
404
405 if (!user)
406 {
407 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
408 "Configuration parameters missing.");
409 gateway->destroy(gateway);
410 return FALSE;
411 }
412
413 /**
414 * Set up configurations
415 */
416 ike_cfg = ike_cfg_create(TRUE, encap, "0.0.0.0", (char*)address);
417 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
418 peer_cfg = peer_cfg_create(priv->name, 2, ike_cfg,
419 CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
420 36000, 0, /* rekey 10h, reauth none */
421 600, 600, /* jitter, over 10min */
422 TRUE, 0, /* mobike, DPD */
423 virtual ? host_create_from_string("0.0.0.0", 0) : NULL,
424 NULL, FALSE, NULL, NULL); /* pool, mediation */
425 auth = auth_cfg_create();
426 auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
427 auth->add(auth, AUTH_RULE_IDENTITY, user);
428 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
429 auth = auth_cfg_create();
430 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
431 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
432 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
433
434 child_cfg = child_cfg_create(priv->name,
435 10800, 10200, /* lifetime 3h, rekey 2h50min */
436 300, /* jitter 5min */
437 NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */
438 ACTION_NONE, ACTION_NONE, ipcomp);
439 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
440 ts = traffic_selector_create_dynamic(0, 0, 65535);
441 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
442 ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
443 "0.0.0.0", 0,
444 "255.255.255.255", 65535);
445 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
446 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
447
448 /**
449 * Prepare IKE_SA
450 */
451 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
452 peer_cfg);
453 if (!ike_sa->get_peer_cfg(ike_sa))
454 {
455 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
456 }
457 else
458 {
459 peer_cfg->destroy(peer_cfg);
460 }
461
462 /**
463 * Register listener, enable initiate-failure-detection hooks
464 */
465 priv->ike_sa = ike_sa;
466 priv->listener.ike_state_change = ike_state_change;
467 priv->listener.child_state_change = child_state_change;
468 charon->bus->add_listener(charon->bus, &priv->listener);
469
470 /**
471 * Initiate
472 */
473 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
474 {
475 charon->bus->remove_listener(charon->bus, &priv->listener);
476 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
477
478 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
479 "Initiating failed.");
480 return FALSE;
481 }
482 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
483 return TRUE;
484 }
485
486 /**
487 * NeedSecrets called from NM via DBUS
488 */
489 static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection,
490 char **setting_name, GError **error)
491 {
492 NMSettingVPN *settings;
493 const char *method, *path;
494 chunk_t secret = chunk_empty, key;
495 bool pgp = FALSE;
496
497 settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
498 NM_TYPE_SETTING_VPN));
499 method = nm_setting_vpn_get_data_item(settings, "method");
500 if (method)
501 {
502 if (streq(method, "eap"))
503 {
504 if (nm_setting_vpn_get_secret(settings, "password"))
505 {
506 return FALSE;
507 }
508 }
509 else if (streq(method, "agent"))
510 {
511 if (nm_setting_vpn_get_secret(settings, "agent"))
512 {
513 return FALSE;
514 }
515 }
516 else if (streq(method, "key"))
517 {
518 path = nm_setting_vpn_get_data_item(settings, "userkey");
519 if (path)
520 {
521 secret.ptr = (char*)nm_setting_vpn_get_secret(settings, "password");
522 if (secret.ptr)
523 {
524 secret.len = strlen(secret.ptr);
525 }
526 if (pem_asn1_load_file((char*)path, &secret, &key, &pgp))
527 {
528 free(key.ptr);
529 return FALSE;
530 }
531 }
532 }
533 }
534 *setting_name = NM_SETTING_VPN_SETTING_NAME;
535 return TRUE;
536 }
537
538 /**
539 * Disconnect called from NM via DBUS
540 */
541 static gboolean disconnect(NMVPNPlugin *plugin, GError **err)
542 {
543 NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
544 enumerator_t *enumerator;
545 ike_sa_t *ike_sa;
546 u_int id;
547
548 /* our ike_sa pointer might be invalid, lookup sa */
549 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
550 while (enumerator->enumerate(enumerator, &ike_sa))
551 {
552 if (priv->ike_sa == ike_sa)
553 {
554 id = ike_sa->get_unique_id(ike_sa);
555 enumerator->destroy(enumerator);
556 charon->controller->terminate_ike(charon->controller, id,
557 controller_cb_empty, NULL);
558 return TRUE;
559 }
560 }
561 enumerator->destroy(enumerator);
562
563 g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_GENERAL,
564 "Connection not found.");
565 return FALSE;
566 }
567
568 /**
569 * Initializer
570 */
571 static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
572 {
573 NMStrongswanPluginPrivate *priv;
574
575 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
576 priv->plugin = NM_VPN_PLUGIN(plugin);
577 memset(&priv->listener.log, 0, sizeof(listener_t));
578 priv->listener.child_updown = child_updown;
579 priv->listener.ike_rekey = ike_rekey;
580 }
581
582 /**
583 * Class constructor
584 */
585 static void nm_strongswan_plugin_class_init(
586 NMStrongswanPluginClass *strongswan_class)
587 {
588 NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS(strongswan_class);
589
590 g_type_class_add_private(G_OBJECT_CLASS(strongswan_class),
591 sizeof(NMStrongswanPluginPrivate));
592 parent_class->connect = connect_;
593 parent_class->need_secrets = need_secrets;
594 parent_class->disconnect = disconnect;
595 }
596
597 /**
598 * Object constructor
599 */
600 NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
601 nm_handler_t *handler)
602 {
603 NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_object_new (
604 NM_TYPE_STRONGSWAN_PLUGIN,
605 NM_VPN_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
606 NULL);
607 if (plugin)
608 {
609 NMStrongswanPluginPrivate *priv;
610
611 priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
612 priv->creds = creds;
613 priv->handler = handler;
614 priv->name = NULL;
615 }
616 return plugin;
617 }
618