nm-manager.c 153 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
18
 * Copyright (C) 2007 - 2009 Novell, Inc.
19
 * Copyright (C) 2007 - 2012 Red Hat, Inc.
20
 */
21

22 23
#include <config.h>

24
#include <stdlib.h>
25
#include <netinet/ether.h>
26 27
#include <fcntl.h>
#include <errno.h>
28
#include <string.h>
29 30
#include <unistd.h>
#include <sys/types.h>
31
#include <sys/stat.h>
32 33
#include <dbus/dbus-glib-lowlevel.h>
#include <dbus/dbus-glib.h>
34
#include <gio/gio.h>
35
#include <glib/gi18n.h>
36

37
#include "nm-glib-compat.h"
38
#include "nm-manager.h"
39
#include "nm-logging.h"
40
#include "nm-dbus-manager.h"
41
#include "nm-vpn-manager.h"
Tambet Ingo's avatar
Tambet Ingo committed
42
#include "nm-modem-manager.h"
43
#include "nm-device-bt.h"
44
#include "nm-device.h"
45
#include "nm-device-ethernet.h"
46
#include "nm-device-wifi.h"
47
#include "nm-device-olpc-mesh.h"
48
#include "nm-device-modem.h"
49
#include "nm-device-infiniband.h"
50
#include "nm-device-bond.h"
Thomas Graf's avatar
Thomas Graf committed
51
#include "nm-device-bridge.h"
52
#include "nm-device-vlan.h"
53
#include "nm-device-adsl.h"
54
#include "nm-device-generic.h"
55
#include "nm-device-veth.h"
56
#include "nm-system.h"
57
#include "nm-setting-bluetooth.h"
58 59
#include "nm-setting-connection.h"
#include "nm-setting-wireless.h"
60
#include "nm-setting-vpn.h"
61
#include "nm-dbus-glib-types.h"
62
#include "nm-platform.h"
Dan Williams's avatar
Dan Williams committed
63
#include "nm-udev-manager.h"
64
#include "nm-hostname-provider.h"
65 66
#include "nm-bluez-manager.h"
#include "nm-bluez-common.h"
67
#include "nm-settings.h"
68
#include "nm-settings-connection.h"
69
#include "nm-manager-auth.h"
70
#include "NetworkManagerUtils.h"
71
#include "nm-utils.h"
72 73
#include "nm-device-factory.h"
#include "wifi-utils.h"
74
#include "nm-enum-types.h"
75
#include "nm-sleep-monitor.h"
76
#include "nm-platform.h"
77 78

#if WITH_CONCHECK
79
#include "nm-connectivity.h"
80
#endif
81

82

83 84 85
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
#define NM_AUTOIP_DBUS_IFACE   "org.freedesktop.nm_avahi_autoipd"

86 87 88 89 90 91 92 93 94
static gboolean impl_manager_get_devices (NMManager *manager,
                                          GPtrArray **devices,
                                          GError **err);

static gboolean impl_manager_get_device_by_ip_iface (NMManager *self,
                                                     const char *iface,
                                                     char **out_object_path,
                                                     GError **error);

95
static void impl_manager_activate_connection (NMManager *manager,
96 97 98 99
                                              const char *connection_path,
                                              const char *device_path,
                                              const char *specific_object_path,
                                              DBusGMethodInvocation *context);
100

101 102 103 104 105 106
static void impl_manager_add_and_activate_connection (NMManager *manager,
                                                      GHashTable *settings,
                                                      const char *device_path,
                                                      const char *specific_object_path,
                                                      DBusGMethodInvocation *context);

107 108 109
static void impl_manager_deactivate_connection (NMManager *manager,
                                                const char *connection_path,
                                                DBusGMethodInvocation *context);
110

111 112 113
static void impl_manager_sleep (NMManager *manager,
                                gboolean do_sleep,
                                DBusGMethodInvocation *context);
114

115 116 117
static void impl_manager_enable (NMManager *manager,
                                 gboolean enable,
                                 DBusGMethodInvocation *context);
118

119 120 121
static void impl_manager_get_permissions (NMManager *manager,
                                          DBusGMethodInvocation *context);

122 123 124 125
static gboolean impl_manager_get_state (NMManager *manager,
                                        guint32 *state,
                                        GError **error);

126 127 128 129 130
static gboolean impl_manager_set_logging (NMManager *manager,
                                          const char *level,
                                          const char *domains,
                                          GError **error);

