Annotation of embedaddon/strongswan/src/charon-nm/nm/nm_service.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2017 Lubomir Rintel
3: *
4: * Copyright (C) 2013-2020 Tobias Brunner
5: * Copyright (C) 2008-2009 Martin Willi
6: * HSR Hochschule fuer Technik Rapperswil
7: *
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>.
12: *
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
16: * for more details.
17: */
18:
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>
1.1.1.2 ! misho 26: #include <networking/tun_device.h>
1.1 misho 27:
28: #include <stdio.h>
29:
30: /**
31: * Private data of NMStrongswanPlugin
32: */
33: typedef struct {
34: /* implements bus listener interface */
35: listener_t listener;
36: /* IKE_SA we are listening on */
37: ike_sa_t *ike_sa;
38: /* backref to public plugin */
39: NMVpnServicePlugin *plugin;
40: /* credentials to use for authentication */
41: nm_creds_t *creds;
42: /* attribute handler for DNS/NBNS server information */
43: nm_handler_t *handler;
1.1.1.2 ! misho 44: /* dummy TUN device */
! 45: tun_device_t *tun;
1.1 misho 46: /* name of the connection */
47: char *name;
48: } NMStrongswanPluginPrivate;
49:
50: G_DEFINE_TYPE_WITH_PRIVATE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
51:
52: #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
53: ((NMStrongswanPluginPrivate*) \
54: nm_strongswan_plugin_get_instance_private (o))
55:
56: /**
57: * Convert an address chunk to a GValue
58: */
59: static GVariant *addr_to_variant(chunk_t addr)
60: {
61: GVariantBuilder builder;
62: int i;
63:
64: switch (addr.len)
65: {
66: case 4:
67: return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
68: case 16:
69: g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
70: for (i = 0; i < addr.len; i++)
71: {
72: g_variant_builder_add (&builder, "y", addr.ptr[i]);
73:
74: }
75: return g_variant_builder_end (&builder);
76: default:
77: return NULL;
78: }
79: }
80:
81: /**
82: * Convert a host to a GValue
83: */
84: static GVariant *host_to_variant(host_t *host)
85: {
86: return addr_to_variant(host->get_address(host));
87: }
88:
89: /**
90: * Convert enumerated handler chunks to a GValue
91: */
92: static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
93: configuration_attribute_type_t type)
94: {
95: GVariantBuilder builder;
96: enumerator_t *enumerator;
97: chunk_t *chunk;
98:
99: g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
100:
101: enumerator = handler->create_enumerator(handler, type);
102: while (enumerator->enumerate(enumerator, &chunk))
103: {
104: g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
105: }
106: enumerator->destroy(enumerator);
107:
108: return g_variant_builder_end (&builder);
109: }
110:
111: /**
112: * Signal IP config to NM, set connection as established
113: */
114: static void signal_ip_config(NMVpnServicePlugin *plugin,
115: ike_sa_t *ike_sa, child_sa_t *child_sa)
116: {
117: NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
118: NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
119: GVariantBuilder builder, ip4builder, ip6builder;
120: GVariant *ip4config, *ip6config;
121: enumerator_t *enumerator;
122: host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
123: nm_handler_t *handler;
124:
125: g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
126: g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
127: g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
128:
129: handler = priv->handler;
130:
131: /* NM apparently requires to know the gateway */
132: other = ike_sa->get_other_host(ike_sa);
133: g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
1.1.1.2 ! misho 134: host_to_variant(other));
! 135:
! 136: /* systemd-resolved requires a device to properly install DNS servers, but
! 137: * Netkey does not use one. Passing the physical interface is not ideal,
! 138: * as NM fiddles around with it and systemd-resolved likes a separate
! 139: * device. So we pass a dummy TUN device along for NM etc. to play with...
! 140: */
! 141: if (priv->tun)
! 142: {
! 143: g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV,
! 144: g_variant_new_string (priv->tun->get_name(priv->tun)));
! 145: }
1.1 misho 146:
147: /* pass the first virtual IPs we got or use the physical IP */
148: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
149: while (enumerator->enumerate(enumerator, &me))
150: {
151: switch (me->get_family(me))
152: {
153: case AF_INET:
154: if (!vip4)
155: {
156: vip4 = me;
157: }
158: break;
159: case AF_INET6:
160: if (!vip6)
161: {
162: vip6 = me;
163: }
164: break;
165: }
166: }
167: enumerator->destroy(enumerator);
168: if (!vip4 && !vip6)
169: {
170: me = ike_sa->get_my_host(ike_sa);
171: switch (me->get_family(me))
172: {
173: case AF_INET:
174: vip4 = me;
175: break;
176: case AF_INET6:
177: vip6 = me;
178: break;
179: }
180: }
181:
182: if (vip4)
183: {
184: g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
185: host_to_variant(vip4));
186: g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
187: g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
188:
189: /* prevent NM from changing the default route. we set our own route in our
190: * own routing table
191: */
192: g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
193: g_variant_new_boolean (TRUE));
194:
195: g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
196: handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
197:
198: g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
199: handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
200: }
201:
202: if (vip6)
203: {
204: g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
205: host_to_variant(vip6));
206: g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
207: g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
208: g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
209: g_variant_new_boolean (TRUE));
210: g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
211: handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
212: /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
213: }
214:
215: ip4config = g_variant_builder_end (&ip4builder);
216: if (g_variant_n_children (ip4config))
217: {
218: g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
219: g_variant_new_boolean (TRUE));
220: }
221: else
222: {
223: g_variant_unref (ip4config);
224: ip4config = NULL;
225: }
226:
227: ip6config = g_variant_builder_end (&ip6builder);
228: if (g_variant_n_children (ip6config))
229: {
230: g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
231: g_variant_new_boolean (TRUE));
232: }
233: else
234: {
235: g_variant_unref (ip6config);
236: ip6config = NULL;
237: }
238:
239: handler->reset(handler);
240:
241: nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
242: if (ip4config)
243: {
244: nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
245: }
246: if (ip6config)
247: {
248: nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
249: }
250: }
251:
252: /**
253: * signal failure to NM, connecting failed
254: */
255: static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure)
256: {
257: NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
258: nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub)->handler;
259:
260: handler->reset(handler);
261:
262: nm_vpn_service_plugin_failure(plugin, failure);
263: }
264:
265: METHOD(listener_t, ike_state_change, bool,
266: NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, ike_sa_state_t state)
267: {
268: if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
269: {
270: signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
271: }
272: return TRUE;
273: }
274:
275: METHOD(listener_t, child_state_change, bool,
276: NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
277: child_sa_state_t state)
278: {
279: if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
280: {
281: signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
282: }
283: return TRUE;
284: }
285:
286: METHOD(listener_t, ike_rekey, bool,
287: NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
288: {
289: if (this->ike_sa == old)
290: { /* follow a rekeyed IKE_SA */
291: this->ike_sa = new;
292: }
293: return TRUE;
294: }
295:
296: METHOD(listener_t, ike_reestablish_pre, bool,
297: NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
298: {
299: if (this->ike_sa == old)
300: { /* ignore child state changes during redirects etc. (task migration) */
301: this->listener.child_state_change = NULL;
302: }
303: return TRUE;
304: }
305:
306: METHOD(listener_t, ike_reestablish_post, bool,
307: NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new,
308: bool initiated)
309: {
310: if (this->ike_sa == old && initiated)
311: { /* if we get redirected during IKE_AUTH we just migrate to the new SA */
312: this->ike_sa = new;
313: /* re-register hooks to detect initiation failures */
314: this->listener.ike_state_change = _ike_state_change;
315: this->listener.child_state_change = _child_state_change;
316: }
317: return TRUE;
318: }
319:
320: METHOD(listener_t, child_updown, bool,
321: NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
322: bool up)
323: {
1.1.1.2 ! misho 324: if (this->ike_sa == ike_sa && up)
1.1 misho 325: {
1.1.1.2 ! misho 326: /* disable initiate-failure-detection hooks */
! 327: this->listener.ike_state_change = NULL;
! 328: this->listener.child_state_change = NULL;
! 329: signal_ip_config(this->plugin, ike_sa, child_sa);
1.1 misho 330: }
331: return TRUE;
332: }
333:
334: /**
335: * Find a certificate for which we have a private key on a smartcard
336: */
337: static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
338: char *pin)
339: {
340: enumerator_t *enumerator, *sans;
341: identification_t *id = NULL;
342: certificate_t *cert;
343: x509_t *x509;
344: private_key_t *key;
345: chunk_t keyid;
346:
347: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
348: CERT_X509, KEY_ANY, NULL, FALSE);
349: while (enumerator->enumerate(enumerator, &cert))
350: {
351: x509 = (x509_t*)cert;
352:
353: /* there might be a lot of certificates, filter them by usage */
354: if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
355: !(x509->get_flags(x509) & X509_CA))
356: {
357: keyid = x509->get_subjectKeyIdentifier(x509);
358: if (keyid.ptr)
359: {
360: /* try to find a private key by the certificate keyid */
361: priv->creds->set_pin(priv->creds, keyid, pin);
362: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
363: KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
364: if (key)
365: {
366: /* prefer a more convenient subjectAltName */
367: sans = x509->create_subjectAltName_enumerator(x509);
368: if (!sans->enumerate(sans, &id))
369: {
370: id = cert->get_subject(cert);
371: }
372: id = id->clone(id);
373: sans->destroy(sans);
374:
375: DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
376: priv->creds->set_cert_and_key(priv->creds,
377: cert->get_ref(cert), key);
378: break;
379: }
380: }
381: }
382: }
383: enumerator->destroy(enumerator);
384: return id;
385: }
386:
387: /**
388: * Add a client auth config for certificate authentication
389: */
390: static bool add_auth_cfg_cert(NMStrongswanPluginPrivate *priv,
391: NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
392: GError **err)
393: {
394: identification_t *id = NULL;
395: certificate_t *cert = NULL;
396: auth_cfg_t *auth;
397: const char *str, *method, *cert_source;
398:
399: method = nm_setting_vpn_get_data_item(vpn, "method");
400: cert_source = nm_setting_vpn_get_data_item(vpn, "cert-source") ?: method;
401:
402: if (streq(cert_source, "smartcard"))
403: {
404: char *pin;
405:
406: pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
407: if (pin)
408: {
409: id = find_smartcard_key(priv, pin);
410: }
411: if (!id)
412: {
413: g_set_error(err, NM_VPN_PLUGIN_ERROR,
414: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
415: "No usable smartcard certificate found.");
416: return FALSE;
417: }
418: }
419: /* ... or certificate/private key authentication */
420: else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
421: {
422: public_key_t *public;
423: private_key_t *private = NULL;
424:
425: bool agent = streq(cert_source, "agent");
426:
427: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
428: BUILD_FROM_FILE, str, BUILD_END);
429: if (!cert)
430: {
431: g_set_error(err, NM_VPN_PLUGIN_ERROR,
432: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
433: "Loading peer certificate failed.");
434: return FALSE;
435: }
436: /* try agent */
437: str = nm_setting_vpn_get_secret(vpn, "agent");
438: if (agent && str)
439: {
440: public = cert->get_public_key(cert);
441: if (public)
442: {
443: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
444: public->get_type(public),
445: BUILD_AGENT_SOCKET, str,
446: BUILD_PUBLIC_KEY, public,
447: BUILD_END);
448: public->destroy(public);
449: }
450: if (!private)
451: {
452: g_set_error(err, NM_VPN_PLUGIN_ERROR,
453: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
454: "Connecting to SSH agent failed.");
455: }
456: }
457: /* ... or key file */
458: str = nm_setting_vpn_get_data_item(vpn, "userkey");
459: if (!agent && str)
460: {
461: char *secret;
462:
463: secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
464: if (secret)
465: {
466: priv->creds->set_key_password(priv->creds, secret);
467: }
468: private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
469: KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
470: if (!private)
471: {
472: g_set_error(err, NM_VPN_PLUGIN_ERROR,
473: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
474: "Loading private key failed.");
475: }
476: }
477: if (private)
478: {
479: id = cert->get_subject(cert);
480: id = id->clone(id);
481: priv->creds->set_cert_and_key(priv->creds, cert, private);
482: }
483: else
484: {
485: DESTROY_IF(cert);
486: return FALSE;
487: }
488: }
489: else
490: {
491: g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
492: "Certificate is missing.");
493: return FALSE;
494: }
495:
496: auth = auth_cfg_create();
497: if (streq(method, "eap-tls"))
498: {
499: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
500: auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_TLS);
501: auth->add(auth, AUTH_RULE_AAA_IDENTITY,
502: identification_create_from_string("%any"));
503: }
504: else
505: {
506: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
507: }
508: if (cert)
509: {
510: auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
511: }
512: str = nm_setting_vpn_get_data_item(vpn, "local-identity");
513: if (str)
514: {
515: identification_t *local_id;
516:
517: local_id = identification_create_from_string((char*)str);
518: if (local_id)
519: {
520: id->destroy(id);
521: id = local_id;
522: }
523: }
524: auth->add(auth, AUTH_RULE_IDENTITY, id);
525: peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
526: return TRUE;
527: }
528:
529: /**
530: * Add a client auth config for username/password authentication
531: */
532: static bool add_auth_cfg_pw(NMStrongswanPluginPrivate *priv,
533: NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
534: GError **err)
535: {
536: identification_t *user = NULL, *id = NULL;
537: auth_cfg_t *auth;
538: const char *str, *method;
539:
540: method = nm_setting_vpn_get_data_item(vpn, "method");
541:
542: str = nm_setting_vpn_get_data_item(vpn, "user");
543: if (str)
544: {
545: user = identification_create_from_string((char*)str);
546: }
547: else
548: {
549: user = identification_create_from_string("%any");
550: }
551: str = nm_setting_vpn_get_data_item(vpn, "local-identity");
552: if (str)
553: {
554: id = identification_create_from_string((char*)str);
555: }
556: else
557: {
558: id = user->clone(user);
559: }
560: str = nm_setting_vpn_get_secret(vpn, "password");
561: if (streq(method, "psk"))
562: {
563: if (strlen(str) < 20)
564: {
565: g_set_error(err, NM_VPN_PLUGIN_ERROR,
566: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
567: "Pre-shared key is too short.");
568: user->destroy(user);
569: id->destroy(id);
570: return FALSE;
571: }
572: priv->creds->set_username_password(priv->creds, id, (char*)str);
573: }
574: else
575: {
576: priv->creds->set_username_password(priv->creds, user, (char*)str);
577: }
578:
579: auth = auth_cfg_create();
580: auth->add(auth, AUTH_RULE_AUTH_CLASS,
581: streq(method, "psk") ? AUTH_CLASS_PSK : AUTH_CLASS_EAP);
582: /* in case EAP-PEAP or EAP-TTLS is used we currently accept any identity */
583: auth->add(auth, AUTH_RULE_AAA_IDENTITY,
584: identification_create_from_string("%any"));
585: auth->add(auth, AUTH_RULE_EAP_IDENTITY, user);
586: auth->add(auth, AUTH_RULE_IDENTITY, id);
587: peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
588: return TRUE;
589: }
590:
591: /**
592: * Connect function called from NM via DBUS
593: */
594: static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
595: GError **err)
596: {
597: NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
598: NMStrongswanPluginPrivate *priv;
599: NMSettingConnection *conn;
600: NMSettingVpn *vpn;
601: enumerator_t *enumerator;
602: identification_t *gateway = NULL;
603: const char *str, *method;
604: bool virtual, proposal;
605: proposal_t *prop;
606: ike_cfg_t *ike_cfg;
607: peer_cfg_t *peer_cfg;
608: child_cfg_t *child_cfg;
609: traffic_selector_t *ts;
610: ike_sa_t *ike_sa;
611: auth_cfg_t *auth;
612: certificate_t *cert = NULL;
613: x509_t *x509;
614: bool loose_gateway_id = FALSE;
615: ike_cfg_create_t ike = {
616: .version = IKEV2,
617: .local = "%any",
618: .local_port = charon->socket->get_port(charon->socket, FALSE),
619: .remote_port = IKEV2_UDP_PORT,
620: .fragmentation = FRAGMENTATION_YES,
621: };
622: peer_cfg_create_t peer = {
623: .cert_policy = CERT_SEND_IF_ASKED,
624: .unique = UNIQUE_REPLACE,
625: .rekey_time = 36000, /* 10h */
626: .jitter_time = 600, /* 10min */
627: .over_time = 600, /* 10min */
628: };
629: child_cfg_create_t child = {
630: .lifetime = {
631: .time = {
632: .life = 10800 /* 3h */,
633: .rekey = 10200 /* 2h50min */,
634: .jitter = 300 /* 5min */
635: },
636: },
637: .mode = MODE_TUNNEL,
1.1.1.2 ! misho 638: .dpd_action = ACTION_RESTART,
! 639: .close_action = ACTION_RESTART,
1.1 misho 640: };
641:
642: /**
643: * Read parameters
644: */
645: priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
646: conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
647: NM_TYPE_SETTING_CONNECTION));
648: vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
649: NM_TYPE_SETTING_VPN));
650: if (priv->name)
651: {
652: free(priv->name);
653: }
654: priv->name = strdup(nm_setting_connection_get_id(conn));
655: DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
656: priv->name);
657: DBG4(DBG_CFG, "%s",
658: nm_setting_to_string(NM_SETTING(vpn)));
1.1.1.2 ! misho 659: if (!priv->tun)
! 660: {
! 661: DBG1(DBG_CFG, "failed to create dummy TUN device, might affect DNS "
! 662: "server installation negatively");
! 663: }
1.1 misho 664: ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address");
665: if (!ike.remote || !*ike.remote)
666: {
667: g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
668: "Gateway address missing.");
669: return FALSE;
670: }
671: str = nm_setting_vpn_get_data_item(vpn, "server-port");
672: if (str && strlen(str))
673: {
674: ike.remote_port = settings_value_as_int((char*)str, ike.remote_port);
675: }
676: str = nm_setting_vpn_get_data_item(vpn, "virtual");
677: virtual = streq(str, "yes");
678: str = nm_setting_vpn_get_data_item(vpn, "encap");
679: ike.force_encap = streq(str, "yes");
680: str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
681: child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
682:
683: /**
684: * Register credentials
685: */
686: priv->creds->clear(priv->creds);
687:
688: /* gateway/CA cert */
689: str = nm_setting_vpn_get_data_item(vpn, "certificate");
690: if (str)
691: {
692: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
693: BUILD_FROM_FILE, str, BUILD_END);
694: if (!cert)
695: {
696: g_set_error(err, NM_VPN_PLUGIN_ERROR,
697: NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
698: "Loading gateway certificate failed.");
699: return FALSE;
700: }
701: priv->creds->add_certificate(priv->creds, cert);
702: }
703: else
704: {
705: /* no certificate defined, fall back to system-wide CA certificates */
706: priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
707: lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
708: }
709:
710: str = nm_setting_vpn_get_data_item(vpn, "remote-identity");
711: if (str)
712: {
713: gateway = identification_create_from_string((char*)str);
714: }
715: else if (cert)
716: {
717: x509 = (x509_t*)cert;
718: if (!(x509->get_flags(x509) & X509_CA))
719: { /* for server certificates, we use the subject as identity */
720: gateway = cert->get_subject(cert);
721: gateway = gateway->clone(gateway);
722: }
723: }
724: if (!gateway || gateway->get_type(gateway) == ID_ANY)
725: {
726: /* if the user configured a CA certificate (or an invalid identity),
727: * we use the IP/hostname of the server */
728: gateway = identification_create_from_string(ike.remote);
729: loose_gateway_id = TRUE;
730: }
731: DBG1(DBG_CFG, "using gateway identity '%Y'", gateway);
732:
733: /**
734: * Set up configurations
735: */
736: ike_cfg = ike_cfg_create(&ike);
737:
738: str = nm_setting_vpn_get_data_item(vpn, "proposal");
739: proposal = streq(str, "yes");
740: str = nm_setting_vpn_get_data_item(vpn, "ike");
741: if (proposal && str && strlen(str))
742: {
743: enumerator = enumerator_create_token(str, ";", "");
744: while (enumerator->enumerate(enumerator, &str))
745: {
746: prop = proposal_create_from_string(PROTO_IKE, str);
747: if (!prop)
748: {
749: g_set_error(err, NM_VPN_PLUGIN_ERROR,
750: NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
751: "Invalid IKE proposal.");
752: enumerator->destroy(enumerator);
753: ike_cfg->destroy(ike_cfg);
754: gateway->destroy(gateway);
755: return FALSE;
756: }
757: ike_cfg->add_proposal(ike_cfg, prop);
758: }
759: enumerator->destroy(enumerator);
760: }
761: else
762: {
763: ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
764: ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
765: }
766:
767: peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
768: if (virtual)
769: {
770: peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
771: peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
772: }
773:
774: method = nm_setting_vpn_get_data_item(vpn, "method");
775: if (streq(method, "cert") ||
776: streq(method, "eap-tls") ||
777: streq(method, "key") ||
778: streq(method, "agent") ||
779: streq(method, "smartcard"))
780: {
781: if (!add_auth_cfg_cert (priv, vpn, peer_cfg, err))
782: {
783: peer_cfg->destroy(peer_cfg);
784: ike_cfg->destroy(ike_cfg);
785: gateway->destroy(gateway);
786: return FALSE;
787: }
788: }
789: else if (streq(method, "eap") ||
790: streq(method, "psk"))
791: {
792: if (!add_auth_cfg_pw(priv, vpn, peer_cfg, err))
793: {
794: peer_cfg->destroy(peer_cfg);
795: ike_cfg->destroy(ike_cfg);
796: gateway->destroy(gateway);
797: return FALSE;
798: }
799: }
800: else
801: {
802: g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
803: "Configuration parameters missing.");
804: peer_cfg->destroy(peer_cfg);
805: ike_cfg->destroy(ike_cfg);
806: gateway->destroy(gateway);
807: return FALSE;
808: }
809:
810: auth = auth_cfg_create();
811: if (streq(method, "psk"))
812: {
813: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
814: }
815: else
816: {
817: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
818: }
819: auth->add(auth, AUTH_RULE_IDENTITY, gateway);
820: auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
821: peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
822:
823: child_cfg = child_cfg_create(priv->name, &child);
824: str = nm_setting_vpn_get_data_item(vpn, "esp");
825: if (proposal && str && strlen(str))
826: {
827: enumerator = enumerator_create_token(str, ";", "");
828: while (enumerator->enumerate(enumerator, &str))
829: {
830: prop = proposal_create_from_string(PROTO_ESP, str);
831: if (!prop)
832: {
833: g_set_error(err, NM_VPN_PLUGIN_ERROR,
834: NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
835: "Invalid ESP proposal.");
836: enumerator->destroy(enumerator);
837: child_cfg->destroy(child_cfg);
838: peer_cfg->destroy(peer_cfg);
839: return FALSE;
840: }
841: child_cfg->add_proposal(child_cfg, prop);
842: }
843: enumerator->destroy(enumerator);
844: }
845: else
846: {
847: child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
1.1.1.2 ! misho 848: child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
1.1 misho 849: }
850: ts = traffic_selector_create_dynamic(0, 0, 65535);
851: child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
1.1.1.2 ! misho 852: str = nm_setting_vpn_get_data_item(vpn, "remote-ts");
! 853: if (str && strlen(str))
! 854: {
! 855: enumerator = enumerator_create_token(str, ";", "");
! 856: while (enumerator->enumerate(enumerator, &str))
! 857: {
! 858: ts = traffic_selector_create_from_cidr((char*)str, 0, 0, 65535);
! 859: if (!ts)
! 860: {
! 861: g_set_error(err, NM_VPN_PLUGIN_ERROR,
! 862: NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
! 863: "Invalid remote traffic selector.");
! 864: enumerator->destroy(enumerator);
! 865: child_cfg->destroy(child_cfg);
! 866: peer_cfg->destroy(peer_cfg);
! 867: return FALSE;
! 868: }
! 869: child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
! 870: }
! 871: enumerator->destroy(enumerator);
! 872: }
! 873: else
! 874: {
! 875: ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
! 876: child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
! 877: ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
! 878: child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
! 879: }
1.1 misho 880: peer_cfg->add_child_cfg(peer_cfg, child_cfg);
881:
882: /**
883: * Prepare IKE_SA
884: */
885: ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
886: peer_cfg);
1.1.1.2 ! misho 887: peer_cfg->destroy(peer_cfg);
1.1 misho 888: if (!ike_sa)
889: {
890: g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
891: "IKE version not supported.");
892: return FALSE;
893: }
894:
895: /**
896: * Register listener, enable initiate-failure-detection hooks
897: */
898: priv->ike_sa = ike_sa;
899: priv->listener.ike_state_change = _ike_state_change;
900: priv->listener.child_state_change = _child_state_change;
901:
902: /**
903: * Initiate
904: */
905: child_cfg->get_ref(child_cfg);
906: if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
907: {
908: charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
909:
910: g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
911: "Initiating failed.");
912: return FALSE;
913: }
914: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
915: return TRUE;
916: }
917:
918: /**
919: * NeedSecrets called from NM via DBUS
920: */
921: static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
922: const char **setting_name, GError **error)
923: {
924: NMSettingVpn *settings;
925: const char *method, *cert_source, *path;
926: bool need_secret = FALSE;
927:
928: settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
929: NM_TYPE_SETTING_VPN));
930: method = nm_setting_vpn_get_data_item(settings, "method");
931: if (method)
932: {
933: if (streq(method, "cert") ||
934: streq(method, "eap-tls") ||
935: streq(method, "key") ||
936: streq(method, "agent") ||
937: streq(method, "smartcard"))
938: {
939: cert_source = nm_setting_vpn_get_data_item(settings, "cert-source");
940: if (!cert_source)
941: {
942: cert_source = method;
943: }
944: if (streq(cert_source, "agent"))
945: {
946: need_secret = !nm_setting_vpn_get_secret(settings, "agent");
947: }
948: else if (streq(cert_source, "smartcard"))
949: {
950: need_secret = !nm_setting_vpn_get_secret(settings, "password");
951: }
952: else
953: {
954: need_secret = TRUE;
955: path = nm_setting_vpn_get_data_item(settings, "userkey");
956: if (path)
957: {
958: private_key_t *key;
959:
960: /* try to load/decrypt the private key */
961: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
962: KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
963: if (key)
964: {
965: key->destroy(key);
966: need_secret = FALSE;
967: }
968: else if (nm_setting_vpn_get_secret(settings, "password"))
969: {
970: need_secret = FALSE;
971: }
972: }
973: }
974: }
975: else if (streq(method, "eap") ||
976: streq(method, "psk"))
977: {
978: need_secret = !nm_setting_vpn_get_secret(settings, "password");
979: }
980: }
981: *setting_name = NM_SETTING_VPN_SETTING_NAME;
982: return need_secret;
983: }
984:
985: /**
986: * The actual disconnection
987: */
988: static gboolean do_disconnect(gpointer plugin)
989: {
990: NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
991: enumerator_t *enumerator;
992: ike_sa_t *ike_sa;
993: u_int id;
994:
995: /* our ike_sa pointer might be invalid, lookup sa */
996: enumerator = charon->controller->create_ike_sa_enumerator(
997: charon->controller, TRUE);
998: while (enumerator->enumerate(enumerator, &ike_sa))
999: {
1000: if (priv->ike_sa == ike_sa)
1001: {
1002: id = ike_sa->get_unique_id(ike_sa);
1003: enumerator->destroy(enumerator);
1004: charon->controller->terminate_ike(charon->controller, id, FALSE,
1005: controller_cb_empty, NULL, 0);
1.1.1.2 ! misho 1006:
! 1007: /* clear secrets as we are asked for new secrets (where we'd find
! 1008: * the cached secrets from earlier connections) before we clear
! 1009: * them in connect() */
! 1010: priv->creds->clear(priv->creds);
1.1 misho 1011: return FALSE;
1012: }
1013: }
1014: enumerator->destroy(enumerator);
1015:
1016: g_debug("Connection not found.");
1017: return FALSE;
1018: }
1019:
1020: /**
1021: * Disconnect called from NM via DBUS
1022: */
1023: static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
1024: {
1025: /* enqueue the actual disconnection, because we may be called in
1026: * response to a listener_t callback and the SA enumeration would
1027: * possibly deadlock. */
1028: g_idle_add(do_disconnect, plugin);
1029:
1030: return TRUE;
1031: }
1032:
1033: /**
1034: * Initializer
1035: */
1036: static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
1037: {
1038: NMStrongswanPluginPrivate *priv;
1039:
1040: priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
1041: priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
1042: memset(&priv->listener, 0, sizeof(listener_t));
1043: priv->listener.child_updown = _child_updown;
1044: priv->listener.ike_rekey = _ike_rekey;
1045: priv->listener.ike_reestablish_pre = _ike_reestablish_pre;
1046: priv->listener.ike_reestablish_post = _ike_reestablish_post;
1047: charon->bus->add_listener(charon->bus, &priv->listener);
1.1.1.2 ! misho 1048: priv->tun = tun_device_create(NULL);
1.1 misho 1049: priv->name = NULL;
1050: }
1051:
1052: /**
1.1.1.2 ! misho 1053: * Destructor
! 1054: */
! 1055: static void nm_strongswan_plugin_dispose(GObject *obj)
! 1056: {
! 1057: NMStrongswanPlugin *plugin;
! 1058: NMStrongswanPluginPrivate *priv;
! 1059:
! 1060: plugin = NM_STRONGSWAN_PLUGIN(obj);
! 1061: priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
! 1062: if (priv->tun)
! 1063: {
! 1064: priv->tun->destroy(priv->tun);
! 1065: priv->tun = NULL;
! 1066: }
! 1067: G_OBJECT_CLASS (nm_strongswan_plugin_parent_class)->dispose (obj);
! 1068: }
! 1069:
! 1070: /**
1.1 misho 1071: * Class constructor
1072: */
1073: static void nm_strongswan_plugin_class_init(
1074: NMStrongswanPluginClass *strongswan_class)
1075: {
1076: NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
1077:
1078: parent_class->connect = connect_;
1079: parent_class->need_secrets = need_secrets;
1080: parent_class->disconnect = disconnect;
1.1.1.2 ! misho 1081: G_OBJECT_CLASS(strongswan_class)->dispose = nm_strongswan_plugin_dispose;
1.1 misho 1082: }
1083:
1084: /**
1085: * Object constructor
1086: */
1087: NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
1088: nm_handler_t *handler)
1089: {
1090: GError *error = NULL;
1091:
1092: NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
1093: NM_TYPE_STRONGSWAN_PLUGIN,
1094: NULL,
1095: &error,
1096: NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
1097: NULL);
1098:
1099: if (plugin)
1100: {
1101: NMStrongswanPluginPrivate *priv;
1102:
1103: /* the rest of the initialization happened in _init above */
1104: priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
1105: priv->creds = creds;
1106: priv->handler = handler;
1107: }
1108: else
1109: {
1110: g_warning ("Failed to initialize a plugin instance: %s", error->message);
1111: g_error_free (error);
1112: }
1113:
1114: return plugin;
1115: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>