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