131 132 133 134
static void impl_manager_get_logging (NMManager *manager,
                                      char **level,
                                      char **domains);

135 136
#include "nm-manager-glue.h"

137
static void bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr,
138 139 140 141 142
                                           const char *bdaddr,
                                           const char *name,
                                           const char *object_path,
                                           guint32 uuids,
                                           NMManager *manager);
143 144

static void bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
145 146 147
                                             const char *bdaddr,
                                             const char *object_path,
                                             gpointer user_data);
148

149
static void add_device (NMManager *self, NMDevice *device);
Tambet Ingo's avatar
Tambet Ingo committed
150

151 152
static void hostname_provider_init (NMHostnameProvider *provider_class);

153 154 155 156 157 158
static NMActiveConnection *internal_activate_device (NMManager *manager,
                                                     NMDevice *device,
                                                     NMConnection *connection,
                                                     const char *specific_object,
                                                     gboolean user_requested,
                                                     gulong sender_uid,
159
                                                     const char *dbus_sender,
160 161 162
                                                     gboolean assumed,
                                                     NMActiveConnection *master,
                                                     GError **error);
163

164
static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
165

166 167 168
static GSList * remove_one_device (NMManager *manager,
                                   GSList *list,
                                   NMDevice *device,
169
                                   gboolean quitting);
170

171 172
static void rfkill_change_wifi (const char *desc, gboolean enabled);

173
#define SSD_POKE_INTERVAL 120
174
#define ORIGDEV_TAG "originating-device"
175

176 177 178 179 180
typedef struct PendingActivation PendingActivation;
typedef void (*PendingActivationFunc) (PendingActivation *pending,
                                       GError *error);

struct PendingActivation {
181 182
	NMManager *manager;

183 184 185
	DBusGMethodInvocation *context;
	PendingActivationFunc callback;
	NMAuthChain *chain;
186
	const char *wifi_shared_permission;
187

188
	char *connection_path;
189
	NMConnection *connection;
190
	char *specific_object_path;
191
	char *device_path;
192
};
193

194
typedef struct {
195
	gboolean user_enabled;
196
	gboolean daemon_enabled;
197
	gboolean sw_enabled;
198
	gboolean hw_enabled;
199
	RfKillType rtype;
200 201 202 203 204
	const char *desc;
	const char *key;
	const char *prop;
	const char *hw_prop;
	RfKillState (*other_enabled_func) (NMManager *);
205
	RfKillState (*daemon_enabled_func) (NMManager *);
206 207
} RadioState;

208
typedef struct {
209
	char *state_file;
210

211 212 213
	GSList *active_connections;
	guint ac_cleanup_id;

214
	GSList *devices;
215
	NMState state;
216
#if WITH_CONCHECK
217
	NMConnectivity *connectivity;
218
#endif
219

220
	NMDBusManager *dbus_mgr;
221
	guint          dbus_connection_changed_id;
Dan Williams's avatar
Dan Williams committed
222
	NMUdevManager *udev_mgr;
223
	NMBluezManager *bluez_mgr;
224

225 226 227
	/* List of NMDeviceFactoryFunc pointers sorted in priority order */
	GSList *factories;

228
	NMSettings *settings;
229
	char *hostname;
230

231
	RadioState radio_states[RFKILL_TYPE_MAX];
232
	gboolean sleeping;
233
	gboolean net_enabled;
234

235 236
	NMVPNManager *vpn_manager;

Tambet Ingo's avatar
Tambet Ingo committed
237 238 239 240
	NMModemManager *modem_manager;
	guint modem_added_id;
	guint modem_removed_id;

241
	DBusGProxy *aipd_proxy;
242
	NMSleepMonitor *sleep_monitor;
243

244 245
	GSList *auth_chains;

246 247 248 249 250
	/* Firmware dir monitor */
	GFileMonitor *fw_monitor;
	guint fw_monitor_id;
	guint fw_changed_id;

251 252
	guint timestamp_update_id;

253 254
	GHashTable *nm_bridges;

255
	gboolean disposed;
256 257 258 259
} NMManagerPrivate;

#define NM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MANAGER, NMManagerPrivate))

260 261 262
G_DEFINE_TYPE_EXTENDED (NMManager, nm_manager, G_TYPE_OBJECT, 0,
						G_IMPLEMENT_INTERFACE (NM_TYPE_HOSTNAME_PROVIDER,
											   hostname_provider_init))
