2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2008-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include <nm-setting-vpn.h>
18 #include <nm-setting-connection.h>
19 #include "nm_service.h"
22 #include <networking/host.h>
23 #include <utils/identification.h>
24 #include <config/peer_cfg.h>
25 #include <credentials/certificates/x509.h>
26 #include <networking/tun_device.h>
30 G_DEFINE_TYPE(NMStrongswanPlugin
, nm_strongswan_plugin
, NM_TYPE_VPN_PLUGIN
)
33 * Private data of NMStrongswanPlugin
36 /* implements bus listener interface */
38 /* IKE_SA we are listening on */
40 /* backref to public plugin */
42 /* credentials to use for authentication */
44 /* attribute handler for DNS/NBNS server information */
45 nm_handler_t
*handler
;
46 /* dummy TUN device */
48 /* name of the connection */
50 } NMStrongswanPluginPrivate
;
52 #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
53 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
54 NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
57 * convert enumerated handler chunks to a UINT_ARRAY GValue
59 static GValue
* handler_to_val(nm_handler_t
*handler
,
60 configuration_attribute_type_t type
)
64 enumerator_t
*enumerator
;
67 enumerator
= handler
->create_enumerator(handler
, type
);
68 array
= g_array_new (FALSE
, TRUE
, sizeof (guint32
));
69 while (enumerator
->enumerate(enumerator
, &chunk
))
71 g_array_append_val (array
, *(u_int32_t
*)chunk
.ptr
);
73 enumerator
->destroy(enumerator
);
74 val
= g_slice_new0 (GValue
);
75 g_value_init (val
, DBUS_TYPE_G_UINT_ARRAY
);
76 g_value_set_boxed (val
, array
);
82 * signal IPv4 config to NM, set connection as established
84 static void signal_ipv4_config(NMVPNPlugin
*plugin
,
85 ike_sa_t
*ike_sa
, child_sa_t
*child_sa
)
87 NMStrongswanPluginPrivate
*priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
91 nm_handler_t
*handler
;
93 config
= g_hash_table_new(g_str_hash
, g_str_equal
);
94 me
= ike_sa
->get_my_host(ike_sa
);
95 handler
= priv
->handler
;
97 /* NM requires a tundev, but netkey does not use one. Passing the physical
98 * interface does not work, as NM fiddles around with it. So we pass a dummy
99 * TUN device along for NM to play with... */
100 val
= g_slice_new0 (GValue
);
101 g_value_init (val
, G_TYPE_STRING
);
102 g_value_set_string (val
, priv
->tun
->get_name(priv
->tun
));
103 g_hash_table_insert (config
, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV
, val
);
105 val
= g_slice_new0(GValue
);
106 g_value_init(val
, G_TYPE_UINT
);
107 g_value_set_uint(val
, *(u_int32_t
*)me
->get_address(me
).ptr
);
108 g_hash_table_insert(config
, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS
, val
);
110 val
= g_slice_new0(GValue
);
111 g_value_init(val
, G_TYPE_UINT
);
112 g_value_set_uint(val
, me
->get_address(me
).len
* 8);
113 g_hash_table_insert(config
, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX
, val
);
115 val
= handler_to_val(handler
, INTERNAL_IP4_DNS
);
116 g_hash_table_insert(config
, NM_VPN_PLUGIN_IP4_CONFIG_DNS
, val
);
118 val
= handler_to_val(handler
, INTERNAL_IP4_NBNS
);
119 g_hash_table_insert(config
, NM_VPN_PLUGIN_IP4_CONFIG_NBNS
, val
);
121 handler
->reset(handler
);
123 nm_vpn_plugin_set_ip4_config(plugin
, config
);
127 * signal failure to NM, connecting failed
129 static void signal_failure(NMVPNPlugin
*plugin
, NMVPNPluginFailure failure
)
131 nm_handler_t
*handler
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
)->handler
;
133 handler
->reset(handler
);
135 /* TODO: NM does not handle this failure!? */
136 nm_vpn_plugin_failure(plugin
, failure
);
137 nm_vpn_plugin_set_state(plugin
, NM_VPN_SERVICE_STATE_STOPPED
);
141 * Implementation of listener_t.ike_state_change
143 static bool ike_state_change(listener_t
*listener
, ike_sa_t
*ike_sa
,
144 ike_sa_state_t state
)
146 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
148 if (private->ike_sa
== ike_sa
&& state
== IKE_DESTROYING
)
150 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED
);
157 * Implementation of listener_t.child_state_change
159 static bool child_state_change(listener_t
*listener
, ike_sa_t
*ike_sa
,
160 child_sa_t
*child_sa
, child_sa_state_t state
)
162 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
164 if (private->ike_sa
== ike_sa
&& state
== CHILD_DESTROYING
)
166 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
173 * Implementation of listener_t.child_updown
175 static bool child_updown(listener_t
*listener
, ike_sa_t
*ike_sa
,
176 child_sa_t
*child_sa
, bool up
)
178 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
180 if (private->ike_sa
== ike_sa
)
183 { /* disable initiate-failure-detection hooks */
184 private->listener
.ike_state_change
= NULL
;
185 private->listener
.child_state_change
= NULL
;
186 signal_ipv4_config(private->plugin
, ike_sa
, child_sa
);
190 signal_failure(private->plugin
, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED
);
198 * Implementation of listener_t.ike_rekey
200 static bool ike_rekey(listener_t
*listener
, ike_sa_t
*old
, ike_sa_t
*new)
202 NMStrongswanPluginPrivate
*private = (NMStrongswanPluginPrivate
*)listener
;
204 if (private->ike_sa
== old
)
205 { /* follow a rekeyed IKE_SA */
206 private->ike_sa
= new;
212 * Find a certificate for which we have a private key on a smartcard
214 static identification_t
*find_smartcard_key(NMStrongswanPluginPrivate
*priv
,
217 enumerator_t
*enumerator
, *sans
;
218 identification_t
*id
= NULL
;
224 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
225 CERT_X509
, KEY_ANY
, NULL
, FALSE
);
226 while (enumerator
->enumerate(enumerator
, &cert
))
228 x509
= (x509_t
*)cert
;
230 /* there might be a lot of certificates, filter them by usage */
231 if ((x509
->get_flags(x509
) & X509_CLIENT_AUTH
) &&
232 !(x509
->get_flags(x509
) & X509_CA
))
234 keyid
= x509
->get_subjectKeyIdentifier(x509
);
237 /* try to find a private key by the certificate keyid */
238 priv
->creds
->set_pin(priv
->creds
, keyid
, pin
);
239 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
240 KEY_ANY
, BUILD_PKCS11_KEYID
, keyid
, BUILD_END
);
243 /* prefer a more convenient subjectAltName */
244 sans
= x509
->create_subjectAltName_enumerator(x509
);
245 if (!sans
->enumerate(sans
, &id
))
247 id
= cert
->get_subject(cert
);
252 DBG1(DBG_CFG
, "using smartcard certificate '%Y'", id
);
253 priv
->creds
->set_cert_and_key(priv
->creds
,
254 cert
->get_ref(cert
), key
);
260 enumerator
->destroy(enumerator
);
265 * Connect function called from NM via DBUS
267 static gboolean
connect_(NMVPNPlugin
*plugin
, NMConnection
*connection
,
270 NMStrongswanPluginPrivate
*priv
;
271 NMSettingConnection
*conn
;
273 identification_t
*user
= NULL
, *gateway
= NULL
;
274 const char *address
, *str
;
275 bool virtual, encap
, ipcomp
;
277 peer_cfg_t
*peer_cfg
;
278 child_cfg_t
*child_cfg
;
279 traffic_selector_t
*ts
;
282 auth_class_t auth_class
= AUTH_CLASS_EAP
;
283 certificate_t
*cert
= NULL
;
285 bool agent
= FALSE
, smartcard
= FALSE
, loose_gateway_id
= FALSE
;
286 lifetime_cfg_t lifetime
= {
288 .life
= 10800 /* 3h */,
289 .rekey
= 10200 /* 2h50min */,
290 .jitter
= 300 /* 5min */
297 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
298 conn
= NM_SETTING_CONNECTION(nm_connection_get_setting(connection
,
299 NM_TYPE_SETTING_CONNECTION
));
300 vpn
= NM_SETTING_VPN(nm_connection_get_setting(connection
,
301 NM_TYPE_SETTING_VPN
));
306 priv
->name
= strdup(nm_setting_connection_get_id(conn
));
307 DBG1(DBG_CFG
, "received initiate for NetworkManager connection %s",
310 nm_setting_to_string(NM_SETTING(vpn
)));
313 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
314 "Failed to create dummy TUN device.");
315 gateway
->destroy(gateway
);
318 address
= nm_setting_vpn_get_data_item(vpn
, "address");
319 if (!address
|| !*address
)
321 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
322 "Gateway address missing.");
325 str
= nm_setting_vpn_get_data_item(vpn
, "virtual");
326 virtual = str
&& streq(str
, "yes");
327 str
= nm_setting_vpn_get_data_item(vpn
, "encap");
328 encap
= str
&& streq(str
, "yes");
329 str
= nm_setting_vpn_get_data_item(vpn
, "ipcomp");
330 ipcomp
= str
&& streq(str
, "yes");
331 str
= nm_setting_vpn_get_data_item(vpn
, "method");
334 if (streq(str
, "psk"))
336 auth_class
= AUTH_CLASS_PSK
;
338 else if (streq(str
, "agent"))
340 auth_class
= AUTH_CLASS_PUBKEY
;
343 else if (streq(str
, "key"))
345 auth_class
= AUTH_CLASS_PUBKEY
;
347 else if (streq(str
, "smartcard"))
349 auth_class
= AUTH_CLASS_PUBKEY
;
355 * Register credentials
357 priv
->creds
->clear(priv
->creds
);
359 /* gateway/CA cert */
360 str
= nm_setting_vpn_get_data_item(vpn
, "certificate");
363 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
364 BUILD_FROM_FILE
, str
, BUILD_END
);
367 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
368 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
369 "Loading gateway certificate failed.");
372 priv
->creds
->add_certificate(priv
->creds
, cert
);
374 x509
= (x509_t
*)cert
;
375 if (!(x509
->get_flags(x509
) & X509_CA
))
376 { /* For a gateway certificate, we use the cert subject as identity. */
377 gateway
= cert
->get_subject(cert
);
378 gateway
= gateway
->clone(gateway
);
379 DBG1(DBG_CFG
, "using gateway certificate, identity '%Y'", gateway
);
384 /* no certificate defined, fall back to system-wide CA certificates */
385 priv
->creds
->load_ca_dir(priv
->creds
, NM_CA_DIR
);
389 /* If the user configured a CA certificate, we use the IP/DNS
390 * of the gateway as its identity. This identity will be used for
391 * certificate lookup and requires the configured IP/DNS to be
392 * included in the gateway certificate. */
393 gateway
= identification_create_from_string((char*)address
);
394 DBG1(DBG_CFG
, "using CA certificate, gateway identity '%Y'", gateway
);
395 loose_gateway_id
= TRUE
;
398 if (auth_class
== AUTH_CLASS_EAP
)
400 /* username/password authentication ... */
401 str
= nm_setting_vpn_get_data_item(vpn
, "user");
404 user
= identification_create_from_string((char*)str
);
405 str
= nm_setting_vpn_get_secret(vpn
, "password");
406 priv
->creds
->set_username_password(priv
->creds
, user
, (char*)str
);
410 if (auth_class
== AUTH_CLASS_PUBKEY
)
416 pin
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
419 user
= find_smartcard_key(priv
, pin
);
423 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
424 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
425 "no usable smartcard certificate found.");
426 gateway
->destroy(gateway
);
430 /* ... or certificate/private key authenitcation */
431 else if ((str
= nm_setting_vpn_get_data_item(vpn
, "usercert")))
433 public_key_t
*public;
434 private_key_t
*private = NULL
;
436 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
437 BUILD_FROM_FILE
, str
, BUILD_END
);
440 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
441 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
442 "Loading peer certificate failed.");
443 gateway
->destroy(gateway
);
447 str
= nm_setting_vpn_get_secret(vpn
, "agent");
450 public = cert
->get_public_key(cert
);
453 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
454 public->get_type(public),
455 BUILD_AGENT_SOCKET
, str
,
456 BUILD_PUBLIC_KEY
, public,
458 public->destroy(public);
462 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
463 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
464 "Connecting to SSH agent failed.");
467 /* ... or key file */
468 str
= nm_setting_vpn_get_data_item(vpn
, "userkey");
473 secret
= (char*)nm_setting_vpn_get_secret(vpn
, "password");
476 priv
->creds
->set_key_password(priv
->creds
, secret
);
478 private = lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
479 KEY_RSA
, BUILD_FROM_FILE
, str
, BUILD_END
);
482 g_set_error(err
, NM_VPN_PLUGIN_ERROR
,
483 NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
484 "Loading private key failed.");
489 user
= cert
->get_subject(cert
);
490 user
= user
->clone(user
);
491 priv
->creds
->set_cert_and_key(priv
->creds
, cert
, private);
496 gateway
->destroy(gateway
);
504 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS
,
505 "Configuration parameters missing.");
506 gateway
->destroy(gateway
);
511 * Set up configurations
513 ike_cfg
= ike_cfg_create(IKEV2
, TRUE
, encap
, "0.0.0.0", FALSE
,
514 charon
->socket
->get_port(charon
->socket
, FALSE
),
515 (char*)address
, FALSE
, IKEV2_UDP_PORT
,
516 FRAGMENTATION_NO
, 0);
517 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
518 peer_cfg
= peer_cfg_create(priv
->name
, ike_cfg
,
519 CERT_SEND_IF_ASKED
, UNIQUE_REPLACE
, 1, /* keyingtries */
520 36000, 0, /* rekey 10h, reauth none */
521 600, 600, /* jitter, over 10min */
522 TRUE
, FALSE
, /* mobike, aggressive */
523 0, 0, /* DPD delay, timeout */
524 FALSE
, NULL
, NULL
); /* mediation */
527 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_from_string("0.0.0.0", 0));
529 auth
= auth_cfg_create();
530 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, auth_class
);
531 auth
->add(auth
, AUTH_RULE_IDENTITY
, user
);
532 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, TRUE
);
533 auth
= auth_cfg_create();
534 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
535 auth
->add(auth
, AUTH_RULE_IDENTITY
, gateway
);
536 auth
->add(auth
, AUTH_RULE_IDENTITY_LOOSE
, loose_gateway_id
);
537 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, FALSE
);
539 child_cfg
= child_cfg_create(priv
->name
, &lifetime
,
540 NULL
, TRUE
, MODE_TUNNEL
, /* updown, hostaccess */
541 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, ipcomp
,
542 0, 0, NULL
, NULL
, 0);
543 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
544 ts
= traffic_selector_create_dynamic(0, 0, 65535);
545 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
546 ts
= traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE
,
548 "255.255.255.255", 65535);
549 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
550 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
555 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(charon
->ike_sa_manager
,
559 peer_cfg
->destroy(peer_cfg
);
560 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
561 "IKE version not supported.");
564 if (!ike_sa
->get_peer_cfg(ike_sa
))
566 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
568 peer_cfg
->destroy(peer_cfg
);
571 * Register listener, enable initiate-failure-detection hooks
573 priv
->ike_sa
= ike_sa
;
574 priv
->listener
.ike_state_change
= ike_state_change
;
575 priv
->listener
.child_state_change
= child_state_change
;
576 charon
->bus
->add_listener(charon
->bus
, &priv
->listener
);
581 child_cfg
->get_ref(child_cfg
);
582 if (ike_sa
->initiate(ike_sa
, child_cfg
, 0, NULL
, NULL
) != SUCCESS
)
584 charon
->bus
->remove_listener(charon
->bus
, &priv
->listener
);
585 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
587 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED
,
588 "Initiating failed.");
591 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
596 * NeedSecrets called from NM via DBUS
598 static gboolean
need_secrets(NMVPNPlugin
*plugin
, NMConnection
*connection
,
599 char **setting_name
, GError
**error
)
601 NMSettingVPN
*settings
;
602 const char *method
, *path
;
604 settings
= NM_SETTING_VPN(nm_connection_get_setting(connection
,
605 NM_TYPE_SETTING_VPN
));
606 method
= nm_setting_vpn_get_data_item(settings
, "method");
609 if (streq(method
, "eap"))
611 if (nm_setting_vpn_get_secret(settings
, "password"))
616 else if (streq(method
, "agent"))
618 if (nm_setting_vpn_get_secret(settings
, "agent"))
623 else if (streq(method
, "key"))
625 path
= nm_setting_vpn_get_data_item(settings
, "userkey");
630 /* try to load/decrypt the private key */
631 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
,
632 KEY_RSA
, BUILD_FROM_FILE
, path
, BUILD_END
);
640 else if (streq(method
, "smartcard"))
642 if (nm_setting_vpn_get_secret(settings
, "password"))
648 *setting_name
= NM_SETTING_VPN_SETTING_NAME
;
653 * Disconnect called from NM via DBUS
655 static gboolean
disconnect(NMVPNPlugin
*plugin
, GError
**err
)
657 NMStrongswanPluginPrivate
*priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
658 enumerator_t
*enumerator
;
662 /* our ike_sa pointer might be invalid, lookup sa */
663 enumerator
= charon
->controller
->create_ike_sa_enumerator(
664 charon
->controller
, TRUE
);
665 while (enumerator
->enumerate(enumerator
, &ike_sa
))
667 if (priv
->ike_sa
== ike_sa
)
669 id
= ike_sa
->get_unique_id(ike_sa
);
670 enumerator
->destroy(enumerator
);
671 charon
->controller
->terminate_ike(charon
->controller
, id
,
672 controller_cb_empty
, NULL
, 0);
676 enumerator
->destroy(enumerator
);
678 g_set_error(err
, NM_VPN_PLUGIN_ERROR
, NM_VPN_PLUGIN_ERROR_GENERAL
,
679 "Connection not found.");
686 static void nm_strongswan_plugin_init(NMStrongswanPlugin
*plugin
)
688 NMStrongswanPluginPrivate
*priv
;
690 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
691 priv
->plugin
= NM_VPN_PLUGIN(plugin
);
692 memset(&priv
->listener
, 0, sizeof(listener_t
));
693 priv
->listener
.child_updown
= child_updown
;
694 priv
->listener
.ike_rekey
= ike_rekey
;
695 priv
->tun
= tun_device_create(NULL
);
702 static void nm_strongswan_plugin_dispose(GObject
*obj
)
704 NMStrongswanPlugin
*plugin
;
705 NMStrongswanPluginPrivate
*priv
;
707 plugin
= NM_STRONGSWAN_PLUGIN(obj
);
708 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
711 priv
->tun
->destroy(priv
->tun
);
719 static void nm_strongswan_plugin_class_init(
720 NMStrongswanPluginClass
*strongswan_class
)
722 NMVPNPluginClass
*parent_class
= NM_VPN_PLUGIN_CLASS(strongswan_class
);
724 g_type_class_add_private(G_OBJECT_CLASS(strongswan_class
),
725 sizeof(NMStrongswanPluginPrivate
));
726 parent_class
->connect
= connect_
;
727 parent_class
->need_secrets
= need_secrets
;
728 parent_class
->disconnect
= disconnect
;
729 G_OBJECT_CLASS(strongswan_class
)->dispose
= nm_strongswan_plugin_dispose
;
735 NMStrongswanPlugin
*nm_strongswan_plugin_new(nm_creds_t
*creds
,
736 nm_handler_t
*handler
)
738 NMStrongswanPlugin
*plugin
= (NMStrongswanPlugin
*)g_object_new (
739 NM_TYPE_STRONGSWAN_PLUGIN
,
740 NM_VPN_PLUGIN_DBUS_SERVICE_NAME
, NM_DBUS_SERVICE_STRONGSWAN
,
744 NMStrongswanPluginPrivate
*priv
;
746 /* the rest of the initialization happened in _init above */
747 priv
= NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin
);
749 priv
->handler
= handler
;