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