263 264 265 266

enum {
	DEVICE_ADDED,
	DEVICE_REMOVED,
267
	STATE_CHANGED,
268
	CHECK_PERMISSIONS,
269
	USER_PERMISSIONS_CHANGED,
270 271
	ACTIVE_CONNECTION_ADDED,
	ACTIVE_CONNECTION_REMOVED,
272 273 274 275 276 277 278 279

	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

enum {
	PROP_0,
280
	PROP_VERSION,
281
	PROP_STATE,
282
	PROP_NETWORKING_ENABLED,
283
	PROP_WIRELESS_ENABLED,
284
	PROP_WIRELESS_HARDWARE_ENABLED,
285 286
	PROP_WWAN_ENABLED,
	PROP_WWAN_HARDWARE_ENABLED,
Tambet Ingo's avatar
Tambet Ingo committed
287 288
	PROP_WIMAX_ENABLED,
	PROP_WIMAX_HARDWARE_ENABLED,
289
	PROP_ACTIVE_CONNECTIONS,
290

291 292
	/* Not exported */
	PROP_HOSTNAME,
293
	PROP_SLEEPING,
294

295 296 297
	LAST_PROP
};

298 299 300

/************************************************************************/

301 302 303 304 305 306 307 308 309 310 311
#define NM_MANAGER_ERROR (nm_manager_error_quark ())

static GQuark
nm_manager_error_quark (void)
{
	static GQuark quark = 0;
	if (!quark)
		quark = g_quark_from_static_string ("nm-manager-error");
	return quark;
}

312 313
/************************************************************************/

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
static void active_connection_state_changed (NMActiveConnection *active,
                                             GParamSpec *pspec,
                                             NMManager *self);

static gboolean
_active_connection_cleanup (gpointer user_data)
{
	NMManager *self = NM_MANAGER (user_data);
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
	GSList *iter;
	gboolean changed = FALSE;

	priv->ac_cleanup_id = 0;

	iter = priv->active_connections;
	while (iter) {
		NMActiveConnection *ac = iter->data;

		iter = iter->next;
		if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
			priv->active_connections = g_slist_remove (priv->active_connections, ac);
335
			g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, ac);
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
			g_signal_handlers_disconnect_by_func (ac, active_connection_state_changed, self);
			g_object_unref (ac);
			changed = TRUE;
		}
	}

	if (changed)
		g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);

	return FALSE;
}

static void
active_connection_state_changed (NMActiveConnection *active,
                                 GParamSpec *pspec,
                                 NMManager *self)
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
	NMActiveConnectionState state;

	state = nm_active_connection_get_state (active);
	if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
		/* Destroy active connections from an idle handler to ensure that
		 * their last property change notifications go out, which wouldn't
		 * happen if we destroyed them immediately when their state was set
		 * to DEACTIVATED.
		 */
		if (!priv->ac_cleanup_id)
			priv->ac_cleanup_id = g_idle_add (_active_connection_cleanup, self);
	}
}

static void
active_connection_add (NMManager *self, NMActiveConnection *active)
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);

	g_return_if_fail (g_slist_find (priv->active_connections, active) == FALSE);

	priv->active_connections = g_slist_prepend (priv->active_connections, active);
	g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
	                  G_CALLBACK (active_connection_state_changed),
	                  self);
379 380

	g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active);
381 382 383
	g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}

384 385 386 387 388 389
const GSList *
nm_manager_get_active_connections (NMManager *manager)
{
	return NM_MANAGER_GET_PRIVATE (manager)->active_connections;
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
static NMActiveConnection *
active_connection_get_by_path (NMManager *manager, const char *path)
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
	GSList *iter;

	g_return_val_if_fail (manager != NULL, NULL);
	g_return_val_if_fail (path != NULL, NULL);

	for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
		NMActiveConnection *candidate = iter->data;

		if (strcmp (path, nm_active_connection_get_path (candidate)) == 0)
			return candidate;
	}
	return NULL;
}

408 409
/************************************************************************/

410 411 412 413 414
static NMDevice *
nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
{
	GSList *iter;

415 416
	g_return_val_if_fail (udi != NULL, NULL);

417 418 419 420 421 422 423 424 425 426 427 428
	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
		if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
			return NM_DEVICE (iter->data);
	}
	return NULL;
}

