1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* NetworkManager -- Network link manager
3    	 *
4    	 * This program is free software; you can redistribute it and/or modify
5    	 * it under the terms of the GNU General Public License as published by
6    	 * the Free Software Foundation; either version 2 of the License, or
7    	 * (at your option) any later version.
8    	 *
9    	 * This program is distributed in the hope that it will be useful,
10   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   	 * GNU General Public License for more details.
13   	 *
14   	 * You should have received a copy of the GNU General Public License along
15   	 * with this program; if not, write to the Free Software Foundation, Inc.,
16   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17   	 *
18   	 * Copyright (C) 2005 - 2013 Red Hat, Inc.
19   	 * Copyright (C) 2006 - 2008 Novell, Inc.
20   	 */
21   	
22   	#include <glib.h>
23   	#include <string.h>
24   	#include <sys/socket.h>
25   	#include <netinet/in.h>
26   	#include <arpa/inet.h>
27   	#include <errno.h>
28   	#include <stdlib.h>
29   	
30   	#include "NetworkManager.h"
31   	#include "NetworkManagerVPN.h"
32   	#include "nm-vpn-connection.h"
33   	#include "nm-setting-connection.h"
34   	#include "nm-setting-vpn.h"
35   	#include "nm-setting-ip4-config.h"
36   	#include "nm-dbus-manager.h"
37   	#include "nm-platform.h"
38   	#include "nm-logging.h"
39   	#include "nm-utils.h"
40   	#include "nm-active-connection.h"
41   	#include "nm-dbus-glib-types.h"
42   	#include "NetworkManagerUtils.h"
43   	#include "nm-glib-compat.h"
44   	#include "settings/nm-settings-connection.h"
45   	#include "nm-dispatcher.h"
46   	#include "nm-agent-manager.h"
47   	
48   	#include "nm-vpn-connection-glue.h"
49   	
50   	G_DEFINE_TYPE (NMVPNConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION)
51   	
52   	typedef enum {
53   		/* Only system secrets */
54   		SECRETS_REQ_SYSTEM = 0,
55   		/* All existing secrets including agent secrets */
56   		SECRETS_REQ_EXISTING = 1,
57   		/* New secrets required; ask an agent */
58   		SECRETS_REQ_NEW = 2,
59   		/* Plugin requests secrets interactively */
60   		SECRETS_REQ_INTERACTIVE = 3,
61   		/* Placeholder for bounds checking */
62   		SECRETS_REQ_LAST
63   	} SecretsReq;
64   	
65   	typedef struct {
66   		gboolean disposed;
67   	
68   		NMConnection *connection;
69   	
70   		guint32 secrets_id;
71   		SecretsReq secrets_idx;
72   		char *username;
73   	
74   		NMDevice *parent_dev;
75   		gulong device_monitor;
76   	
77   		NMVPNConnectionState vpn_state;
78   		NMVPNConnectionStateReason failure_reason;
79   		DBusGProxy *proxy;
80   		GHashTable *connect_hash;
81   		guint connect_timeout;
82   		gboolean has_ip4;
83   		NMIP4Config *ip4_config;
84   		guint32 ip4_internal_gw;
85   		guint32 ip4_external_gw;
86   		gboolean has_ip6;
87   		NMIP6Config *ip6_config;
88   		struct in6_addr *ip6_internal_gw;
89   		struct in6_addr *ip6_external_gw;
90   		char *ip_iface;
91   		int ip_ifindex;
92   		char *banner;
93   		guint32 mtu;
94   	} NMVPNConnectionPrivate;
95   	
96   	#define NM_VPN_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_CONNECTION, NMVPNConnectionPrivate))
97   	
98   	enum {
99   		VPN_STATE_CHANGED,
100  		INTERNAL_STATE_CHANGED,
101  	
102  		LAST_SIGNAL
103  	};
104  	
105  	static guint signals[LAST_SIGNAL] = { 0 };
106  	
107  	enum {
108  		PROP_0,
109  		PROP_VPN_STATE,
110  		PROP_BANNER,
111  		PROP_MASTER = 2000,
112  	
113  		LAST_PROP
114  	};
115  	
116  	static void get_secrets (NMVPNConnection *self,
117  	                         SecretsReq secrets_idx,
118  	                         const char **hints);
119  	
120  	static void plugin_interactive_secrets_required (DBusGProxy *proxy,
121  	                                                 const char *message,
122  	                                                 const char **secrets,
123  	                                                 gpointer user_data);
124  	
125  	static NMActiveConnectionState
126  	ac_state_from_vpn_state (NMVPNConnectionState vpn_state)
127  	{
128  		/* Set the NMActiveConnection state based on VPN state */
129  		switch (vpn_state) {
130  		case NM_VPN_CONNECTION_STATE_PREPARE:
131  		case NM_VPN_CONNECTION_STATE_NEED_AUTH:
132  		case NM_VPN_CONNECTION_STATE_CONNECT:
133  		case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
134  			return NM_ACTIVE_CONNECTION_STATE_ACTIVATING;
135  		case NM_VPN_CONNECTION_STATE_ACTIVATED:
136  			return NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
137  		case NM_VPN_CONNECTION_STATE_FAILED:
138  		case NM_VPN_CONNECTION_STATE_DISCONNECTED:
139  			return NM_ACTIVE_CONNECTION_STATE_DEACTIVATED;
140  		default:
141  			break;
142  		}
143  		return NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
144  	}
145  	
146  	static void
147  	call_plugin_disconnect (NMVPNConnection *self)
148  	{
149  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
150  		GError *error = NULL;
151  	
152  		if (priv->proxy) {
153  			dbus_g_proxy_call (priv->proxy, "Disconnect", &error,
154  			                   G_TYPE_INVALID,
155  			                   G_TYPE_INVALID);
156  			if (error)
157  				nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", error->message);
158  			g_clear_error (&error);
159  	
160  			g_object_unref (priv->proxy);
161  			priv->proxy = NULL;
162  		}
163  	}
164  	
165  	static void
166  	vpn_cleanup (NMVPNConnection *connection)
167  	{
168  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
169  	
170  		if (priv->ip_ifindex) {
171  			nm_platform_link_set_down (priv->ip_ifindex);
172  			nm_platform_route_flush (priv->ip_ifindex);
173  			nm_platform_address_flush (priv->ip_ifindex);
174  		}
175  	
176  		nm_device_set_vpn4_config (priv->parent_dev, NULL);
177  		nm_device_set_vpn6_config (priv->parent_dev, NULL);
178  	
179  		g_free (priv->banner);
180  		priv->banner = NULL;
181  	
182  		g_free (priv->ip_iface);
183  		priv->ip_iface = NULL;
184  		priv->ip_ifindex = 0;
185  	
186  		/* Clear out connection secrets to ensure that the settings service
187  		 * gets asked for them next time the connection is activated.
188  		 */
189  		if (priv->connection)
190  			nm_connection_clear_secrets (priv->connection);
191  	}
192  	
193  	static void
194  	nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
195  	                                 NMVPNConnectionState vpn_state,
196  	                                 NMVPNConnectionStateReason reason)
197  	{
198  		NMVPNConnectionPrivate *priv;
199  		NMVPNConnectionState old_vpn_state;
200  	
201  		g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
202  	
203  		priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
204  	
205  		if (vpn_state == priv->vpn_state)
206  			return;
207  	
208  		old_vpn_state = priv->vpn_state;
209  		priv->vpn_state = vpn_state;
210  	
211  		/* Update active connection base class state */
212  		nm_active_connection_set_state (NM_ACTIVE_CONNECTION (connection),
213  		                                ac_state_from_vpn_state (vpn_state));
214  	
215  		/* Clear any in-progress secrets request */
216  		if (priv->secrets_id) {
217  			nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id);
218  			priv->secrets_id = 0;
219  		}
220  	
221  		/* The connection gets destroyed by the VPN manager when it enters the
222  		 * disconnected/failed state, but we need to keep it around for a bit
223  		 * to send out signals and handle the dispatcher.  So ref it.
224  		 */
225  		g_object_ref (connection);
226  	
227  		g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, vpn_state, reason);
228  		g_signal_emit (connection, signals[INTERNAL_STATE_CHANGED], 0, vpn_state, old_vpn_state, reason);
229  		g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE);
230  	
231  		switch (vpn_state) {
232  		case NM_VPN_CONNECTION_STATE_NEED_AUTH:
233  			/* Do nothing; not part of 'default' because we don't want to touch
234  			 * priv->secrets_req as NEED_AUTH is re-entered during interactive
235  			 * secrets.
236  			 */
237  			break;
238  		case NM_VPN_CONNECTION_STATE_ACTIVATED:
239  			/* Secrets no longer needed now that we're connected */
240  			nm_connection_clear_secrets (priv->connection);
241  	
242  			/* Let dispatcher scripts know we're up and running */
243  			nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP,
244  			                        priv->connection,
245  			                        priv->parent_dev,
246  			                        priv->ip_iface,
247  			                        priv->ip4_config,
248  			                        priv->ip6_config,
249  			                        NULL,
250  			                        NULL);
251  			break;
252  		case NM_VPN_CONNECTION_STATE_FAILED:
253  		case NM_VPN_CONNECTION_STATE_DISCONNECTED:
254  			if (old_vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED) {
255  				/* Let dispatcher scripts know we're about to go down */
256  				nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN,
257  				                        priv->connection,
258  				                        priv->parent_dev,
259  				                        priv->ip_iface,
260  				                        NULL,
261  				                        NULL,
262  				                        NULL,
263  				                        NULL);
264  			}
265  	
266  			/* Tear down and clean up the connection */
267  			call_plugin_disconnect (connection);
268  			vpn_cleanup (connection);
269  			/* Fall through */
270  		default:
271  			priv->secrets_idx = SECRETS_REQ_SYSTEM;
272  			break;
273  		}
274  	
275  		g_object_unref (connection);
276  	}
277  	
278  	static void
279  	device_state_changed (NMDevice *device,
280  	                      NMDeviceState new_state,
281  	                      NMDeviceState old_state,
282  	                      NMDeviceStateReason reason,
283  	                      gpointer user_data)
284  	{
285  		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
286  	
287  		if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
288  			nm_vpn_connection_set_vpn_state (connection,
289  			                                 NM_VPN_CONNECTION_STATE_DISCONNECTED,
290  			                                 NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
291  		} else if (new_state == NM_DEVICE_STATE_FAILED) {
292  			nm_vpn_connection_set_vpn_state (connection,
293  			                                 NM_VPN_CONNECTION_STATE_FAILED,
294  			                                 NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
295  		}
296  	}
297  	
298  	static void
299  	add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw)
300  	{
301  		NMIP4Config *parent_config;
302  		guint32 parent_gw;
303  		NMPlatformIP4Route route;
304  		NMIP4Config *vpn4_config;
305  	
306  		g_return_if_fail (NM_IS_DEVICE (parent_device));
307  		g_return_if_fail (vpn_gw != 0);
308  	
309  		/* Set up a route to the VPN gateway's public IP address through the default
310  		 * network device if the VPN gateway is on a different subnet.
311  		 */
312  	
313  		parent_config = nm_device_get_ip4_config (parent_device);
314  		g_return_if_fail (parent_config != NULL);
315  		parent_gw = nm_ip4_config_get_gateway (parent_config);
316  		if (!parent_gw)
317  			return;
318  	
319  		vpn4_config = nm_ip4_config_new ();
320  	
321  		memset (&route, 0, sizeof (route));
322  		route.network = vpn_gw;
323  		route.plen = 32;
324  		route.gateway = parent_gw;
325  	
326  		/* If the VPN gateway is in the same subnet as one of the parent device's
327  		 * IP addresses, don't add the host route to it, but a route through the
328  		 * parent device.
329  		 */
330  		if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32))
331  			route.gateway = 0;
332  	
333  		nm_ip4_config_add_route (vpn4_config, &route);
334  	
335  		/* Ensure there's a route to the parent device's gateway through the
336  		 * parent device, since if the VPN claims the default route and the VPN
337  		 * routes include a subnet that matches the parent device's subnet,
338  		 * the parent device's gateway would get routed through the VPN and fail.
339  		 */
340  		memset (&route, 0, sizeof (route));
341  		route.network = parent_gw;
342  		route.plen = 32;
343  	
344  		nm_ip4_config_add_route (vpn4_config, &route);
345  	
346  		nm_device_set_vpn4_config (parent_device, vpn4_config);
347  		g_object_unref (vpn4_config);
348  	}
349  	
350  	static void
351  	add_ip6_vpn_gateway_route (NMDevice *parent_device,
352  	                           const struct in6_addr *vpn_gw)
353  	{
354  		NMIP6Config *parent_config;
355  		const struct in6_addr *parent_gw;
356  		NMPlatformIP6Route route;
357  		NMIP6Config *vpn6_config;
358  	
359  		g_return_if_fail (NM_IS_DEVICE (parent_device));
360  		g_return_if_fail (vpn_gw != NULL);
361  	
362  		parent_config = nm_device_get_ip6_config (parent_device);
363  		g_return_if_fail (parent_config != NULL);
364  		parent_gw = nm_ip6_config_get_gateway (parent_config);
365  		if (!parent_gw)
366  			return;
367  	
368  		vpn6_config = nm_ip6_config_new ();
369  	
370  		memset (&route, 0, sizeof (route));
371  		route.network = *vpn_gw;
372  		route.plen = 128;
373  		route.gateway = *parent_gw;
374  	
375  		/* If the VPN gateway is in the same subnet as one of the parent device's
376  		 * IP addresses, don't add the host route to it, but a route through the
377  		 * parent device.
378  		 */
379  		if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128))
380  			route.gateway = in6addr_any;
381  	
382  		nm_ip6_config_add_route (vpn6_config, &route);
383  	
384  		/* Ensure there's a route to the parent device's gateway through the
385  		 * parent device, since if the VPN claims the default route and the VPN
386  		 * routes include a subnet that matches the parent device's subnet,
387  		 * the parent device's gateway would get routed through the VPN and fail.
388  		 */
389  		memset (&route, 0, sizeof (route));
390  		route.network = *parent_gw;
391  		route.plen = 128;
392  	
393  		nm_ip6_config_add_route (vpn6_config, &route);
394  	
395  		nm_device_set_vpn6_config (parent_device, vpn6_config);
396  		g_object_unref (vpn6_config);
397  	}
398  	
399  	NMVPNConnection *
400  	nm_vpn_connection_new (NMConnection *connection,
401  	                       NMDevice *parent_device,
402  	                       const char *specific_object,
403  	                       gboolean user_requested,
404  	                       gulong user_uid)
405  	{
406  		NMVPNConnection *self;
407  	
408  		g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
409  		g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
410  	
411  		self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
412  		                                         NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
413  		                                         NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device,
414  		                                         NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
415  		                                         NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested,
416  		                                         NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid,
417  		                                         NM_ACTIVE_CONNECTION_VPN, TRUE,
418  		                                         NULL);
419  		if (self)
420  			nm_active_connection_export (NM_ACTIVE_CONNECTION (self));
421  	
422  		return self;
423  	}
424  	
425  	static const char *
426  	nm_vpn_connection_get_service (NMVPNConnection *connection)
427  	{
428  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
429  		NMSettingVPN *s_vpn;
430  	
431  		s_vpn = nm_connection_get_setting_vpn (priv->connection);
432  		return nm_setting_vpn_get_service_type (s_vpn);
433  	}
434  	
435  	static void
436  	plugin_failed (DBusGProxy *proxy,
437  				   NMVPNPluginFailure plugin_failure,
438  				   gpointer user_data)
439  	{
440  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (user_data);
441  	
442  		nm_log_warn (LOGD_VPN, "VPN plugin failed: %d", plugin_failure);
443  	
444  		switch (plugin_failure) {
445  		case NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED:
446  			priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED;
447  			break;
448  		case NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG:
449  			priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID;
450  			break;
451  		default:
452  			priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN;
453  		}
454  	}
455  	
456  	static const char *
457  	vpn_state_to_string (NMVPNServiceState state)
458  	{
459  		switch (state) {
460  		case NM_VPN_SERVICE_STATE_INIT:
461  			return "init";
462  		case NM_VPN_SERVICE_STATE_SHUTDOWN:
463  			return "shutdown";
464  		case NM_VPN_SERVICE_STATE_STARTING:
465  			return "starting";
466  		case NM_VPN_SERVICE_STATE_STARTED:
467  			return "started";
468  		case NM_VPN_SERVICE_STATE_STOPPING:
469  			return "stopping";
470  		case NM_VPN_SERVICE_STATE_STOPPED:
471  			return "stopped";
472  		default:
473  			break;
474  		}
475  		return "unknown";
476  	}
477  	
478  	static void
479  	plugin_state_changed (DBusGProxy *proxy,
480  	                      NMVPNServiceState state,
481  	                      gpointer user_data)
482  	{
483  		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
484  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
485  	
486  		nm_log_info (LOGD_VPN, "VPN plugin state changed: %s (%d)",
487  		             vpn_state_to_string (state), state);
488  	
489  		if (state == NM_VPN_SERVICE_STATE_STOPPED) {
490  			/* Clear connection secrets to ensure secrets get requested each time the
491  			 * connection is activated.
492  			 */
493  			nm_connection_clear_secrets (priv->connection);
494  	
495  			switch (nm_vpn_connection_get_vpn_state (connection)) {
496  			case NM_VPN_CONNECTION_STATE_PREPARE:
497  			case NM_VPN_CONNECTION_STATE_NEED_AUTH:
498  			case NM_VPN_CONNECTION_STATE_CONNECT:
499  			case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
500  			case NM_VPN_CONNECTION_STATE_ACTIVATED:
501  				nm_log_info (LOGD_VPN, "VPN plugin state change reason: %d", priv->failure_reason);
502  				nm_vpn_connection_set_vpn_state (connection,
503  				                                 NM_VPN_CONNECTION_STATE_FAILED,
504  												 priv->failure_reason);
505  	
506  				/* Reset the failure reason */
507  				priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN;
508  				break;
509  			default:
510  				break;
511  			}
512  		}
513  	}
514  	
515  	static char addr_to_string_buf[INET6_ADDRSTRLEN + 1];
516  	
517  	static const char *
518  	ip_address_to_string (guint32 numeric)
519  	{
520  		guint32 temp_addr;
521  	
522  		memset (&addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
523  		temp_addr = numeric;
524  	
525  		if (inet_ntop (AF_INET, &temp_addr, addr_to_string_buf, INET_ADDRSTRLEN)) {
526  			return addr_to_string_buf;
527  		} else {
528  			nm_log_warn (LOGD_VPN, "error converting IP4 address 0x%X",
529  			             ntohl (temp_addr));
530  			return NULL;
531  		}
532  	}
533  	
534  	static const char *
535  	ip6_address_to_string (const struct in6_addr *addr)
536  	{
537  		memset (addr_to_string_buf, '\0', sizeof (addr_to_string_buf));
538  		if (inet_ntop (AF_INET6, addr, addr_to_string_buf, INET6_ADDRSTRLEN)) {
539  			return addr_to_string_buf;
540  		} else {
541  			nm_log_warn (LOGD_VPN, "error converting IP6 address");
542  			return NULL;
543  		}
544  	}
545  	
546  	static void
547  	print_vpn_config (NMVPNConnection *connection)
548  	{
549  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
550  		const NMPlatformIP4Address *address4;
551  		const NMPlatformIP6Address *address6;
552  		char *dns_domain = NULL;
553  		guint32 num, i;
554  	
555  		if (priv->ip4_external_gw) {
556  			nm_log_info (LOGD_VPN, "VPN Gateway: %s",
557  			             ip_address_to_string (priv->ip4_external_gw));
558  		} else if (priv->ip6_external_gw) {
559  			nm_log_info (LOGD_VPN, "VPN Gateway: %s",
560  			             ip6_address_to_string (priv->ip6_external_gw));
561  		}
562  	
563  		nm_log_info (LOGD_VPN, "Tunnel Device: %s", priv->ip_iface);
564  	
565  		if (priv->ip4_config) {
566  			nm_log_info (LOGD_VPN, "IPv4 configuration:");
567  	
568  			address4 = nm_ip4_config_get_address (priv->ip4_config, 0);
569  	
570  			if (priv->ip4_internal_gw)
571  				nm_log_info (LOGD_VPN, "  Internal Gateway: %s", ip_address_to_string (priv->ip4_internal_gw));
572  			nm_log_info (LOGD_VPN, "  Internal Address: %s", ip_address_to_string (address4->address));
573  			nm_log_info (LOGD_VPN, "  Internal Prefix: %d", address4->plen);
574  			nm_log_info (LOGD_VPN, "  Internal Point-to-Point Address: %s",
575  						 ip_address_to_string (nm_ip4_config_get_ptp_address (priv->ip4_config)));
576  			nm_log_info (LOGD_VPN, "  Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config));
577  	
578  			num = nm_ip4_config_get_num_routes (priv->ip4_config);
579  			for (i = 0; i < num; i++) {
580  				const NMPlatformIP4Route *route = nm_ip4_config_get_route (priv->ip4_config, i);
581  	
582  				nm_log_info (LOGD_VPN, "  Static Route: %s/%d   Next Hop: %s",
583  				             ip_address_to_string (route->network),
584  				             route->plen,
585  				             ip_address_to_string (route->gateway));
586  			}
587  	
588  			nm_log_info (LOGD_VPN, "  Forbid Default Route: %s",
589  						 nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no");
590  	
591  			num = nm_ip4_config_get_num_nameservers (priv->ip4_config);
592  			for (i = 0; i < num; i++) {
593  				nm_log_info (LOGD_VPN, "  Internal DNS: %s",
594  							 ip_address_to_string (nm_ip4_config_get_nameserver (priv->ip4_config, i)));
595  			}
596  	
597  			if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0)
598  				dns_domain = (char *) nm_ip4_config_get_domain (priv->ip4_config, 0);
599  	
600  			nm_log_info (LOGD_VPN, "  DNS Domain: '%s'", dns_domain ? dns_domain : "(none)");
601  		} else
602  			nm_log_info (LOGD_VPN, "No IPv4 configuration");
603  	
604  		if (priv->ip6_config) {
605  			nm_log_info (LOGD_VPN, "IPv6 configuration:");
606  	
607  			address6 = nm_ip6_config_get_address (priv->ip6_config, 0);
608  	
609  			if (priv->ip6_internal_gw)
610  				nm_log_info (LOGD_VPN, "  Internal Gateway: %s", ip6_address_to_string (priv->ip6_internal_gw));
611  			nm_log_info (LOGD_VPN, "  Internal Address: %s", ip6_address_to_string (&address6->address));
612  			nm_log_info (LOGD_VPN, "  Internal Prefix: %d", address6->plen);
613  			nm_log_info (LOGD_VPN, "  Internal Point-to-Point Address: %s",
614  						 ip6_address_to_string (nm_ip6_config_get_ptp_address (priv->ip6_config)));
615  			nm_log_info (LOGD_VPN, "  Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config));
616  	
617  			num = nm_ip6_config_get_num_routes (priv->ip6_config);
618  			for (i = 0; i < num; i++) {
619  				const NMPlatformIP6Route *route = nm_ip6_config_get_route (priv->ip6_config, i);
620  	
621  				nm_log_info (LOGD_VPN, "  Static Route: %s/%d   Next Hop: %s",
622  				             ip6_address_to_string (&route->network),
623  				             route->plen,
624  				             ip6_address_to_string (&route->gateway));
625  			}
626  	
627  			nm_log_info (LOGD_VPN, "  Forbid Default Route: %s",
628  						 nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no");
629  	
630  			num = nm_ip6_config_get_num_nameservers (priv->ip6_config);
631  			for (i = 0; i < num; i++) {
632  				nm_log_info (LOGD_VPN, "  Internal DNS: %s",
633  							 ip6_address_to_string (nm_ip6_config_get_nameserver (priv->ip6_config, i)));
634  			}
635  	
636  			if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0)
637  				dns_domain = (char *) nm_ip6_config_get_domain (priv->ip6_config, 0);
638  	
639  			nm_log_info (LOGD_VPN, "  DNS Domain: '%s'", dns_domain ? dns_domain : "(none)");
640  		} else
641  			nm_log_info (LOGD_VPN, "No IPv6 configuration");
642  	
643  		if (priv->banner && strlen (priv->banner)) {
644  			nm_log_info (LOGD_VPN, "Login Banner:");
645  			nm_log_info (LOGD_VPN, "-----------------------------------------");
646  			nm_log_info (LOGD_VPN, "%s", priv->banner);
647  			nm_log_info (LOGD_VPN, "-----------------------------------------");
648  		}
649  	}
650  	
651  	static gboolean
652  	nm_vpn_connection_apply_config (NMVPNConnection *connection)
653  	{
654  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
655  	
656  		nm_platform_link_set_up (priv->ip_ifindex);
657  	
658  		if (priv->ip4_config) {
659  			if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex, 0))
660  				return FALSE;
661  		}
662  	
663  		if (priv->ip6_config) {
664  			if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex, 0))
665  				/* FIXME: remove ip4 config */
666  				return FALSE;
667  		}
668  	
669  		/* Add any explicit route to the VPN gateway through the parent device */
670  		if (priv->ip4_external_gw)
671  			add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_external_gw);
672  		if (priv->ip6_external_gw)
673  			add_ip6_vpn_gateway_route (priv->parent_dev, priv->ip6_external_gw);
674  	
675  		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
676  		             nm_connection_get_id (priv->connection));
677  		nm_vpn_connection_set_vpn_state (connection,
678  		                                 NM_VPN_CONNECTION_STATE_ACTIVATED,
679  		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
680  		return TRUE;
681  	}
682  	
683  	static void
684  	nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection,
685  	                                         gboolean         success)
686  	{
687  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
688  	
689  		if (priv->connect_timeout == 0) {
690  			/* config_complete() was already called with an error;
691  			 * ignore further calls.
692  			 */
693  			return;
694  		}
695  	
696  		if (success) {
697  			if (   (priv->has_ip4 && !priv->ip4_config)
698  			    || (priv->has_ip6 && !priv->ip6_config)) {
699  				/* Need to wait for other config */
700  				return;
701  			}
702  		}
703  	
704  		g_source_remove (priv->connect_timeout);
705  		priv->connect_timeout = 0;
706  	
707  		if (success) {
708  			print_vpn_config (connection);
709  	
710  			if (nm_vpn_connection_apply_config (connection))
711  				return;
712  		}
713  	
714  		g_clear_object (&priv->ip4_config);
715  		g_clear_object (&priv->ip6_config);
716  	
717  		nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.",
718  		             nm_connection_get_id (priv->connection));
719  		nm_vpn_connection_set_vpn_state (connection,
720  		                                 NM_VPN_CONNECTION_STATE_FAILED,
721  		                                 NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
722  	}
723  	
724  	static gboolean
725  	process_generic_config (NMVPNConnection *connection,
726  	                        GHashTable *config_hash)
727  	{
728  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
729  		GValue *val;
730  	
731  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_TUNDEV);
732  		if (val)
733  			priv->ip_iface = g_strdup (g_value_get_string (val));
734  		else {
735  			nm_log_err (LOGD_VPN, "invalid or missing tunnel device received!");
736  			nm_vpn_connection_config_maybe_complete (connection, FALSE);
737  			return FALSE;
738  		}
739  	
740  		/* Grab the interface index for address/routing operations */
741  		priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface);
742  		if (!priv->ip_ifindex) {
743  			nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
744  			nm_vpn_connection_config_maybe_complete (connection, FALSE);
745  			return FALSE;
746  		}
747  	
748  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_BANNER);
749  		if (val) {
750  			g_free (priv->banner);
751  			priv->banner = g_strdup (g_value_get_string (val));
752  		}
753  	
754  		/* External world-visible address of the VPN server */
755  		priv->ip4_external_gw = 0;
756  		priv->ip6_external_gw = NULL;
757  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY);
758  		if (val) {
759  			if (G_VALUE_HOLDS (val, G_TYPE_UINT)) {
760  				priv->ip4_external_gw = g_value_get_uint (val);
761  			} else if (G_VALUE_HOLDS (val, DBUS_TYPE_G_UCHAR_ARRAY)) {
762  				GByteArray *ba = g_value_get_boxed (val);
763  	
764  				if (ba->len == sizeof (struct in6_addr))
765  					priv->ip6_external_gw = g_memdup (ba->data, ba->len);
766  			} else {
767  				nm_log_err (LOGD_VPN, "(%s): VPN gateway is neither IPv4 nor IPv6", priv->ip_iface);
768  				nm_vpn_connection_config_maybe_complete (connection, FALSE);
769  				return FALSE;
770  			}
771  		}
772  	
773  		/* MTU; this is a per-connection value, though NM's API treats it
774  		 * like it's IP4-specific. So we store it for now and retrieve it
775  		 * later in ip4_config_get.
776  		 */
777  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_MTU);
778  		if (val)
779  			priv->mtu = g_value_get_uint (val);
780  		else
781  			priv->mtu = 0;
782  	
783  		return TRUE;
784  	}
785  	
786  	static void
787  	nm_vpn_connection_config_get (DBusGProxy *proxy,
788  	                              GHashTable *config_hash,
789  	                              gpointer user_data)
790  	{
791  		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
792  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
793  		GValue *val;
794  	
795  		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.",
796  		             nm_connection_get_id (priv->connection));
797  	
798  		if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
799  			nm_vpn_connection_set_vpn_state (connection,
800  			                                 NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
801  			                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
802  		}
803  	
804  		if (!process_generic_config (connection, config_hash))
805  			return;
806  	
807  		/* Note whether to expect IPv4 and IPv6 configs */
808  		val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP4);
809  		priv->has_ip4 = val ? g_value_get_boolean (val) : FALSE;
810  		g_clear_object (&priv->ip4_config);
811  	
812  		val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP6);
813  		priv->has_ip6 = val ? g_value_get_boolean (val) : FALSE;
814  		g_clear_object (&priv->ip6_config);
815  	}
816  	
817  	static void
818  	nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
819  	                                  GHashTable *config_hash,
820  	                                  gpointer user_data)
821  	{
822  		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
823  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
824  		NMPlatformIP4Address address;
825  		NMIP4Config *config;
826  		GValue *val;
827  		int i;
828  	
829  		if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
830  			nm_vpn_connection_set_vpn_state (connection,
831  			                                 NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
832  			                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
833  		}
834  	
835  		if (priv->has_ip4) {
836  			nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.",
837  			             nm_connection_get_id (priv->connection));
838  	
839  			if (g_hash_table_size (config_hash) == 0) {
840  				priv->has_ip4 = FALSE;
841  				nm_vpn_connection_config_maybe_complete (connection, TRUE);
842  				return;
843  			}
844  		} else {
845  			nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received from old-style plugin.",
846  			             nm_connection_get_id (priv->connection));
847  	
848  			/* In the old API, the generic and IPv4 configuration items
849  			 * were mixed together.
850  			 */
851  			if (!process_generic_config (connection, config_hash))
852  				return;
853  	
854  			priv->has_ip4 = TRUE;
855  			priv->has_ip6 = FALSE;
856  		}
857  	
858  		config = nm_ip4_config_new ();
859  	
860  		memset (&address, 0, sizeof (address));
861  		address.plen = 24;
862  		if (priv->ip4_external_gw)
863  			nm_ip4_config_set_gateway (config, priv->ip4_external_gw);
864  	
865  		/* Internal address of the VPN subnet's gateway */
866  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY);
867  		if (val)
868  			priv->ip4_internal_gw = g_value_get_uint (val);
869  	
870  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS);
871  		if (val)
872  			address.address = g_value_get_uint (val);
873  	
874  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP);
875  		if (val)
876  			nm_ip4_config_set_ptp_address (config, g_value_get_uint (val));
877  	
878  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX);
879  		if (val)
880  			address.plen = g_value_get_uint (val);
881  	
882  		if (address.address && address.plen) {
883  			nm_ip4_config_add_address (config, &address);
884  		} else {
885  			nm_log_err (LOGD_VPN, "invalid IP4 config received!");
886  			g_object_unref (config);
887  			nm_vpn_connection_config_maybe_complete (connection, FALSE);
888  			return;
889  		}
890  	
891  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS);
892  		if (val) {
893  			GArray *dns = (GArray *) g_value_get_boxed (val);
894  	
895  			for (i = 0; i < dns->len; i++)
896  				nm_ip4_config_add_nameserver (config, g_array_index (dns, guint, i));
897  		}
898  	
899  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_NBNS);
900  		if (val) {
901  			GArray *nbns = (GArray *) g_value_get_boxed (val);
902  	
903  			for (i = 0; i < nbns->len; i++)
904  				nm_ip4_config_add_wins (config, g_array_index (nbns, guint, i));
905  		}
906  	
907  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_MSS);
908  		if (val)
909  			nm_ip4_config_set_mss (config, g_value_get_uint (val));
910  	
911  		if (priv->mtu)
912  			nm_ip4_config_set_mtu (config, priv->mtu);
913  	
914  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN);
915  		if (val)
916  			nm_ip4_config_add_domain (config, g_value_get_string (val));
917  	
918  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS);
919  		if (val) {
920  			const char **domains = g_value_get_boxed (val);
921  			const char **domain;
922  	
923  			for (domain = domains; domain && *domain; domain++)
924  				nm_ip4_config_add_domain (config, *domain);
925  		}
926  	
927  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES);
928  		if (val) {
929  			GSList *routes;
930  			GSList *iter;
931  	
932  			routes = nm_utils_ip4_routes_from_gvalue (val);
933  			for (iter = routes; iter; iter = iter->next) {
934  				NMIP4Route *item = iter->data;
935  				NMPlatformIP4Route route;
936  	
937  				memset (&route, 0, sizeof (route));
938  				route.network = nm_ip4_route_get_dest (item);
939  				route.plen = nm_ip4_route_get_prefix (item);
940  				route.gateway = nm_ip4_route_get_next_hop (item);
941  	
942  				/* Ignore host routes to the VPN gateway since NM adds one itself
943  				 * below.  Since NM knows more about the routing situation than
944  				 * the VPN server, we want to use the NM created route instead of
945  				 * whatever the server provides.
946  				 */
947  				if (priv->ip4_external_gw && route.network == priv->ip4_external_gw && route.plen == 32)
948  					continue;
949  	
950  				/* Otherwise accept the VPN-provided route */
951  				nm_ip4_config_add_route (config, &route);
952  			}
953  	
954  			g_slist_free_full (routes, (GDestroyNotify) nm_ip4_route_unref);
955  		}
956  	
957  		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT);
958  		if (val && G_VALUE_HOLDS_BOOLEAN (val))
959  			nm_ip4_config_set_never_default (config, g_value_get_boolean (val));
960  	
961  		/* Merge in user overrides from the NMConnection's IPv4 setting */
962  		nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (priv->connection));
963  	
964  		priv->ip4_config = config;
965  		nm_vpn_connection_config_maybe_complete (connection, TRUE);
966  	}
967  	
968  	static void
969  	nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
970  	                                  GHashTable *config_hash,
971  	                                  gpointer user_data)
972  	{
973  		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
974  		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
975  		NMPlatformIP6Address address;
976  		NMIP6Config *config;
977  		GValue *val;
978  		int i;
979  	
980  		nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.",
981  		             nm_connection_get_id (priv->connection));
982  	
(1) Event cond_true: Condition "nm_vpn_connection_get_vpn_state(connection) == NM_VPN_CONNECTION_STATE_CONNECT", taking true branch
983  		if (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_CONNECT) {
984  			nm_vpn_connection_set_vpn_state (connection,
985  			                                 NM_VPN_CONNECTION_STATE_IP_CONFIG_GET,
986  			                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
987  		}
988  	
(2) Event cond_false: Condition "g_hash_table_size(config_hash) == 0", taking false branch
989  		if (g_hash_table_size (config_hash) == 0) {
990  			priv->has_ip6 = FALSE;
991  			nm_vpn_connection_config_maybe_complete (connection, TRUE);
992  			return;
(3) Event if_end: End of if statement
993  		}
994  	
995  		config = nm_ip6_config_new ();
996  	
997  		memset (&address, 0, sizeof (address));
998  		address.plen = 128;
(4) Event cond_false: Condition "priv->ip6_external_gw", taking false branch
(6) Event var_compare_op: Comparing "priv->ip6_external_gw" to null implies that "priv->ip6_external_gw" might be null.
Also see events: [alias_transfer][var_deref_op]
999  		if (priv->ip6_external_gw)
(5) Event if_end: End of if statement
1000 			nm_ip6_config_set_gateway (config, priv->ip6_external_gw);
1001 	
1002 		/* Internal address of the VPN subnet's gateway */
1003 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY);
(7) Event cond_true: Condition "val", taking true branch
1004 		if (val) {
1005 			GByteArray *ba = g_value_get_boxed (val);
1006 	
(8) Event cond_true: Condition "ba->len == 16UL /* sizeof (struct in6_addr) */", taking true branch
1007 			if (ba->len == sizeof (struct in6_addr))
1008 				priv->ip6_internal_gw = g_memdup (ba->data, ba->len);
1009 		}
1010 	
1011 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS);
(9) Event cond_true: Condition "val", taking true branch
1012 		if (val) {
1013 			GByteArray *ba = g_value_get_boxed (val);
1014 	
(10) Event cond_true: Condition "ba->len == 16UL /* sizeof (struct in6_addr) */", taking true branch
1015 			if (ba->len == sizeof (struct in6_addr))
1016 				address.address = *(struct in6_addr *) ba->data;
1017 		}
1018 	
1019 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PTP);
(11) Event cond_true: Condition "val", taking true branch
1020 		if (val) {
1021 			GByteArray *ba = g_value_get_boxed (val);
1022 	
(12) Event cond_true: Condition "ba->len == 16UL /* sizeof (struct in6_addr) */", taking true branch
1023 			if (ba->len == sizeof (struct in6_addr))
1024 				nm_ip6_config_set_ptp_address (config, (struct in6_addr *)ba->data);
1025 		}
1026 	
1027 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX);
(13) Event cond_true: Condition "val", taking true branch
1028 		if (val)
1029 			address.plen = g_value_get_uint (val);
1030 	
(14) Event cond_true: Condition "__a->__in6_u.__u6_addr32[0] == 0", taking true branch
(15) Event cond_true: Condition "__a->__in6_u.__u6_addr32[1] == 0", taking true branch
(16) Event cond_true: Condition "__a->__in6_u.__u6_addr32[2] == 0", taking true branch
(17) Event cond_true: Condition "__a->__in6_u.__u6_addr32[3] == 0", taking true branch
(18) Event cond_false: Condition "!({...})", taking false branch
1031 		if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen)
1032 			nm_ip6_config_add_address (config, &address);
(19) Event else_branch: Reached else branch
1033 		else {
1034 			nm_log_err (LOGD_VPN, "invalid IP6 config received!");
1035 			g_object_unref (config);
1036 			nm_vpn_connection_config_maybe_complete (connection, FALSE);
1037 		}
1038 	
1039 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DNS);
(20) Event cond_true: Condition "val", taking true branch
1040 		if (val) {
1041 			GPtrArray *dns = (GPtrArray *) g_value_get_boxed (val);
1042 			GByteArray *ba;
1043 	
(21) Event cond_true: Condition "i < dns->len", taking true branch
(24) Event loop_begin: Jumped back to beginning of loop
(25) Event cond_false: Condition "i < dns->len", taking false branch
1044 			for (i = 0; i < dns->len; i++) {
1045 				ba = dns->pdata[i];
(22) Event cond_true: Condition "ba->len == 16UL /* sizeof (struct in6_addr) */", taking true branch
1046 				if (ba->len == sizeof (struct in6_addr))
1047 					nm_ip6_config_add_nameserver (config, (struct in6_addr *)ba->data);
(23) Event loop: Jumping back to the beginning of the loop
(26) Event loop_end: Reached end of loop
1048 			}
1049 		}
1050 	
1051 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_MSS);
(27) Event cond_true: Condition "val", taking true branch
1052 		if (val)
1053 			nm_ip6_config_set_mss (config, g_value_get_uint (val));
1054 	
1055 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN);
(28) Event cond_true: Condition "val", taking true branch
1056 		if (val)
1057 			nm_ip6_config_add_domain (config, g_value_get_string (val));
1058 	
1059 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS);
(29) Event cond_true: Condition "val", taking true branch
1060 		if (val) {
1061 			const char **domains = g_value_get_boxed (val);
1062 			const char **domain;
1063 	
(30) Event cond_true: Condition "domain", taking true branch
(31) Event cond_true: Condition "*domain", taking true branch
(33) Event loop_begin: Jumped back to beginning of loop
(34) Event cond_true: Condition "domain", taking true branch
(35) Event cond_false: Condition "*domain", taking false branch
1064 			for (domain = domains; domain && *domain; domain++)
(32) Event loop: Jumping back to the beginning of the loop
(36) Event loop_end: Reached end of loop
1065 				nm_ip6_config_add_domain (config, *domain);
1066 		}
1067 	
1068 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES);
(37) Event cond_true: Condition "val", taking true branch
1069 		if (val) {
1070 			GSList *routes;
1071 			GSList *iter;
1072 	
1073 			routes = nm_utils_ip6_routes_from_gvalue (val);
(38) Event cond_true: Condition "iter", taking true branch
1074 			for (iter = routes; iter; iter = iter->next) {
1075 				NMIP6Route *item = iter->data;
1076 				NMPlatformIP6Route route;
1077 	
1078 				memset (&route, 0, sizeof (route));
1079 				route.network = *nm_ip6_route_get_dest (item);
1080 				route.plen = nm_ip6_route_get_prefix (item);
1081 				route.gateway = *nm_ip6_route_get_next_hop (item);
1082 	
1083 				/* Ignore host routes to the VPN gateway since NM adds one itself
1084 				 * below.  Since NM knows more about the routing situation than
1085 				 * the VPN server, we want to use the NM created route instead of
1086 				 * whatever the server provides.
1087 				 */
(39) Event alias_transfer: Assigning: "__b" = "priv->ip6_external_gw".
(40) Event var_deref_op: Dereferencing null pointer "__b".
Also see events: [var_compare_op]
1088 				if (IN6_ARE_ADDR_EQUAL (&route.network, priv->ip6_external_gw) && route.plen == 128)
1089 					continue;
1090 	
1091 				/* Otherwise accept the VPN-provided route */
1092 				nm_ip6_config_add_route (config, &route);
1093 			}
1094 	
1095 			g_slist_free_full (routes, (GDestroyNotify) nm_ip6_route_unref);
1096 		}
1097 	
1098 		val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT);
1099 		if (val && G_VALUE_HOLDS_BOOLEAN (val))
1100 			nm_ip6_config_set_never_default (config, g_value_get_boolean (val));
1101 	
1102 		/* Merge in user overrides from the NMConnection's IPv6 setting */
1103 		nm_ip6_config_merge_setting (config, nm_connection_get_setting_ip6_config (priv->connection));
1104 	
1105 		priv->ip6_config = config;
1106 		nm_vpn_connection_config_maybe_complete (connection, TRUE);
1107 	}
1108 	
1109 	static gboolean
1110 	connect_timeout_cb (gpointer user_data)
1111 	{
1112 		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
1113 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
1114 		NMVPNConnectionState state;
1115 	
1116 		priv->connect_timeout = 0;
1117 	
1118 		/* Cancel activation if it's taken too long */
1119 		state = nm_vpn_connection_get_vpn_state (connection);
1120 		if (state == NM_VPN_CONNECTION_STATE_CONNECT ||
1121 		    state == NM_VPN_CONNECTION_STATE_IP_CONFIG_GET) {
1122 			nm_log_warn (LOGD_VPN, "VPN connection '%s' connect timeout exceeded.",
1123 			             nm_connection_get_id (priv->connection));
1124 			nm_vpn_connection_set_vpn_state (connection,
1125 			                                 NM_VPN_CONNECTION_STATE_FAILED,
1126 			                                 NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT);
1127 		}
1128 	
1129 		return FALSE;
1130 	}
1131 	
1132 	static void
1133 	connect_success (NMVPNConnection *connection)
1134 	{
1135 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
1136 	
1137 		/* 40 second timeout waiting for IP config signal from VPN service */
1138 		priv->connect_timeout = g_timeout_add_seconds (40, connect_timeout_cb, connection);
1139 	
1140 		g_hash_table_destroy (priv->connect_hash);
1141 		priv->connect_hash = NULL;
1142 	}
1143 	
1144 	static void
1145 	connect_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
1146 	{
1147 		NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
1148 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1149 		GError *err = NULL;
1150 	
1151 		nm_log_info (LOGD_VPN, "VPN connection '%s' (Connect) reply received.",
1152 		             nm_connection_get_id (priv->connection));
1153 	
1154 		dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID);
1155 		if (!err) {
1156 			connect_success (self);
1157 			return;
1158 		}
1159 	
1160 		nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect: '%s'.",
1161 		             nm_connection_get_id (priv->connection), err->message);
1162 		g_error_free (err);
1163 		nm_vpn_connection_set_vpn_state (self,
1164 		                                 NM_VPN_CONNECTION_STATE_FAILED,
1165 		                                 NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
1166 	}
1167 	
1168 	static void
1169 	connect_interactive_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
1170 	{
1171 		NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
1172 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1173 		GError *err = NULL;
1174 	
1175 		nm_log_info (LOGD_VPN, "VPN connection '%s' (ConnectInteractive) reply received.",
1176 		             nm_connection_get_id (priv->connection));
1177 	
1178 		dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID);
1179 		if (!err) {
1180 			connect_success (self);
1181 			return;
1182 		}
1183 	
1184 		if (dbus_g_error_has_name (err, NM_DBUS_VPN_ERROR_PREFIX "." NM_DBUS_VPN_INTERACTIVE_NOT_SUPPORTED)) {
1185 			/* Fall back to Connect() */
1186 			dbus_g_proxy_begin_call (priv->proxy, "Connect",
1187 			                         connect_cb, self, NULL,
1188 			                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
1189 			                         G_TYPE_INVALID);
1190 		} else {
1191 			nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect interactively: '%s'.",
1192 			             nm_connection_get_id (priv->connection), err->message);
1193 			g_error_free (err);
1194 			nm_vpn_connection_set_vpn_state (self,
1195 			                                 NM_VPN_CONNECTION_STATE_FAILED,
1196 			                                 NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
1197 		}
1198 	}
1199 	
1200 	/* Add a username to a hashed connection */
1201 	static GHashTable *
1202 	_hash_with_username (NMConnection *connection, const char *username)
1203 	{
1204 		NMConnection *dup;
1205 		NMSettingVPN *s_vpn;
1206 		GHashTable *hash;
1207 		const char *existing;
1208 	
1209 		/* Shortcut if we weren't given a username or if there already was one in
1210 		 * the VPN setting; don't bother duplicating the connection and everything.
1211 		 */
1212 		s_vpn = nm_connection_get_setting_vpn (connection);
1213 		g_assert (s_vpn);
1214 		existing = nm_setting_vpn_get_user_name (s_vpn);
1215 		if (username == NULL || existing)
1216 			return nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL);
1217 	
1218 		dup = nm_connection_duplicate (connection);
1219 		g_assert (dup);
1220 		s_vpn = nm_connection_get_setting_vpn (dup);
1221 		g_assert (s_vpn);
1222 		g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, username, NULL);
1223 		hash = nm_connection_to_hash (dup, NM_SETTING_HASH_FLAG_ALL);
1224 		g_object_unref (dup);
1225 		return hash;
1226 	}
1227 	
1228 	static void
1229 	really_activate (NMVPNConnection *connection, const char *username)
1230 	{
1231 		NMVPNConnectionPrivate *priv;
1232 		NMAgentManager *agent_mgr;
1233 		GHashTable *details;
1234 	
1235 		g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
1236 		g_return_if_fail (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_NEED_AUTH);
1237 	
1238 		priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
1239 	
1240 		dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
1241 		                                   G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID);
1242 	
1243 		dbus_g_proxy_add_signal (priv->proxy, "Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
1244 		dbus_g_proxy_connect_signal (priv->proxy, "Config",
1245 		                             G_CALLBACK (nm_vpn_connection_config_get),
1246 		                             connection, NULL);
1247 	
1248 		/* Ip4Config signal */
1249 		dbus_g_proxy_add_signal (priv->proxy, "Ip4Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
1250 		dbus_g_proxy_connect_signal (priv->proxy, "Ip4Config",
1251 		                             G_CALLBACK (nm_vpn_connection_ip4_config_get),
1252 		                             connection, NULL);
1253 	
1254 		/* Ip6Config signal */
1255 		dbus_g_proxy_add_signal (priv->proxy, "Ip6Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID);
1256 		dbus_g_proxy_connect_signal (priv->proxy, "Ip6Config",
1257 		                             G_CALLBACK (nm_vpn_connection_ip6_config_get),
1258 		                             connection, NULL);
1259 	
1260 		if (priv->connect_hash)
1261 			g_hash_table_destroy (priv->connect_hash);
1262 		priv->connect_hash = _hash_with_username (priv->connection, username);
1263 		details = g_hash_table_new (g_str_hash, g_str_equal);
1264 	
1265 		/* If at least one agent doesn't support VPN hints, then we can't use
1266 		 * ConnectInteractive(), because that agent won't be able to pass hints
1267 		 * from the VPN plugin's interactive secrets requests to the VPN authentication
1268 		 * dialog and we won't get the secrets we need.  In this case fall back to
1269 		 * the old Connect() call.
1270 		 */
1271 		agent_mgr = nm_agent_manager_get ();
1272 		if (nm_agent_manager_all_agents_have_capability (agent_mgr,
1273 		                                                 nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (connection)),
1274 		                                                 nm_active_connection_get_user_uid (NM_ACTIVE_CONNECTION (connection)),
1275 		                                                 NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) {
1276 			nm_log_dbg (LOGD_VPN, "Allowing interactive secrets as all agents have that capability");
1277 			dbus_g_proxy_begin_call (priv->proxy, "ConnectInteractive",
1278 			                         connect_interactive_cb, connection, NULL,
1279 			                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
1280 			                         DBUS_TYPE_G_MAP_OF_VARIANT, details,
1281 			                         G_TYPE_INVALID);
1282 		} else {
1283 			nm_log_dbg (LOGD_VPN, "Calling old Connect function as not all agents support interactive secrets");
1284 			dbus_g_proxy_begin_call (priv->proxy, "Connect",
1285 			                         connect_cb, connection, NULL,
1286 			                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash,
1287 			                         G_TYPE_INVALID);
1288 		}
1289 		g_object_unref (agent_mgr);
1290 		g_hash_table_destroy (details);
1291 	
1292 		nm_vpn_connection_set_vpn_state (connection,
1293 		                                 NM_VPN_CONNECTION_STATE_CONNECT,
1294 		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
1295 	}
1296 	
1297 	void
1298 	nm_vpn_connection_activate (NMVPNConnection *connection)
1299 	{
1300 		NMVPNConnectionPrivate *priv;
1301 		DBusGConnection *bus;
1302 	
1303 		g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
1304 		g_return_if_fail (nm_vpn_connection_get_vpn_state (connection) == NM_VPN_CONNECTION_STATE_PREPARE);
1305 	
1306 		priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
1307 	
1308 		bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ());
1309 		priv->proxy = dbus_g_proxy_new_for_name (bus,
1310 		                                         nm_vpn_connection_get_service (connection),
1311 		                                         NM_VPN_DBUS_PLUGIN_PATH,
1312 		                                         NM_VPN_DBUS_PLUGIN_INTERFACE);
1313 	
1314 		dbus_g_proxy_add_signal (priv->proxy, "Failure", G_TYPE_UINT, G_TYPE_INVALID);
1315 		dbus_g_proxy_connect_signal (priv->proxy, "Failure",
1316 		                             G_CALLBACK (plugin_failed),
1317 		                             connection, NULL);
1318 	
1319 		/* StateChanged signal */
1320 		dbus_g_proxy_add_signal (priv->proxy, "StateChanged", G_TYPE_UINT, G_TYPE_INVALID);
1321 		dbus_g_proxy_connect_signal (priv->proxy, "StateChanged",
1322 		                             G_CALLBACK (plugin_state_changed),
1323 		                             connection, NULL);
1324 	
1325 		dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
1326 		                                   G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID);
1327 		dbus_g_proxy_add_signal (priv->proxy, "SecretsRequired", G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID);
1328 		dbus_g_proxy_connect_signal (priv->proxy, "SecretsRequired",
1329 		                             G_CALLBACK (plugin_interactive_secrets_required),
1330 		                             connection, NULL);
1331 	
1332 		nm_vpn_connection_set_vpn_state (connection,
1333 		                                 NM_VPN_CONNECTION_STATE_NEED_AUTH,
1334 		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
1335 	
1336 		/* Kick off the secrets requests; first we get existing system secrets
1337 		 * and ask the plugin if these are sufficient, next we get all existing
1338 		 * secrets from system and from user agents and ask the plugin again,
1339 		 * and last we ask the user for new secrets if required.
1340 		 */
1341 		get_secrets (connection, SECRETS_REQ_SYSTEM, NULL);
1342 	}
1343 	
1344 	NMConnection *
1345 	nm_vpn_connection_get_connection (NMVPNConnection *connection)
1346 	{
1347 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1348 	
1349 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->connection;
1350 	}
1351 	
1352 	NMVPNConnectionState
1353 	nm_vpn_connection_get_vpn_state (NMVPNConnection *connection)
1354 	{
1355 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NM_VPN_CONNECTION_STATE_UNKNOWN);
1356 	
1357 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->vpn_state;
1358 	}
1359 	
1360 	const char *
1361 	nm_vpn_connection_get_banner (NMVPNConnection *connection)
1362 	{
1363 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1364 	
1365 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->banner;
1366 	}
1367 	
1368 	NMIP4Config *
1369 	nm_vpn_connection_get_ip4_config (NMVPNConnection *connection)
1370 	{
1371 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1372 	
1373 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config;
1374 	}
1375 	
1376 	NMIP6Config *
1377 	nm_vpn_connection_get_ip6_config (NMVPNConnection *connection)
1378 	{
1379 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1380 	
1381 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_config;
1382 	}
1383 	
1384 	const char *
1385 	nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
1386 	{
1387 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1388 	
1389 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_iface;
1390 	}
1391 	
1392 	int
1393 	nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection)
1394 	{
1395 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), -1);
1396 	
1397 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex;
1398 	}
1399 	
1400 	NMDevice *
1401 	nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
1402 	{
1403 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
1404 	
1405 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
1406 	}
1407 	
1408 	guint32
1409 	nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
1410 	{
1411 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0);
1412 	
1413 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw;
1414 	}
1415 	
1416 	struct in6_addr *
1417 	nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection)
1418 	{
1419 		g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0);
1420 	
1421 		return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_internal_gw;
1422 	}
1423 	
1424 	void
1425 	nm_vpn_connection_fail (NMVPNConnection *connection,
1426 	                        NMVPNConnectionStateReason reason)
1427 	{
1428 		g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
1429 	
1430 		nm_vpn_connection_set_vpn_state (connection,
1431 		                                 NM_VPN_CONNECTION_STATE_FAILED,
1432 		                                 reason);
1433 	}
1434 	
1435 	void
1436 	nm_vpn_connection_disconnect (NMVPNConnection *connection,
1437 	                              NMVPNConnectionStateReason reason)
1438 	{
1439 		g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
1440 	
1441 		nm_vpn_connection_set_vpn_state (connection,
1442 		                                 NM_VPN_CONNECTION_STATE_DISCONNECTED,
1443 		                                 reason);
1444 	}
1445 	
1446 	/******************************************************************************/
1447 	
1448 	static void
1449 	plugin_need_secrets_cb  (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
1450 	{
1451 		NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
1452 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1453 		GError *error = NULL;
1454 		char *setting_name;
1455 	
1456 		dbus_g_proxy_end_call (proxy, call, &error,
1457 		                       G_TYPE_STRING, &setting_name,
1458 		                       G_TYPE_INVALID);
1459 		if (error) {
1460 			nm_log_err (LOGD_VPN, "(%s/%s) plugin NeedSecrets request #%d failed: %s %s",
1461 			            nm_connection_get_uuid (priv->connection),
1462 			            nm_connection_get_id (priv->connection),
1463 			            priv->secrets_idx + 1,
1464 			            g_quark_to_string (error->domain),
1465 			            error->message);
1466 			nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
1467 			g_error_free (error);
1468 			return;
1469 		}
1470 	
1471 		if (setting_name && strlen (setting_name)) {
1472 			/* More secrets required */
1473 	
1474 			if (priv->secrets_idx == SECRETS_REQ_NEW) {
1475 				nm_log_err (LOGD_VPN, "(%s/%s) final secrets request failed to provide sufficient secrets",
1476 				            nm_connection_get_uuid (priv->connection),
1477 				            nm_connection_get_id (priv->connection));
1478 				nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
1479 			} else {
1480 				nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required",
1481 				            nm_connection_get_uuid (priv->connection),
1482 				            nm_connection_get_id (priv->connection));
1483 	
1484 				get_secrets (self, priv->secrets_idx + 1, NULL);
1485 			}
1486 			return;
1487 		}
1488 	
1489 		nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated no additional secrets required",
1490 		            nm_connection_get_uuid (priv->connection),
1491 		            nm_connection_get_id (priv->connection));
1492 	
1493 		/* No secrets required; we can start the VPN */
1494 		really_activate (self, priv->username);
1495 	}
1496 	
1497 	static void
1498 	plugin_new_secrets_cb  (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
1499 	{
1500 		NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
1501 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1502 		GError *error = NULL;
1503 	
1504 		if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
1505 			nm_log_err (LOGD_VPN, "(%s/%s) sending new secrets to the plugin failed: %s %s",
1506 			            nm_connection_get_uuid (priv->connection),
1507 			            nm_connection_get_id (priv->connection),
1508 			            g_quark_to_string (error->domain),
1509 			            error->message);
1510 			nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
1511 			g_error_free (error);
1512 		}
1513 	}
1514 	
1515 	static void
1516 	get_secrets_cb (NMSettingsConnection *connection,
1517 	                guint32 call_id,
1518 	                const char *agent_username,
1519 	                const char *setting_name,
1520 	                GError *error,
1521 	                gpointer user_data)
1522 	{
1523 		NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
1524 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1525 		GHashTable *hash;
1526 	
1527 		g_return_if_fail (NM_CONNECTION (connection) == priv->connection);
1528 		g_return_if_fail (call_id == priv->secrets_id);
1529 	
1530 		priv->secrets_id = 0;
1531 	
1532 		if (error) {
1533 			nm_log_err (LOGD_VPN, "Failed to request VPN secrets #%d: (%d) %s",
1534 			            priv->secrets_idx + 1, error->code, error->message);
1535 			nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
1536 		} else {
1537 			/* Cache the username for later */
1538 			if (agent_username) {
1539 				g_free (priv->username);
1540 				priv->username = g_strdup (agent_username);
1541 			}
1542 	
1543 			hash = _hash_with_username (priv->connection, priv->username);
1544 	
1545 			if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) {
1546 				nm_log_dbg (LOGD_VPN, "(%s/%s) sending secrets to the plugin",
1547 				            nm_connection_get_uuid (priv->connection),
1548 				            nm_connection_get_id (priv->connection));
1549 	
1550 				/* Send the secrets back to the plugin */
1551 				dbus_g_proxy_begin_call (priv->proxy, "NewSecrets",
1552 				                         plugin_new_secrets_cb, self, NULL,
1553 				                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
1554 				                         G_TYPE_INVALID);
1555 			} else {
1556 				nm_log_dbg (LOGD_VPN, "(%s/%s) asking service if additional secrets are required",
1557 				            nm_connection_get_uuid (priv->connection),
1558 				            nm_connection_get_id (priv->connection));
1559 	
1560 				/* Ask the VPN service if more secrets are required */
1561 				dbus_g_proxy_begin_call (priv->proxy, "NeedSecrets",
1562 				                         plugin_need_secrets_cb, self, NULL,
1563 				                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
1564 				                         G_TYPE_INVALID);
1565 			}
1566 	
1567 			g_hash_table_destroy (hash);
1568 		}
1569 	}
1570 	
1571 	static void
1572 	get_secrets (NMVPNConnection *self,
1573 	             SecretsReq secrets_idx,
1574 	             const char **hints)
1575 	{
1576 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1577 		NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_NONE;
1578 		GError *error = NULL;
1579 		gboolean filter_by_uid;
1580 	
1581 		g_return_if_fail (secrets_idx < SECRETS_REQ_LAST);
1582 		priv->secrets_idx = secrets_idx;
1583 	
1584 		filter_by_uid = nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self));
1585 	
1586 		nm_log_dbg (LOGD_VPN, "(%s/%s) requesting VPN secrets pass #%d",
1587 		            nm_connection_get_uuid (priv->connection),
1588 		            nm_connection_get_id (priv->connection),
1589 		            priv->secrets_idx + 1);
1590 	
1591 		switch (priv->secrets_idx) {
1592 		case SECRETS_REQ_SYSTEM:
1593 			flags = NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM;
1594 			filter_by_uid = FALSE;
1595 			break;
1596 		case SECRETS_REQ_EXISTING:
1597 			flags = NM_SETTINGS_GET_SECRETS_FLAG_NONE;
1598 			break;
1599 		case SECRETS_REQ_NEW:
1600 		case SECRETS_REQ_INTERACTIVE:
1601 			flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION;
1602 			break;
1603 		default:
1604 			g_assert_not_reached ();
1605 		}
1606 	
1607 		if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self)))
1608 			flags |= NM_SETTINGS_GET_SECRETS_FLAG_USER_REQUESTED;
1609 	
1610 		priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection),
1611 		                                                       filter_by_uid,
1612 		                                                       nm_active_connection_get_user_uid (NM_ACTIVE_CONNECTION (self)),
1613 		                                                       NM_SETTING_VPN_SETTING_NAME,
1614 		                                                       flags,
1615 		                                                       hints,
1616 		                                                       get_secrets_cb,
1617 		                                                       self,
1618 		                                                       &error);
1619 		if (!priv->secrets_id) {
1620 			if (error) {
1621 				nm_log_err (LOGD_VPN, "failed to request VPN secrets #%d: (%d) %s",
1622 				            priv->secrets_idx + 1, error->code, error->message);
1623 			}
1624 			nm_vpn_connection_fail (self, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
1625 			g_clear_error (&error);
1626 		}
1627 	}
1628 	
1629 	static void
1630 	plugin_interactive_secrets_required (DBusGProxy *proxy,
1631 	                                     const char *message,
1632 	                                     const char **secrets,
1633 	                                     gpointer user_data)
1634 	{
1635 		NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
1636 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
1637 		guint32 secrets_len = secrets ? g_strv_length ((char **) secrets) : 0;
1638 		char **hints;
1639 		guint32 i;
1640 	
1641 		nm_log_info (LOGD_VPN, "VPN plugin requested secrets; state %s (%d)",
1642 		             vpn_state_to_string (priv->vpn_state), priv->vpn_state);
1643 	
1644 		g_return_if_fail (priv->vpn_state == NM_VPN_CONNECTION_STATE_CONNECT ||
1645 		                  priv->vpn_state == NM_VPN_CONNECTION_STATE_NEED_AUTH);
1646 	
1647 		priv->secrets_idx = SECRETS_REQ_INTERACTIVE;
1648 		nm_vpn_connection_set_vpn_state (connection,
1649 		                                 NM_VPN_CONNECTION_STATE_NEED_AUTH,
1650 		                                 NM_VPN_CONNECTION_STATE_REASON_NONE);
1651 	
1652 		/* Copy hints and add message to the end */
1653 		hints = g_malloc0 (sizeof (char *) * (secrets_len + 2));
1654 		for (i = 0; i < secrets_len; i++)
1655 			hints[i] = g_strdup (secrets[i]);
1656 		if (message)
1657 			hints[i] = g_strdup_printf ("x-vpn-message:%s", message);
1658 	
1659 		get_secrets (connection, SECRETS_REQ_INTERACTIVE, (const char **) hints);
1660 		g_strfreev (hints);
1661 	}
1662 	
1663 	/******************************************************************************/
1664 	
1665 	static void
1666 	nm_vpn_connection_init (NMVPNConnection *self)
1667 	{
1668 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
1669 	
1670 		priv->vpn_state = NM_VPN_CONNECTION_STATE_PREPARE;
1671 		priv->secrets_idx = SECRETS_REQ_SYSTEM;
1672 	}
1673 	
1674 	static void
1675 	constructed (GObject *object)
1676 	{
1677 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
1678 		NMConnection *connection;
1679 		NMDevice *device;
1680 	
1681 		G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object);
1682 	
1683 		connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
1684 		priv->connection = g_object_ref (connection);
1685 	
1686 		device = (NMDevice *) nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
1687 		g_assert (device);
1688 	
1689 		priv->parent_dev = g_object_ref (device);
1690 	
1691 		priv->device_monitor = g_signal_connect (device, "state-changed",
1692 		                                         G_CALLBACK (device_state_changed),
1693 		                                         object);
1694 	}
1695 	
1696 	static void
1697 	dispose (GObject *object)
1698 	{
1699 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
1700 	
1701 		if (priv->disposed) {
1702 			G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object);
1703 			return;
1704 		}
1705 		priv->disposed = TRUE;
1706 	
1707 		if (priv->connect_hash)
1708 			g_hash_table_destroy (priv->connect_hash);
1709 	
1710 		if (priv->ip6_internal_gw)
1711 			g_free (priv->ip6_internal_gw);
1712 		if (priv->ip6_external_gw)
1713 			g_free (priv->ip6_external_gw);
1714 	
1715 		if (priv->device_monitor)
1716 			g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor);
1717 	
1718 		g_clear_object (&priv->parent_dev);
1719 	
1720 		if (priv->ip4_config)
1721 			g_object_unref (priv->ip4_config);
1722 		if (priv->ip6_config)
1723 			g_object_unref (priv->ip6_config);
1724 	
1725 		if (priv->connect_timeout)
1726 			g_source_remove (priv->connect_timeout);
1727 	
1728 		if (priv->proxy)
1729 			g_object_unref (priv->proxy);
1730 	
1731 		if (priv->secrets_id) {
1732 			nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection),
1733 			                                       priv->secrets_id);
1734 		}
1735 	
1736 		g_clear_object (&priv->connection);
1737 		g_free (priv->username);
1738 	
1739 		G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object);
1740 	}
1741 	
1742 	static void
1743 	finalize (GObject *object)
1744 	{
1745 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
1746 	
1747 		g_free (priv->banner);
1748 		g_free (priv->ip_iface);
1749 	
1750 		G_OBJECT_CLASS (nm_vpn_connection_parent_class)->finalize (object);
1751 	}
1752 	
1753 	static void
1754 	get_property (GObject *object, guint prop_id,
1755 			    GValue *value, GParamSpec *pspec)
1756 	{
1757 		NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
1758 	
1759 		switch (prop_id) {
1760 		case PROP_VPN_STATE:
1761 			g_value_set_uint (value, priv->vpn_state);
1762 			break;
1763 		case PROP_BANNER:
1764 			g_value_set_string (value, priv->banner ? priv->banner : "");
1765 			break;
1766 		case PROP_MASTER:
1767 			g_value_set_boxed (value, nm_device_get_path (priv->parent_dev));
1768 			break;
1769 		default:
1770 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1771 			break;
1772 		}
1773 	}
1774 	
1775 	static void
1776 	nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
1777 	{
1778 		GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
1779 	
1780 		g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate));
1781 	
1782 		/* virtual methods */
1783 		object_class->get_property = get_property;
1784 		object_class->constructed = constructed;
1785 		object_class->dispose = dispose;
1786 		object_class->finalize = finalize;
1787 	
1788 		g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
1789 	
1790 		/* properties */
1791 		g_object_class_install_property (object_class, PROP_VPN_STATE,
1792 			g_param_spec_uint (NM_VPN_CONNECTION_VPN_STATE,
1793 			                   "VpnState",
1794 			                   "Current VPN state",
1795 			                   NM_VPN_CONNECTION_STATE_UNKNOWN,
1796 			                   NM_VPN_CONNECTION_STATE_DISCONNECTED,
1797 			                   NM_VPN_CONNECTION_STATE_UNKNOWN,
1798 			                   G_PARAM_READABLE));
1799 	
1800 		g_object_class_install_property (object_class, PROP_BANNER,
1801 			g_param_spec_string (NM_VPN_CONNECTION_BANNER,
1802 			                     "Banner",
1803 			                     "Login Banner",
1804 			                     NULL,
1805 			                     G_PARAM_READABLE));
1806 	
1807 		/* signals */
1808 		signals[VPN_STATE_CHANGED] =
1809 			g_signal_new ("vpn-state-changed",
1810 			              G_OBJECT_CLASS_TYPE (object_class),
1811 			              G_SIGNAL_RUN_FIRST,
1812 			              0, NULL, NULL, NULL,
1813 			              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
1814 	
1815 		signals[INTERNAL_STATE_CHANGED] =
1816 			g_signal_new (NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
1817 			              G_OBJECT_CLASS_TYPE (object_class),
1818 			              G_SIGNAL_RUN_FIRST,
1819 			              0, NULL, NULL, NULL,
1820 			              G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
1821 	
1822 		nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
1823 		                                        G_TYPE_FROM_CLASS (object_class),
1824 		                                        &dbus_glib_nm_vpn_connection_object_info);
1825 	}
1826 	
1827