]>
Commit | Line | Data |
---|---|---|
6dbce9c8 | 1 | /* |
9a71b721 LR |
2 | * Copyright (C) 2017 Lubomir Rintel |
3 | * | |
bc3eda99 | 4 | * Copyright (C) 2013-2020 Tobias Brunner |
3ab0e8a0 | 5 | * Copyright (C) 2008-2009 Martin Willi |
1b671669 | 6 | * HSR Hochschule fuer Technik Rapperswil |
6dbce9c8 MW |
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. | |
6dbce9c8 MW |
17 | */ |
18 | ||
6dbce9c8 MW |
19 | #include "nm_service.h" |
20 | ||
21 | #include <daemon.h> | |
2e7cc07e | 22 | #include <networking/host.h> |
6dbce9c8 MW |
23 | #include <utils/identification.h> |
24 | #include <config/peer_cfg.h> | |
0ed6b7a7 | 25 | #include <credentials/certificates/x509.h> |
6dbce9c8 MW |
26 | |
27 | #include <stdio.h> | |
28 | ||
6dbce9c8 MW |
29 | /** |
30 | * Private data of NMStrongswanPlugin | |
31 | */ | |
32 | typedef struct { | |
3ab0e8a0 | 33 | /* implements bus listener interface */ |
a985db3f | 34 | listener_t listener; |
3ab0e8a0 | 35 | /* IKE_SA we are listening on */ |
6dbce9c8 | 36 | ike_sa_t *ike_sa; |
3ab0e8a0 | 37 | /* backref to public plugin */ |
9a71b721 | 38 | NMVpnServicePlugin *plugin; |
3ab0e8a0 | 39 | /* credentials to use for authentication */ |
ec249871 | 40 | nm_creds_t *creds; |
3ab0e8a0 MW |
41 | /* attribute handler for DNS/NBNS server information */ |
42 | nm_handler_t *handler; | |
69b80589 MW |
43 | /* name of the connection */ |
44 | char *name; | |
6dbce9c8 MW |
45 | } NMStrongswanPluginPrivate; |
46 | ||
18bee930 TB |
47 | G_DEFINE_TYPE_WITH_PRIVATE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_PLUGIN) |
48 | ||
6dbce9c8 | 49 | #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \ |
18bee930 TB |
50 | ((NMStrongswanPluginPrivate*) \ |
51 | nm_strongswan_plugin_get_instance_private (o)) | |
6dbce9c8 | 52 | |
3ab0e8a0 | 53 | /** |
05b7f1cb | 54 | * Convert an address chunk to a GValue |
3ab0e8a0 | 55 | */ |
05b7f1cb TB |
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, | |
3ab0e8a0 MW |
90 | configuration_attribute_type_t type) |
91 | { | |
9a71b721 | 92 | GVariantBuilder builder; |
3ab0e8a0 | 93 | enumerator_t *enumerator; |
0af3a4f1 | 94 | chunk_t *chunk; |
7daf5226 | 95 | |
05b7f1cb | 96 | g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type)); |
9a71b721 | 97 | |
3ab0e8a0 | 98 | enumerator = handler->create_enumerator(handler, type); |
3ab0e8a0 MW |
99 | while (enumerator->enumerate(enumerator, &chunk)) |
100 | { | |
05b7f1cb | 101 | g_variant_builder_add_value (&builder, addr_to_variant(*chunk)); |
3ab0e8a0 MW |
102 | } |
103 | enumerator->destroy(enumerator); | |
7daf5226 | 104 | |
9a71b721 | 105 | return g_variant_builder_end (&builder); |
3ab0e8a0 MW |
106 | } |
107 | ||
6dbce9c8 | 108 | /** |
05b7f1cb | 109 | * Signal IP config to NM, set connection as established |
6dbce9c8 | 110 | */ |
05b7f1cb TB |
111 | static void signal_ip_config(NMVpnServicePlugin *plugin, |
112 | ike_sa_t *ike_sa, child_sa_t *child_sa) | |
6dbce9c8 | 113 | { |
18bee930 TB |
114 | NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin; |
115 | NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub); | |
05b7f1cb TB |
116 | GVariantBuilder builder, ip4builder, ip6builder; |
117 | GVariant *ip4config, *ip6config; | |
9cf09eca | 118 | enumerator_t *enumerator; |
05b7f1cb | 119 | host_t *me, *other, *vip4 = NULL, *vip6 = NULL; |
3ab0e8a0 | 120 | nm_handler_t *handler; |
7daf5226 | 121 | |
9a71b721 | 122 | g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); |
05b7f1cb TB |
123 | g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT); |
124 | g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT); | |
9a71b721 | 125 | |
c15eea73 | 126 | handler = priv->handler; |
7daf5226 | 127 | |
f201d86d | 128 | /* NM apparently requires to know the gateway */ |
f201d86d | 129 | other = ike_sa->get_other_host(ike_sa); |
05b7f1cb TB |
130 | g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, |
131 | host_to_variant(other)); | |
f201d86d | 132 | |
05b7f1cb | 133 | /* pass the first virtual IPs we got or use the physical IP */ |
9cf09eca | 134 | enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); |
05b7f1cb | 135 | while (enumerator->enumerate(enumerator, &me)) |
9cf09eca | 136 | { |
05b7f1cb TB |
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 | } | |
9cf09eca TB |
152 | } |
153 | enumerator->destroy(enumerator); | |
05b7f1cb TB |
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 | } | |
7daf5226 | 167 | |
05b7f1cb TB |
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 | } | |
3651c8dc | 187 | |
05b7f1cb TB |
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 | } | |
7daf5226 | 200 | |
05b7f1cb TB |
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 | } | |
9a71b721 | 212 | |
05b7f1cb TB |
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 | } | |
7daf5226 | 224 | |
3ab0e8a0 | 225 | handler->reset(handler); |
7daf5226 | 226 | |
05b7f1cb TB |
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 | } | |
6dbce9c8 MW |
236 | } |
237 | ||
238 | /** | |
a985db3f | 239 | * signal failure to NM, connecting failed |
6dbce9c8 | 240 | */ |
9a71b721 | 241 | static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure) |
a985db3f | 242 | { |
18bee930 TB |
243 | NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin; |
244 | nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub)->handler; | |
7daf5226 | 245 | |
3ab0e8a0 | 246 | handler->reset(handler); |
7daf5226 | 247 | |
9a71b721 | 248 | nm_vpn_service_plugin_failure(plugin, failure); |
a985db3f MW |
249 | } |
250 | ||
3d2f5ae0 TB |
251 | METHOD(listener_t, ike_state_change, bool, |
252 | NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, ike_sa_state_t state) | |
6dbce9c8 | 253 | { |
3d2f5ae0 | 254 | if (this->ike_sa == ike_sa && state == IKE_DESTROYING) |
6dbce9c8 | 255 | { |
3d2f5ae0 | 256 | signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED); |
a985db3f MW |
257 | } |
258 | return TRUE; | |
259 | } | |
260 | ||
3d2f5ae0 TB |
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) | |
a985db3f | 264 | { |
3d2f5ae0 | 265 | if (this->ike_sa == ike_sa && state == CHILD_DESTROYING) |
bad99d5a | 266 | { |
3d2f5ae0 | 267 | signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); |
bad99d5a MW |
268 | } |
269 | return TRUE; | |
270 | } | |
a985db3f | 271 | |
3d2f5ae0 TB |
272 | METHOD(listener_t, ike_rekey, bool, |
273 | NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new) | |
bad99d5a | 274 | { |
3d2f5ae0 TB |
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 | } | |
7daf5226 | 291 | |
3d2f5ae0 TB |
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) | |
a985db3f | 311 | { |
bad99d5a MW |
312 | if (up) |
313 | { /* disable initiate-failure-detection hooks */ | |
3d2f5ae0 TB |
314 | this->listener.ike_state_change = NULL; |
315 | this->listener.child_state_change = NULL; | |
316 | signal_ip_config(this->plugin, ike_sa, child_sa); | |
bad99d5a MW |
317 | } |
318 | else | |
a985db3f | 319 | { |
3d2f5ae0 TB |
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); | |
6dbce9c8 MW |
325 | } |
326 | } | |
327 | return TRUE; | |
328 | } | |
329 | ||
8bec0f51 MW |
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 | ||
bc3eda99 TB |
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 | { | |
ff8f6b15 | 390 | identification_t *id = NULL; |
bc3eda99 TB |
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 | { | |
ff8f6b15 | 405 | id = find_smartcard_key(priv, pin); |
bc3eda99 | 406 | } |
ff8f6b15 | 407 | if (!id) |
bc3eda99 TB |
408 | { |
409 | g_set_error(err, NM_VPN_PLUGIN_ERROR, | |
410 | NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, | |
ff8f6b15 | 411 | "No usable smartcard certificate found."); |
bc3eda99 TB |
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 | { | |
ff8f6b15 TB |
475 | id = cert->get_subject(cert); |
476 | id = id->clone(id); | |
bc3eda99 TB |
477 | priv->creds->set_cert_and_key(priv->creds, cert, private); |
478 | } | |
479 | else | |
480 | { | |
481 | DESTROY_IF(cert); | |
482 | return FALSE; | |
483 | } | |
484 | } | |
ff8f6b15 TB |
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 | } | |
bc3eda99 TB |
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 | } | |
ff8f6b15 TB |
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); | |
bc3eda99 TB |
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 | { | |
ff8f6b15 | 532 | identification_t *user = NULL, *id = NULL; |
bc3eda99 TB |
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); | |
ff8f6b15 TB |
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) | |
bc3eda99 TB |
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); | |
ff8f6b15 | 565 | id->destroy(id); |
bc3eda99 TB |
566 | return FALSE; |
567 | } | |
ff8f6b15 | 568 | priv->creds->set_username_password(priv->creds, id, (char*)str); |
bc3eda99 TB |
569 | } |
570 | else | |
571 | { | |
ff8f6b15 | 572 | priv->creds->set_username_password(priv->creds, user, (char*)str); |
bc3eda99 TB |
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")); | |
ff8f6b15 TB |
581 | auth->add(auth, AUTH_RULE_EAP_IDENTITY, user); |
582 | auth->add(auth, AUTH_RULE_IDENTITY, id); | |
bc3eda99 TB |
583 | peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); |
584 | return TRUE; | |
585 | } | |
586 | ||
6dbce9c8 MW |
587 | /** |
588 | * Connect function called from NM via DBUS | |
589 | */ | |
9a71b721 | 590 | static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection, |
6dbce9c8 MW |
591 | GError **err) |
592 | { | |
18bee930 | 593 | NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin; |
69b80589 MW |
594 | NMStrongswanPluginPrivate *priv; |
595 | NMSettingConnection *conn; | |
9a71b721 | 596 | NMSettingVpn *vpn; |
4ac68f02 | 597 | enumerator_t *enumerator; |
bc3eda99 TB |
598 | identification_t *gateway = NULL; |
599 | const char *str, *method; | |
9486a2e5 | 600 | bool virtual, proposal; |
4ac68f02 | 601 | proposal_t *prop; |
6dbce9c8 MW |
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; | |
a44bb934 | 607 | auth_cfg_t *auth; |
a88aae3d | 608 | certificate_t *cert = NULL; |
0ed6b7a7 | 609 | x509_t *x509; |
bc3eda99 | 610 | bool loose_gateway_id = FALSE; |
9486a2e5 TB |
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 | }; | |
2ba5dadb TB |
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 | }; | |
8a00a845 TB |
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, | |
e75f4237 | 635 | }; |
7daf5226 | 636 | |
6dbce9c8 MW |
637 | /** |
638 | * Read parameters | |
639 | */ | |
18bee930 | 640 | priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub); |
69b80589 MW |
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))); | |
9486a2e5 TB |
654 | ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address"); |
655 | if (!ike.remote || !*ike.remote) | |
6dbce9c8 MW |
656 | { |
657 | g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, | |
323f9f99 | 658 | "Gateway address missing."); |
6dbce9c8 MW |
659 | return FALSE; |
660 | } | |
60777574 TB |
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 | } | |
69b80589 | 666 | str = nm_setting_vpn_get_data_item(vpn, "virtual"); |
8a00a845 | 667 | virtual = streq(str, "yes"); |
69b80589 | 668 | str = nm_setting_vpn_get_data_item(vpn, "encap"); |
9486a2e5 | 669 | ike.force_encap = streq(str, "yes"); |
69b80589 | 670 | str = nm_setting_vpn_get_data_item(vpn, "ipcomp"); |
749ac175 | 671 | child.options |= streq(str, "yes") ? OPT_IPCOMP : 0; |
7daf5226 | 672 | |
ec249871 MW |
673 | /** |
674 | * Register credentials | |
675 | */ | |
69b80589 | 676 | priv->creds->clear(priv->creds); |
7daf5226 | 677 | |
0ed6b7a7 | 678 | /* gateway/CA cert */ |
69b80589 | 679 | str = nm_setting_vpn_get_data_item(vpn, "certificate"); |
ec249871 MW |
680 | if (str) |
681 | { | |
ec249871 MW |
682 | cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, |
683 | BUILD_FROM_FILE, str, BUILD_END); | |
85af7a89 MW |
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); | |
ec249871 | 692 | } |
85af7a89 | 693 | else |
a88aae3d | 694 | { |
85af7a89 | 695 | /* no certificate defined, fall back to system-wide CA certificates */ |
97c74b56 TB |
696 | priv->creds->load_ca_dir(priv->creds, lib->settings->get_str( |
697 | lib->settings, "charon-nm.ca_dir", NM_CA_DIR)); | |
a88aae3d | 698 | } |
19e64e10 TB |
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) | |
85af7a89 | 715 | { |
19e64e10 TB |
716 | /* if the user configured a CA certificate (or an invalid identity), |
717 | * we use the IP/hostname of the server */ | |
9486a2e5 | 718 | gateway = identification_create_from_string(ike.remote); |
e6fcc172 | 719 | loose_gateway_id = TRUE; |
0ed6b7a7 | 720 | } |
19e64e10 | 721 | DBG1(DBG_CFG, "using gateway identity '%Y'", gateway); |
7daf5226 | 722 | |
6dbce9c8 MW |
723 | /** |
724 | * Set up configurations | |
725 | */ | |
9486a2e5 | 726 | ike_cfg = ike_cfg_create(&ike); |
4ac68f02 D |
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); | |
4ac68f02 D |
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 | } | |
2ba5dadb TB |
756 | |
757 | peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer); | |
101d26ba MW |
758 | if (virtual) |
759 | { | |
5538e290 TB |
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)); | |
101d26ba | 762 | } |
bc3eda99 TB |
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 | ||
a44bb934 | 800 | auth = auth_cfg_create(); |
393e0167 | 801 | if (streq(method, "psk")) |
5ae822cf TB |
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 | } | |
0ed6b7a7 | 809 | auth->add(auth, AUTH_RULE_IDENTITY, gateway); |
e6fcc172 | 810 | auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id); |
a44bb934 | 811 | peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); |
7daf5226 | 812 | |
8a00a845 | 813 | child_cfg = child_cfg_create(priv->name, &child); |
4ac68f02 D |
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 | } | |
b81d8cd3 | 840 | ts = traffic_selector_create_dynamic(0, 0, 65535); |
6dbce9c8 | 841 | child_cfg->add_traffic_selector(child_cfg, TRUE, ts); |
5538e290 TB |
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); | |
6dbce9c8 MW |
845 | child_cfg->add_traffic_selector(child_cfg, FALSE, ts); |
846 | peer_cfg->add_child_cfg(peer_cfg, child_cfg); | |
7daf5226 | 847 | |
6dbce9c8 | 848 | /** |
bad99d5a | 849 | * Prepare IKE_SA |
6dbce9c8 MW |
850 | */ |
851 | ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, | |
852 | peer_cfg); | |
3d54ae94 MW |
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 | } | |
6dbce9c8 MW |
860 | if (!ike_sa->get_peer_cfg(ike_sa)) |
861 | { | |
862 | ike_sa->set_peer_cfg(ike_sa, peer_cfg); | |
863 | } | |
41faec07 | 864 | peer_cfg->destroy(peer_cfg); |
7daf5226 | 865 | |
bad99d5a MW |
866 | /** |
867 | * Register listener, enable initiate-failure-detection hooks | |
868 | */ | |
69b80589 | 869 | priv->ike_sa = ike_sa; |
3d2f5ae0 TB |
870 | priv->listener.ike_state_change = _ike_state_change; |
871 | priv->listener.child_state_change = _child_state_change; | |
7daf5226 | 872 | |
bad99d5a MW |
873 | /** |
874 | * Initiate | |
875 | */ | |
3d54ae94 | 876 | child_cfg->get_ref(child_cfg); |
a13c013b | 877 | if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) |
6dbce9c8 MW |
878 | { |
879 | charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); | |
7daf5226 | 880 | |
6dbce9c8 | 881 | g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, |
323f9f99 | 882 | "Initiating failed."); |
6dbce9c8 MW |
883 | return FALSE; |
884 | } | |
6dbce9c8 MW |
885 | charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); |
886 | return TRUE; | |
887 | } | |
888 | ||
889 | /** | |
7daf5226 | 890 | * NeedSecrets called from NM via DBUS |
6dbce9c8 | 891 | */ |
9a71b721 LR |
892 | static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection, |
893 | const char **setting_name, GError **error) | |
6dbce9c8 | 894 | { |
9a71b721 | 895 | NMSettingVpn *settings; |
bc3eda99 TB |
896 | const char *method, *cert_source, *path; |
897 | bool need_secret = FALSE; | |
7daf5226 | 898 | |
ec249871 MW |
899 | settings = NM_SETTING_VPN(nm_connection_get_setting(connection, |
900 | NM_TYPE_SETTING_VPN)); | |
d7625f09 | 901 | method = nm_setting_vpn_get_data_item(settings, "method"); |
aff26a62 | 902 | if (method) |
ec249871 | 903 | { |
bc3eda99 TB |
904 | if (streq(method, "cert") || |
905 | streq(method, "eap-tls") || | |
906 | streq(method, "key") || | |
907 | streq(method, "agent") || | |
908 | streq(method, "smartcard")) | |
aff26a62 | 909 | { |
bc3eda99 TB |
910 | cert_source = nm_setting_vpn_get_data_item(settings, "cert-source"); |
911 | if (!cert_source) | |
aff26a62 | 912 | { |
bc3eda99 | 913 | cert_source = method; |
aff26a62 | 914 | } |
bc3eda99 | 915 | if (streq(cert_source, "agent")) |
aff26a62 | 916 | { |
bc3eda99 | 917 | need_secret = !nm_setting_vpn_get_secret(settings, "agent"); |
aff26a62 | 918 | } |
bc3eda99 | 919 | else if (streq(cert_source, "smartcard")) |
1d03954a | 920 | { |
bc3eda99 TB |
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) | |
c489c588 | 928 | { |
bc3eda99 TB |
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 | } | |
c489c588 | 943 | } |
1d03954a MW |
944 | } |
945 | } | |
bc3eda99 TB |
946 | else if (streq(method, "eap") || |
947 | streq(method, "psk")) | |
8bec0f51 | 948 | { |
bc3eda99 | 949 | need_secret = !nm_setting_vpn_get_secret(settings, "password"); |
8bec0f51 | 950 | } |
ec249871 | 951 | } |
aff26a62 | 952 | *setting_name = NM_SETTING_VPN_SETTING_NAME; |
bc3eda99 | 953 | return need_secret; |
6dbce9c8 MW |
954 | } |
955 | ||
956 | /** | |
9a71b721 | 957 | * The actual disconnection |
6dbce9c8 | 958 | */ |
9a71b721 | 959 | static gboolean do_disconnect(gpointer plugin) |
6dbce9c8 | 960 | { |
69b80589 | 961 | NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); |
6dbce9c8 MW |
962 | enumerator_t *enumerator; |
963 | ike_sa_t *ike_sa; | |
964 | u_int id; | |
7daf5226 | 965 | |
69b80589 | 966 | /* our ike_sa pointer might be invalid, lookup sa */ |
69c3eca0 MW |
967 | enumerator = charon->controller->create_ike_sa_enumerator( |
968 | charon->controller, TRUE); | |
6dbce9c8 MW |
969 | while (enumerator->enumerate(enumerator, &ike_sa)) |
970 | { | |
69b80589 | 971 | if (priv->ike_sa == ike_sa) |
6dbce9c8 MW |
972 | { |
973 | id = ike_sa->get_unique_id(ike_sa); | |
974 | enumerator->destroy(enumerator); | |
7b729097 | 975 | charon->controller->terminate_ike(charon->controller, id, FALSE, |
8e3f14ba | 976 | controller_cb_empty, NULL, 0); |
d5d83756 TB |
977 | |
978 | /* clear secrets as we are asked for new secrets (where we'd find | |
979 | * the cached secrets from earlier connections) before we clear | |
980 | * them in connect() */ | |
981 | priv->creds->clear(priv->creds); | |
9a71b721 | 982 | return FALSE; |
6dbce9c8 MW |
983 | } |
984 | } | |
985 | enumerator->destroy(enumerator); | |
7daf5226 | 986 | |
9a71b721 | 987 | g_debug("Connection not found."); |
6dbce9c8 MW |
988 | return FALSE; |
989 | } | |
990 | ||
9a71b721 LR |
991 | /** |
992 | * Disconnect called from NM via DBUS | |
993 | */ | |
994 | static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err) | |
995 | { | |
9a71b721 LR |
996 | /* enqueue the actual disconnection, because we may be called in |
997 | * response to a listener_t callback and the SA enumeration would | |
998 | * possibly deadlock. */ | |
999 | g_idle_add(do_disconnect, plugin); | |
1000 | ||
1001 | return TRUE; | |
1002 | } | |
1003 | ||
6dbce9c8 MW |
1004 | /** |
1005 | * Initializer | |
1006 | */ | |
1007 | static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin) | |
1008 | { | |
69b80589 | 1009 | NMStrongswanPluginPrivate *priv; |
7daf5226 | 1010 | |
69b80589 | 1011 | priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); |
9a71b721 | 1012 | priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin); |
b64f3336 | 1013 | memset(&priv->listener, 0, sizeof(listener_t)); |
3d2f5ae0 TB |
1014 | priv->listener.child_updown = _child_updown; |
1015 | priv->listener.ike_rekey = _ike_rekey; | |
1016 | priv->listener.ike_reestablish_pre = _ike_reestablish_pre; | |
1017 | priv->listener.ike_reestablish_post = _ike_reestablish_post; | |
5575aaf5 | 1018 | charon->bus->add_listener(charon->bus, &priv->listener); |
c15eea73 TB |
1019 | priv->name = NULL; |
1020 | } | |
1021 | ||
6dbce9c8 MW |
1022 | /** |
1023 | * Class constructor | |
1024 | */ | |
1025 | static void nm_strongswan_plugin_class_init( | |
1026 | NMStrongswanPluginClass *strongswan_class) | |
1027 | { | |
9a71b721 | 1028 | NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class); |
7daf5226 | 1029 | |
6dbce9c8 MW |
1030 | parent_class->connect = connect_; |
1031 | parent_class->need_secrets = need_secrets; | |
1032 | parent_class->disconnect = disconnect; | |
1033 | } | |
1034 | ||
1035 | /** | |
1036 | * Object constructor | |
1037 | */ | |
3ab0e8a0 MW |
1038 | NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds, |
1039 | nm_handler_t *handler) | |
6dbce9c8 | 1040 | { |
9a71b721 LR |
1041 | GError *error = NULL; |
1042 | ||
1043 | NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new ( | |
ec249871 | 1044 | NM_TYPE_STRONGSWAN_PLUGIN, |
9a71b721 LR |
1045 | NULL, |
1046 | &error, | |
1047 | NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN, | |
ec249871 | 1048 | NULL); |
9a71b721 | 1049 | |
1b9f6c24 MW |
1050 | if (plugin) |
1051 | { | |
69b80589 | 1052 | NMStrongswanPluginPrivate *priv; |
7daf5226 | 1053 | |
c15eea73 | 1054 | /* the rest of the initialization happened in _init above */ |
69b80589 MW |
1055 | priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); |
1056 | priv->creds = creds; | |
1057 | priv->handler = handler; | |
1b9f6c24 | 1058 | } |
9a71b721 LR |
1059 | else |
1060 | { | |
1061 | g_warning ("Failed to initialize a plugin instance: %s", error->message); | |
1062 | g_error_free (error); | |
1063 | } | |
1064 | ||
ec249871 | 1065 | return plugin; |
6dbce9c8 | 1066 | } |