static NMDevice *
nm_manager_get_device_by_path (NMManager *manager, const char *path)
{
	GSList *iter;

429 430
	g_return_val_if_fail (path != NULL, NULL);

431 432 433 434 435 436 437
	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
		if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
			return NM_DEVICE (iter->data);
	}
	return NULL;
}

438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
NMDevice *
nm_manager_get_device_by_master (NMManager *manager, const char *master, const char *driver)
{
	GSList *iter;

	g_return_val_if_fail (master != NULL, NULL);

	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
		NMDevice *device = NM_DEVICE (iter->data);

		if (!strcmp (nm_device_get_iface (device), master) &&
		    (!driver || !strcmp (nm_device_get_driver (device), driver)))
			return device;
	}

	return NULL;
}

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
NMDevice *
nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
{
	GSList *iter;

	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
		NMDevice *device = NM_DEVICE (iter->data);

		if (nm_device_get_ifindex (device) == ifindex)
			return device;
	}

	return NULL;
}

471 472 473 474 475 476 477 478 479 480
static gboolean
manager_sleeping (NMManager *self)
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);

	if (priv->sleeping || !priv->net_enabled)
		return TRUE;
	return FALSE;
}

Tambet Ingo's avatar
Tambet Ingo committed
481 482
static void
modem_added (NMModemManager *modem_manager,
483 484
			 NMModem *modem,
			 const char *driver,
Tambet Ingo's avatar
Tambet Ingo committed
485 486
			 gpointer user_data)
{
487 488 489
	NMManager *self = NM_MANAGER (user_data);
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
	NMDevice *replace_device, *device = NULL;
490
	const char *modem_iface;
491
	GSList *iter;
492

493 494 495 496 497
	/* Don't rely only on the data port; use the control port if available */
	modem_iface = nm_modem_get_data_port (modem);
	if (!modem_iface)
		modem_iface = nm_modem_get_control_port (modem);
	g_return_if_fail (modem_iface);
498

499
	replace_device = find_device_by_ip_iface (NM_MANAGER (user_data), modem_iface);
500
	if (replace_device) {
501 502 503
		priv->devices = remove_one_device (NM_MANAGER (user_data),
		                                   priv->devices,
		                                   replace_device,
504
		                                   FALSE);
505 506
	}

507 508
	/* Give Bluetooth DUN devices first chance to claim the modem */
	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
509
		if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
510 511 512 513 514 515 516 517 518 519
			if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver))
				return;
		}
	}

	/* If it was a Bluetooth modem and no bluetooth device claimed it, ignore
	 * it.  The rfcomm port (and thus the modem) gets created automatically
	 * by the Bluetooth code during the connection process.
	 */
	if (driver && !strcmp (driver, "bluetooth")) {
520
		nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", modem_iface);
521 522 523
		return;
	}

524 525
	/* Make the new modem device */
	device = nm_device_modem_new (modem, driver);
526 527
	if (device)
		add_device (self, device);
Tambet Ingo's avatar
Tambet Ingo committed
528 529
}

530 531 532 533 534
static void
nm_manager_update_state (NMManager *manager)
{
	NMManagerPrivate *priv;
	NMState new_state = NM_STATE_DISCONNECTED;
535
	GSList *iter;
536 537 538 539 540

	g_return_if_fail (NM_IS_MANAGER (manager));

	priv = NM_MANAGER_GET_PRIVATE (manager);

541
	if (manager_sleeping (manager))
542
		new_state = NM_STATE_ASLEEP;
543
	else {
544 545 546
		for (iter = priv->devices; iter; iter = iter->next) {
			NMDevice *dev = NM_DEVICE (iter->data);
			NMDeviceState state = nm_device_get_state (dev);
547

548 549 550 551 552
			if (state == NM_DEVICE_STATE_ACTIVATED) {
				new_state = NM_STATE_CONNECTED_GLOBAL;
#if WITH_CONCHECK
				/* Connectivity check might have a better idea */
				if (nm_connectivity_get_connected (priv->connectivity) == FALSE)
553
					new_state = NM_STATE_CONNECTED_SITE;
554 555 556
#endif
				break;
			}
557

558 559 560 561 562
			if (nm_device_is_activating (dev))
				new_state = NM_STATE_CONNECTING;
			else if (new_state != NM_STATE_CONNECTING) {
				if (state == NM_DEVICE_STATE_DEACTIVATING)
					new_state = NM_STATE_DISCONNECTING;
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
			}
		}
	}

	if (priv->state != new_state) {
		priv->state = new_state;
		g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);

		g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
	}
}

static void
manager_device_state_changed (NMDevice *device,
                              NMDeviceState new_state,
                              NMDeviceState old_state,
                              NMDeviceStateReason reason,
                              gpointer user_data)
{
582
	NMManager *self = NM_MANAGER (user_data);
583
#if WITH_CONCHECK
584
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
585
#endif
586 587 588 589 590 591 592

	switch (new_state) {
	case NM_DEVICE_STATE_UNMANAGED:
	case NM_DEVICE_STATE_UNAVAILABLE:
	case NM_DEVICE_STATE_DISCONNECTED:
	case NM_DEVICE_STATE_PREPARE:
	case NM_DEVICE_STATE_FAILED:
593
		g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
594 595 596 597 598
		break;
	default:
		break;
	}

599
	nm_manager_update_state (self);
600

601
#if WITH_CONCHECK
602 603 604 605 606
	if (priv->state >= NM_STATE_CONNECTED_LOCAL) {
		if (old_state == NM_DEVICE_STATE_ACTIVATED || new_state == NM_DEVICE_STATE_ACTIVATED) {
			/* Still connected, but a device activated or deactivated; make sure
			 * we still have connectivity on the other activated devices.
			 */
607 608
			nm_log_dbg (LOGD_CORE, "(%s): triggered connectivity check due to state change",
			            nm_device_get_iface (device));
609 610 611 612
			nm_connectivity_start_check (priv->connectivity);
		}
	} else {
		/* Cannot be connected if no devices are activated */
613
		nm_log_dbg (LOGD_CORE, "stopping connectivity checks");
614 615
		nm_connectivity_stop_check (priv->connectivity);
	}
616
#endif
617 618 619 620
}

/* Removes a device from a device list; returns the start of the new device list */
static GSList *
621 622 623
remove_one_device (NMManager *manager,
                   GSList *list,
                   NMDevice *device,
624
                   gboolean quitting)
625
{
626 627
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);

628
	if (nm_device_get_managed (device)) {
629 630 631 632 633 634 635
		/* When quitting, we want to leave up interfaces & connections
		 * that can be taken over again (ie, "assumed") when NM restarts
		 * so that '/etc/init.d/NetworkManager restart' will not distrupt
		 * networking for interfaces that support connection assumption.
		 * All other devices get unmanaged when NM quits so that their
		 * connections get torn down and the interface is deactivated.
		 */
636

637
		if (   !nm_device_can_assume_connections (device)
638 639
		    || (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
		    || !quitting)
640
			nm_device_set_manager_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
641
	}
642 643 644

	g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);

645
	nm_settings_device_removed (priv->settings, device);
646 647 648 649 650 651
	g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
	g_object_unref (device);

	return g_slist_remove (list, device);
}

Tambet Ingo's avatar
Tambet Ingo committed
652 653
static void
modem_removed (NMModemManager *modem_manager,
654
			   NMModem *modem,
Tambet Ingo's avatar
Tambet Ingo committed
655 656
			   gpointer user_data)
{
657 658
	NMManager *self = NM_MANAGER (user_data);
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
659
	NMDevice *found;
660 661 662 663
	GSList *iter;

	/* Give Bluetooth DUN devices first chance to handle the modem removal */
	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
664
		if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) {
665 666 667 668
			if (nm_device_bt_modem_removed (NM_DEVICE_BT (iter->data), modem))
				return;
		}
	}
Tambet Ingo's avatar
Tambet Ingo committed
669

670
	/* Otherwise remove the standalone modem */
671 672
	found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
	if (found)
673
		priv->devices = remove_one_device (self, priv->devices, found, FALSE);
Tambet Ingo's avatar
Tambet Ingo committed
674 675
}

676 677 678 679 680 681 682 683 684 685
static void
aipd_handle_event (DBusGProxy *proxy,
                   const char *event,
                   const char *iface,
                   const char *address,
                   gpointer user_data)
{
	NMManager *manager = NM_MANAGER (user_data);
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
	GSList *iter;
686
	gboolean handled = FALSE;
687 688

	if (!event || !iface) {
689
		nm_log_warn (LOGD_AUTOIP4, "incomplete message received from avahi-autoipd");
690 691 692 693 694 695 696
		return;
	}

	if (   (strcmp (event, "BIND") != 0)
	    && (strcmp (event, "CONFLICT") != 0)
	    && (strcmp (event, "UNBIND") != 0)
	    && (strcmp (event, "STOP") != 0)) {
697
		nm_log_warn (LOGD_AUTOIP4, "unknown event '%s' received from avahi-autoipd", event);
698 699 700 701 702 703 704 705 706 707 708 709 710 711
		return;
	}

	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
		NMDevice *candidate = NM_DEVICE (iter->data);

		if (!strcmp (nm_device_get_iface (candidate), iface)) {
			nm_device_handle_autoip4_event (candidate, event, address);
			handled = TRUE;
			break;
		}
	}

	if (!handled)
712
		nm_log_warn (LOGD_AUTOIP4, "(%s): unhandled avahi-autoipd event", iface);
713 714
}

715 716 717 718 719 720 721 722 723 724 725 726
static const char *
hostname_provider_get_hostname (NMHostnameProvider *provider)
{
	return NM_MANAGER_GET_PRIVATE (provider)->hostname;
}

static void
hostname_provider_init (NMHostnameProvider *provider_class)
{
	provider_class->get_hostname = hostname_provider_get_hostname;
}

727 728 729 730 731 732 733 734
NMState
nm_manager_get_state (NMManager *manager)
{
	g_return_val_if_fail (NM_IS_MANAGER (manager), NM_STATE_UNKNOWN);

	return NM_MANAGER_GET_PRIVATE (manager)->state;
}

735 736 737 738 739 740
static gboolean
might_be_vpn (NMConnection *connection)
{
	NMSettingConnection *s_con;
	const char *ctype = NULL;

741
	if (nm_connection_get_setting_vpn (connection))
742 743 744
		return TRUE;

	/* Make sure it's not a VPN, which we can't autocomplete yet */
745
	s_con = nm_connection_get_setting_connection (connection);
746 747 748 749 750 751 752 753 754 755 756
	if (s_con)
		ctype = nm_setting_connection_get_connection_type (s_con);

	return (g_strcmp0 (ctype, NM_SETTING_VPN_SETTING_NAME) == 0);
}

static gboolean
try_complete_vpn (NMConnection *connection, GSList *existing, GError **error)
{
	g_assert (might_be_vpn (connection) == TRUE);

757
	if (!nm_connection_get_setting_vpn (connection)) {
758 759 760 761 762 763 764 765 766 767 768
		g_set_error_literal (error,
			                 NM_MANAGER_ERROR,
			                 NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
			                 "VPN connections require a 'vpn' setting");
		return FALSE;
	}

	nm_utils_complete_generic (connection,
	                           NM_SETTING_VPN_SETTING_NAME,
	                           existing,
	                           _("VPN connection %d"),
769 770 771
	                           NULL,
	                           FALSE); /* No IPv6 by default for now */

772 773 774
	return TRUE;
}

775 776
static PendingActivation *
pending_activation_new (NMManager *manager,
777
                        DBusGMethodInvocation *context,
778 779
                        const char *device_path,
                        const char *connection_path,
780
                        GHashTable *settings,
781
                        const char *specific_object_path,
782 783
                        PendingActivationFunc callback,
                        GError **error)
784
{
785
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
786
	PendingActivation *pending;
787
	NMDevice *device = NULL;
788 789 790
	NMConnection *connection = NULL;
	GSList *all_connections = NULL;
	gboolean success;
791

792 793 794 795
	g_return_val_if_fail (manager != NULL, NULL);
	g_return_val_if_fail (context != NULL, NULL);
	g_return_val_if_fail (device_path != NULL, NULL);

796
	/* A object path of "/" means NULL */
797 798
	if (g_strcmp0 (specific_object_path, "/") == 0)
		specific_object_path = NULL;
799 800
	if (g_strcmp0 (device_path, "/") == 0)
		device_path = NULL;
801

802 803
	/* Create the partial connection from the given settings */
	if (settings) {
804 805
		if (device_path)
			device = nm_manager_get_device_by_path (manager, device_path);
806 807 808 809 810 811 812 813 814 815 816 817
		if (!device) {
			g_set_error_literal (error,
				                 NM_MANAGER_ERROR,
				                 NM_MANAGER_ERROR_UNKNOWN_DEVICE,
				                 "Device not found");
			return NULL;
		}

		connection = nm_connection_new ();
		nm_connection_replace_settings (connection, settings, NULL);

		all_connections = nm_settings_get_connections (priv->settings);
818 819 820 821 822 823 824 825 826 827 828 829

		if (might_be_vpn (connection)) {
			/* Try to fill the VPN's connection setting and name at least */
			success = try_complete_vpn (connection, all_connections, error);
		} else {
			/* Let each device subclass complete the connection */
			success = nm_device_complete_connection (device,
			                                         connection,
			                                         specific_object_path,
			                                         all_connections,
			                                         error);
		}
830 831 832 833 834 835 836 837
		g_slist_free (all_connections);

		if (success == FALSE) {
			g_object_unref (connection);
			return NULL;
		}
	}

838 839
	pending = g_slice_new0 (PendingActivation);
	pending->manager = manager;
840 841 842
	pending->context = context;
	pending->callback = callback;

843
	pending->connection_path = g_strdup (connection_path);
844
	pending->connection = connection;
845

846 847 848
	/* "/" is special-cased to NULL to get through D-Bus */
	if (specific_object_path && strcmp (specific_object_path, "/"))
		pending->specific_object_path = g_strdup (specific_object_path);
849 850
	if (device_path && strcmp (device_path, "/"))
		pending->device_path = g_strdup (device_path);
851 852 853 854

	return pending;
}

855
static void
856 857 858 859
pending_auth_done (NMAuthChain *chain,
                   GError *error,
                   DBusGMethodInvocation *context,
                   gpointer user_data)
860 861 862
{
	PendingActivation *pending = user_data;
	NMAuthCallResult result;
863
	GError *tmp_error = NULL;
864 865 866 867

	/* Caller has had a chance to obtain authorization, so we only need to
	 * check for 'yes' here.
	 */
868 869 870 871
	result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
	if (error)
		tmp_error = g_error_copy (error);
	else if (result != NM_AUTH_CALL_RESULT_YES) {
872 873 874
		tmp_error = g_error_new_literal (NM_MANAGER_ERROR,
		                                 NM_MANAGER_ERROR_PERMISSION_DENIED,
		                                 "Not authorized to control networking.");
875
	} else if (pending->wifi_shared_permission) {
876 877 878 879 880 881
		result = nm_auth_chain_get_result (chain, pending->wifi_shared_permission);
		if (result != NM_AUTH_CALL_RESULT_YES) {
			tmp_error = g_error_new_literal (NM_MANAGER_ERROR,
			                                 NM_MANAGER_ERROR_PERMISSION_DENIED,
			                                 "Not authorized to share connections via wifi.");
		}
882 883
	}

884 885
	pending->callback (pending, tmp_error);
	g_clear_error (&tmp_error);
886 887 888
}

static void
889
pending_activation_check_authorized (PendingActivation *pending)
890
{
891
	GError *error;
892 893 894
	const char *wifi_permission = NULL;
	NMConnection *connection;
	NMSettings *settings;
895
	const char *error_desc = NULL;
896 897 898

	g_return_if_fail (pending != NULL);

899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
	/* By this point we have an auto-completed connection (for AddAndActivate)
	 * or an existing connection (for Activate).
	 */
	connection = pending->connection;
	if (!connection) {
		settings = NM_MANAGER_GET_PRIVATE (pending->manager)->settings;
		connection = (NMConnection *) nm_settings_get_connection_by_path (settings, pending->connection_path);
	}

	if (!connection) {
		error = g_error_new_literal (NM_MANAGER_ERROR,
		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
		                             "Connection could not be found.");
		pending->callback (pending, error);
		g_error_free (error);
		return;
	}

917 918 919
	/* First check if the user is allowed to use networking at all, giving
	 * the user a chance to authenticate to gain the permission.
	 */
920
	pending->chain = nm_auth_chain_new (pending->context,
921
	                                    pending_auth_done,
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
	                                    pending,
	                                    &error_desc);
	if (pending->chain) {
		nm_auth_chain_add_call (pending->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);

		/* Shared wifi connections require special permissions too */
		wifi_permission = nm_utils_get_shared_wifi_permission (connection);
		if (wifi_permission) {
			pending->wifi_shared_permission = wifi_permission;
			nm_auth_chain_add_call (pending->chain, wifi_permission, TRUE);
		}
	} else {
		error = g_error_new_literal (NM_MANAGER_ERROR,
		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
		                             error_desc);
		pending->callback (pending, error);
		g_error_free (error);
939
	}
940 941 942 943 944
}

static void
pending_activation_destroy (PendingActivation *pending,
                            GError *error,
945
                            NMActiveConnection *ac)
946 947 948
{
	g_return_if_fail (pending != NULL);

949 950
	if (error)
		dbus_g_method_return_error (pending->context, error);
951
	else if (ac) {
952 953 954
		if (pending->connection) {
			dbus_g_method_return (pending->context,
			                      pending->connection_path,
955 956 957 958 959
			                      nm_active_connection_get_path (ac));
		} else {
			dbus_g_method_return (pending->context,
			                      nm_active_connection_get_path (ac));
		}
960 961
	}

962 963 964
	g_free (pending->connection_path);
	g_free (pending->specific_object_path);
	g_free (pending->device_path);
965 966
	if (pending->connection)
		g_object_unref (pending->connection);
967

968 969
	if (pending->chain)
		nm_auth_chain_unref (pending->chain);
970 971 972

	memset (pending, 0, sizeof (PendingActivation));
	g_slice_free (PendingActivation, pending);
973 974
}

975
/*******************************************************************/
976
/* Settings stuff via NMSettings                                   */
977 978
/*******************************************************************/

979 980
static NMDevice *
get_device_from_hwaddr (NMManager *self, NMConnection *connection)
981 982 983 984 985
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
	GSList *iter;

	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
986 987
		if (nm_device_hwaddr_matches (NM_DEVICE (iter->data), connection, NULL, 0, TRUE))
			return iter->data;
988 989 990 991
	}
	return NULL;
}

992 993 994 995
static NMDevice*
find_vlan_parent (NMManager *self,
                  NMConnection *connection,
                  gboolean check_hwaddr)
996 997
{
	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
998 999
	NMSettingVlan *s_vlan;
	NMConnection *parent_connection;
1000 1001
	const char *parent_iface;
	NMDevice *parent = NULL;
1002 1003
	GSList *iter;

1004
	/* The 'parent' property could be either an interface name, a connection
1005 1006
	 * UUID, or even given by the MAC address of the connection's ethernet
	 * or WiFi setting.
1007
	 */
1008 1009 1010
	s_vlan = nm_connection_get_setting_vlan (connection);
	g_return_val_if_fail (s_vlan != NULL, NULL);

1011 1012 1013 1014
	parent_iface = nm_setting_vlan_get_parent (s_vlan);
	if (parent_iface) {
		parent = find_device_by_ip_iface (self, parent_iface);
		if (parent)
1015
			return parent;
1016

1017
		if (nm_utils_is_uuid (parent_iface)) {
1018
			/* Try as a connection UUID */
1019
			parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface);
1020 1021 1022
			if (parent_connection) {
				/* Check if the parent connection is activated on some device already */
				for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
1023 1024 1025 1026 1027 1028 1029
					NMActRequest *req;
					NMConnection *candidate;

					req = nm_device_get_act_request (NM_DEVICE (iter->data));
					if (req) {
						candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
						if (candidate == parent_connection)
1030
							return NM_DEVICE (iter->data);
1031
					}
1032 1033
				}

1034 1035
				/* Check the hardware address of the parent connection */
				if (check_hwaddr)
1036
					return get_device_from_hwaddr (self, parent_connection);
1037 1038
			}
			return NULL;
1039 1040 1041 1042 1043
		}
	}

	/* Try the hardware address from the VLAN connection's hardware setting */
	if (check_hwaddr)
1044
		return get_device_from_hwaddr (self, connection);
1045 1046 1047 1048

	return NULL;
}

1049 1050 1051 1052
/**
 * get_virtual_iface_name:
 * @self: the #NMManager
 * @connection: the #NMConnection representing a virtual interface
1053
 * @out_parent: on success, the parent device if any
1054 1055 1056 1057 1058 1059 1060 1061 1062
 *
 * Given @connection, returns the interface name that the connection
 * would represent.  If the interface name is not given by the connection,
 * this may require constructing it based on information in the connection
 * and existing network interfaces.
 *
 * Returns: the expected interface name (caller takes ownership), or %NULL